001: // Copyright 2006, 2007 The Apache Software Foundation
002: //
003: // Licensed under the Apache License, Version 2.0 (the "License");
004: // you may not use this file except in compliance with the License.
005: // You may obtain a copy of the License at
006: //
007: // http://www.apache.org/licenses/LICENSE-2.0
008: //
009: // Unless required by applicable law or agreed to in writing, software
010: // distributed under the License is distributed on an "AS IS" BASIS,
011: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: // See the License for the specific language governing permissions and
013: // limitations under the License.
014:
015: package org.apache.tapestry.internal.services;
016:
017: import static org.easymock.EasyMock.eq;
018: import static org.easymock.EasyMock.isA;
019: import static org.easymock.EasyMock.isNull;
020:
021: import org.apache.tapestry.ComponentEventHandler;
022: import org.apache.tapestry.Link;
023: import org.apache.tapestry.TapestryConstants;
024: import org.apache.tapestry.internal.InternalConstants;
025: import org.apache.tapestry.internal.structure.ComponentPageElement;
026: import org.apache.tapestry.internal.structure.Page;
027: import org.apache.tapestry.internal.test.InternalBaseTestCase;
028: import org.apache.tapestry.internal.util.Holder;
029: import org.apache.tapestry.ioc.services.TypeCoercer;
030: import org.apache.tapestry.services.ComponentClassResolver;
031: import org.apache.tapestry.services.Request;
032: import org.apache.tapestry.services.Response;
033: import org.easymock.EasyMock;
034: import org.easymock.IAnswer;
035: import org.testng.annotations.AfterClass;
036: import org.testng.annotations.BeforeClass;
037: import org.testng.annotations.Test;
038:
039: public class LinkFactoryImplTest extends InternalBaseTestCase {
040: private static final String ENCODED = "*encoded*";
041:
042: private static final String PAGE_LOGICAL_NAME = "sub/MyPage";
043:
044: private TypeCoercer _typeCoercer;
045:
046: @BeforeClass
047: public void setup() {
048: _typeCoercer = getObject(TypeCoercer.class, null);
049: }
050:
051: @AfterClass
052: public void cleanup() {
053: _typeCoercer = null;
054: }
055:
056: @Test
057: public void action_link_root_context_no_ids() {
058: testActionLink("", PAGE_LOGICAL_NAME, "foo.bar", "someaction",
059: "/sub/mypage.foo.bar:someaction");
060:
061: }
062:
063: @Test
064: public void action_link_root_context_with_ids() {
065: testActionLink("", PAGE_LOGICAL_NAME, "foo.bar", "publish",
066: "/sub/mypage.foo.bar:publish/fred/5", "fred", 5);
067: }
068:
069: @Test
070: public void action_link_with_default_action() {
071: testActionLink("", PAGE_LOGICAL_NAME, "foo.bar",
072: TapestryConstants.ACTION_EVENT,
073: "/sub/mypage.foo.bar/fred/5", "fred", 5);
074: }
075:
076: @Test
077: public void page_level_event_always_includes_action() {
078: testActionLink("", PAGE_LOGICAL_NAME, "",
079: TapestryConstants.ACTION_EVENT,
080: "/sub/mypage:action/barney/99", "barney", 99);
081: }
082:
083: @Test
084: public void action_link_named_context_no_ids() {
085: testActionLink("/fred", PAGE_LOGICAL_NAME, "foo.bar",
086: "someaction", "/fred/sub/mypage.foo.bar:someaction");
087: }
088:
089: @SuppressWarnings("unchecked")
090: @Test
091: public void page_link() {
092: Request request = mockRequest();
093: Response response = mockResponse();
094: ComponentClassResolver resolver = mockComponentClassResolver();
095: Page page = mockPage();
096: ComponentPageElement rootElement = mockComponentPageElement();
097: LinkFactoryListener listener = mockLinkFactoryListener();
098: ComponentInvocationMap map = mockComponentInvocationMap();
099:
100: train_getLogicalName(page, PAGE_LOGICAL_NAME);
101: train_getContextPath(request, "/barney");
102:
103: train_getRootElement(page, rootElement);
104:
105: final Holder<Link> holder = new Holder<Link>();
106:
107: train_triggerPassivateEventForPageLink(rootElement, listener,
108: holder);
109:
110: train_encodeRedirectURL(response, "/barney/"
111: + PAGE_LOGICAL_NAME.toLowerCase() + "/foo/bar", ENCODED);
112:
113: // This needs to be refactored a bit to be more testable.
114:
115: map.store(isA(Link.class), isA(ComponentInvocation.class));
116:
117: replay();
118:
119: LinkFactory factory = new LinkFactoryImpl(request, response,
120: resolver, map, null, _typeCoercer);
121: factory.addListener(listener);
122:
123: Link link = factory.createPageLink(page, false);
124:
125: assertEquals(link.toRedirectURI(), ENCODED);
126:
127: // Make sure the link was passed to the LinkFactoryListener
128:
129: assertSame(link, holder.get());
130:
131: verify();
132: }
133:
134: @SuppressWarnings("unchecked")
135: @Test
136: public void page_link_using_supplied_activation_context() {
137: Request request = mockRequest();
138: Response response = mockResponse();
139: ComponentClassResolver resolver = mockComponentClassResolver();
140: Page page = mockPage();
141: LinkFactoryListener listener = mockLinkFactoryListener();
142: ComponentInvocationMap map = mockComponentInvocationMap();
143:
144: train_getLogicalName(page, PAGE_LOGICAL_NAME);
145: train_getContextPath(request, "/barney");
146:
147: Holder<Link> holder = new Holder<Link>();
148:
149: IAnswer<Void> createdPageLinkAnswer = newAnswerForCreatedLink(holder);
150:
151: listener.createdPageLink(isA(Link.class));
152: getMocksControl().andAnswer(createdPageLinkAnswer);
153:
154: train_encodeRedirectURL(response, "/barney/"
155: + PAGE_LOGICAL_NAME.toLowerCase() + "/biff/bazz",
156: ENCODED);
157:
158: // This needs to be refactored a bit to be more testable.
159:
160: map.store(isA(Link.class), isA(ComponentInvocation.class));
161:
162: replay();
163:
164: LinkFactory factory = new LinkFactoryImpl(request, response,
165: resolver, map, null, _typeCoercer);
166: factory.addListener(listener);
167:
168: Link link = factory.createPageLink(page, false, "biff", "bazz");
169:
170: assertEquals(link.toRedirectURI(), ENCODED);
171:
172: // Make sure the link was passed to the LinkFactoryListener
173:
174: assertSame(link, holder.get());
175:
176: verify();
177: }
178:
179: @SuppressWarnings("unchecked")
180: @Test
181: public void page_link_using_empty_activation_context_and_override() {
182: Request request = mockRequest();
183: Response response = mockResponse();
184: ComponentClassResolver resolver = mockComponentClassResolver();
185: Page page = mockPage();
186: LinkFactoryListener listener = mockLinkFactoryListener();
187: ComponentInvocationMap map = mockComponentInvocationMap();
188:
189: train_getLogicalName(page, PAGE_LOGICAL_NAME);
190: train_getContextPath(request, "/barney");
191:
192: Holder<Link> holder = new Holder<Link>();
193:
194: IAnswer<Void> createdPageLinkAnswer = newAnswerForCreatedLink(holder);
195:
196: listener.createdPageLink(isA(Link.class));
197: getMocksControl().andAnswer(createdPageLinkAnswer);
198:
199: train_encodeRedirectURL(response, "/barney/"
200: + PAGE_LOGICAL_NAME.toLowerCase(), ENCODED);
201:
202: // This needs to be refactored a bit to be more testable.
203:
204: map.store(isA(Link.class), isA(ComponentInvocation.class));
205:
206: replay();
207:
208: LinkFactory factory = new LinkFactoryImpl(request, response,
209: resolver, map, null, _typeCoercer);
210: factory.addListener(listener);
211:
212: Link link = factory.createPageLink(page, true);
213:
214: assertEquals(link.toRedirectURI(), ENCODED);
215:
216: // Make sure the link was passed to the LinkFactoryListener
217:
218: assertSame(link, holder.get());
219:
220: verify();
221: }
222:
223: @Test
224: public void page_link_by_name() {
225: Request request = mockRequest();
226: Response response = mockResponse();
227: ComponentClassResolver resolver = mockComponentClassResolver();
228: Page page = mockPage();
229: ComponentPageElement rootElement = mockComponentPageElement();
230: LinkFactoryListener listener = mockLinkFactoryListener();
231: ComponentInvocationMap map = mockComponentInvocationMap();
232: RequestPageCache cache = mockRequestPageCache();
233:
234: train_get(cache, PAGE_LOGICAL_NAME, page);
235:
236: train_getLogicalName(page, PAGE_LOGICAL_NAME);
237: train_getContextPath(request, "/barney");
238:
239: train_getRootElement(page, rootElement);
240:
241: // Answer for triggerEvent() which returns a boolean.
242: final Holder<Link> holder = new Holder<Link>();
243:
244: train_triggerPassivateEventForPageLink(rootElement, listener,
245: holder);
246:
247: train_encodeRedirectURL(response, "/barney/"
248: + PAGE_LOGICAL_NAME.toLowerCase() + "/foo/bar", ENCODED);
249:
250: // This needs to be refactored a bit to be more testable.
251:
252: map.store(isA(Link.class), isA(ComponentInvocation.class));
253:
254: replay();
255:
256: LinkFactory factory = new LinkFactoryImpl(request, response,
257: resolver, map, cache, _typeCoercer);
258: factory.addListener(listener);
259:
260: Link link = factory.createPageLink(PAGE_LOGICAL_NAME, false);
261:
262: assertEquals(link.toRedirectURI(), ENCODED);
263:
264: // Make sure the link was passed to the LinkFactoryListener
265:
266: assertSame(link, holder.get());
267:
268: verify();
269: }
270:
271: @SuppressWarnings("unchecked")
272: private void train_triggerPassivateEventForPageLink(
273: ComponentPageElement rootElement,
274: LinkFactoryListener listener, Holder<Link> holder) {
275: IAnswer<Boolean> triggerEventAnswer = newAnswerForPassivateEventTrigger();
276:
277: IAnswer<Void> createdPageLinkAnswer = newAnswerForCreatedLink(holder);
278:
279: // Intercept the call to handle component event, and let the IAnswer
280: // do the work.
281:
282: expect(
283: rootElement.triggerEvent(
284: eq(TapestryConstants.PASSIVATE_EVENT),
285: (Object[]) isNull(),
286: isA(ComponentEventHandler.class))).andAnswer(
287: triggerEventAnswer);
288:
289: listener.createdPageLink(isA(Link.class));
290: getMocksControl().andAnswer(createdPageLinkAnswer);
291: }
292:
293: @SuppressWarnings("unchecked")
294: private void train_triggerPassivateEventForActionLink(
295: ComponentPageElement rootElement,
296: LinkFactoryListener listener, Holder<Link> holder) {
297: IAnswer<Boolean> triggerEventAnswer = newAnswerForPassivateEventTrigger();
298:
299: IAnswer<Void> createdPageLinkAnswer = newAnswerForCreatedLink(holder);
300:
301: // Intercept the call to handle component event, and let the IAnswer
302: // do the work.
303:
304: expect(
305: rootElement.triggerEvent(
306: eq(TapestryConstants.PASSIVATE_EVENT),
307: (Object[]) isNull(),
308: isA(ComponentEventHandler.class))).andAnswer(
309: triggerEventAnswer);
310:
311: listener.createdActionLink(isA(Link.class));
312: getMocksControl().andAnswer(createdPageLinkAnswer);
313: }
314:
315: private IAnswer<Void> newAnswerForCreatedLink(
316: final Holder<Link> holder) {
317: return new IAnswer<Void>() {
318: public Void answer() throws Throwable {
319: Link link = (Link) EasyMock.getCurrentArguments()[0];
320:
321: holder.put(link);
322:
323: return null;
324: }
325: };
326: }
327:
328: private IAnswer<Boolean> newAnswerForPassivateEventTrigger() {
329: return new IAnswer<Boolean>() {
330: @SuppressWarnings("unchecked")
331: public Boolean answer() throws Throwable {
332: ComponentEventHandler handler = (ComponentEventHandler) EasyMock
333: .getCurrentArguments()[2];
334:
335: handler.handleResult(new Object[] { "foo", "bar" },
336: null, null);
337:
338: return true;
339: }
340: };
341: }
342:
343: @SuppressWarnings("unchecked")
344: private void testActionLink(String contextPath,
345: String logicalPageName, String nestedId, String eventName,
346: String expectedURI, Object... context) {
347: Request request = mockRequest();
348: Response response = mockResponse();
349: ComponentClassResolver resolver = mockComponentClassResolver();
350: ComponentPageElement element = mockComponentPageElement();
351: Page page = mockPage();
352: ComponentPageElement rootElement = mockComponentPageElement();
353: LinkFactoryListener listener = mockLinkFactoryListener();
354: ComponentInvocationMap map = mockComponentInvocationMap();
355: RequestPageCache cache = mockRequestPageCache();
356:
357: final Holder<Link> holder = new Holder<Link>();
358:
359: train_getContainingPage(element, page);
360: train_getLogicalName(page, logicalPageName);
361: train_getContextPath(request, contextPath);
362: train_getNestedId(element, nestedId);
363:
364: train_getRootElement(page, rootElement);
365: train_triggerPassivateEventForActionLink(rootElement, listener,
366: holder);
367:
368: // This needs to be refactored a bit to be more testable.
369:
370: map.store(isA(Link.class), isA(ComponentInvocation.class));
371:
372: train_encodeURL(response, String.format("%s?%s=foo/bar",
373: expectedURI, InternalConstants.PAGE_CONTEXT_NAME),
374: ENCODED);
375:
376: replay();
377:
378: LinkFactory factory = new LinkFactoryImpl(request, response,
379: resolver, map, cache, _typeCoercer);
380: factory.addListener(listener);
381:
382: Link link = factory.createActionLink(element, eventName, false,
383: context);
384:
385: assertEquals(link.toURI(), ENCODED);
386: assertSame(link, holder.get());
387:
388: verify();
389: }
390: }
|