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.isA;
018:
019: import java.util.Arrays;
020: import java.util.Collection;
021: import java.util.Collections;
022: import java.util.List;
023:
024: import org.apache.tapestry.internal.test.InternalBaseTestCase;
025: import org.apache.tapestry.services.ComponentClassResolver;
026: import org.apache.tapestry.services.LibraryMapping;
027: import org.testng.annotations.Test;
028:
029: public class ComponentClassResolverImplTest extends
030: InternalBaseTestCase {
031: private static final String APP_ROOT_PACKAGE = "org.example.app";
032:
033: private static final String CORE_PREFIX = "core";
034:
035: private static final String CORE_ROOT_PACKAGE = "org.apache.tapestry.corelib";
036:
037: private static final String LIB_PREFIX = "lib";
038:
039: private static final String LIB_ROOT_PACKAGE = "org.example.lib";
040:
041: private ComponentClassResolverImpl create(
042: ComponentInstantiatorSource source,
043: ClassNameLocator locator, LibraryMapping... mappings) {
044: List<LibraryMapping> list = Arrays.asList(mappings);
045:
046: return new ComponentClassResolverImpl(source, locator,
047: APP_ROOT_PACKAGE, list);
048: }
049:
050: @Test
051: public void simple_page_name() {
052: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
053: ClassNameLocator locator = newClassNameLocator();
054:
055: train_for_app_packages(source);
056:
057: String className = APP_ROOT_PACKAGE + ".pages.SimplePage";
058:
059: train_locateComponentClassNames(locator, APP_ROOT_PACKAGE
060: + ".pages", className);
061:
062: replay();
063:
064: ComponentClassResolver resolver = create(source, locator);
065:
066: assertEquals(resolver.resolvePageNameToClassName("SimplePage"),
067: className);
068:
069: verify();
070: }
071:
072: @Test
073: public void canonicalize_existing_page_name() {
074: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
075: ClassNameLocator locator = newClassNameLocator();
076:
077: train_for_app_packages(source);
078:
079: String className = APP_ROOT_PACKAGE + ".pages.SimplePage";
080:
081: train_locateComponentClassNames(locator, APP_ROOT_PACKAGE
082: + ".pages", className);
083:
084: replay();
085:
086: ComponentClassResolver resolver = create(source, locator);
087:
088: assertEquals(resolver.canonicalizePageName("simplepage"),
089: "SimplePage");
090:
091: verify();
092:
093: }
094:
095: @Test
096: public void page_name_in_subfolder() {
097: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
098: ClassNameLocator locator = newClassNameLocator();
099:
100: train_for_app_packages(source);
101:
102: String className = APP_ROOT_PACKAGE
103: + ".pages.subfolder.NestedPage";
104:
105: train_locateComponentClassNames(locator, APP_ROOT_PACKAGE
106: + ".pages", className);
107:
108: replay();
109:
110: ComponentClassResolver resolver = create(source, locator);
111:
112: assertEquals(resolver
113: .resolvePageNameToClassName("subfolder/NestedPage"),
114: className);
115:
116: verify();
117: }
118:
119: @Test
120: public void lots_of_prefixes_and_suffixes_stripped() {
121: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
122: ClassNameLocator locator = newClassNameLocator();
123:
124: train_for_app_packages(source);
125:
126: String className = APP_ROOT_PACKAGE
127: + ".pages.admin.edit.AdminUserEdit";
128:
129: train_locateComponentClassNames(locator, APP_ROOT_PACKAGE
130: + ".pages", className);
131:
132: replay();
133:
134: ComponentClassResolver resolver = create(source, locator);
135:
136: assertEquals(resolver
137: .resolvePageNameToClassName("admin/edit/User"),
138: className);
139:
140: verify();
141: }
142:
143: @Test
144: public void page_in_subfolder() {
145: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
146: ClassNameLocator locator = newClassNameLocator();
147:
148: train_for_app_packages(source);
149:
150: String className = APP_ROOT_PACKAGE
151: + ".pages.subfolder.NestedPage";
152:
153: train_locateComponentClassNames(locator, APP_ROOT_PACKAGE
154: + ".pages", className);
155:
156: replay();
157:
158: ComponentClassResolver resolver = create(source, locator);
159:
160: assertEquals(resolver
161: .resolvePageNameToClassName("subfolder/NestedPage"),
162: className);
163:
164: verify();
165:
166: }
167:
168: @Test
169: public void subfolder_name_as_classname_prefix_is_stripped() {
170: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
171: ClassNameLocator locator = newClassNameLocator();
172:
173: train_for_app_packages(source);
174:
175: String className = APP_ROOT_PACKAGE + ".pages.foo.FooBar";
176:
177: train_locateComponentClassNames(locator, APP_ROOT_PACKAGE
178: + ".pages", className);
179:
180: replay();
181:
182: ComponentClassResolver resolver = create(source, locator);
183:
184: assertEquals(resolver.resolvePageNameToClassName("foo/Bar"),
185: className);
186:
187: verify();
188:
189: }
190:
191: @Test
192: public void is_page_name() {
193: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
194: ClassNameLocator locator = newClassNameLocator();
195:
196: train_for_app_packages(source);
197:
198: String className = APP_ROOT_PACKAGE + ".pages.SimplePage";
199:
200: train_locateComponentClassNames(locator, APP_ROOT_PACKAGE
201: + ".pages", className);
202:
203: replay();
204:
205: ComponentClassResolver resolver = create(source, locator);
206:
207: assertTrue(resolver.isPageName("SimplePage"));
208: assertTrue(resolver.isPageName("simplepage"));
209: assertFalse(resolver.isPageName("UnknownPage"));
210:
211: verify();
212: }
213:
214: @Test
215: public void is_page_name_for_core_page() {
216: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
217: ClassNameLocator locator = newClassNameLocator();
218:
219: train_for_app_packages(source);
220: train_for_packages(source, CORE_ROOT_PACKAGE);
221:
222: String className = CORE_ROOT_PACKAGE + ".pages.CorePage";
223:
224: train_locateComponentClassNames(locator, CORE_ROOT_PACKAGE
225: + ".pages", className);
226:
227: replay();
228:
229: ComponentClassResolver resolver = create(source, locator,
230: new LibraryMapping(CORE_PREFIX, CORE_ROOT_PACKAGE));
231:
232: // Can look like an application page, but still resolves to the core library class name.
233:
234: assertTrue(resolver.isPageName("CorePage"));
235:
236: // Or we can give it its true name
237:
238: assertTrue(resolver.isPageName("core/corepage"));
239:
240: assertFalse(resolver.isPageName("UnknownPage"));
241:
242: verify();
243: }
244:
245: protected final ClassNameLocator newClassNameLocator() {
246: ClassNameLocator locator = newMock(ClassNameLocator.class);
247:
248: stub_locateComponentClassNames(locator);
249:
250: return locator;
251: }
252:
253: private void stub_locateComponentClassNames(ClassNameLocator locator) {
254: Collection<String> noMatches = Collections.emptyList();
255:
256: expect(locator.locateClassNames(isA(String.class)))
257: .andStubReturn(noMatches);
258: }
259:
260: protected final void train_locateComponentClassNames(
261: ClassNameLocator locator, String packageName,
262: String... classNames) {
263: expect(locator.locateClassNames(packageName)).andReturn(
264: Arrays.asList(classNames));
265: }
266:
267: @Test
268: public void class_name_to_simple_page_name() {
269: String className = APP_ROOT_PACKAGE + ".pages.SimplePage";
270:
271: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
272: ClassNameLocator locator = newClassNameLocator();
273:
274: train_for_app_packages(source);
275:
276: train_locateComponentClassNames(locator, APP_ROOT_PACKAGE
277: + ".pages", className);
278:
279: replay();
280:
281: ComponentClassResolver resolver = create(source, locator);
282:
283: assertEquals(
284: resolver.resolvePageClassNameToPageName(className),
285: "SimplePage");
286:
287: verify();
288: }
289:
290: /** All of the caches are handled identically, so we just test the pages for caching. */
291: @Test
292: public void resolved_page_names_are_cached() {
293:
294: String pageClassName = APP_ROOT_PACKAGE + ".pages.SimplePage";
295:
296: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
297: ClassNameLocator locator = newClassNameLocator();
298:
299: train_for_app_packages(source);
300:
301: train_locateComponentClassNames(locator, APP_ROOT_PACKAGE
302: + ".pages", pageClassName);
303:
304: replay();
305:
306: ComponentClassResolverImpl resolver = create(source, locator);
307:
308: assertEquals(resolver.resolvePageNameToClassName("SimplePage"),
309: pageClassName);
310:
311: verify();
312:
313: // No more training, because it's already cached.
314:
315: replay();
316:
317: assertEquals(resolver.resolvePageNameToClassName("SimplePage"),
318: pageClassName);
319:
320: verify();
321:
322: // After clearing the cache, redoes the work.
323:
324: train_locateComponentClassNames(locator, APP_ROOT_PACKAGE
325: + ".pages", pageClassName);
326: stub_locateComponentClassNames(locator);
327:
328: replay();
329:
330: resolver.objectWasInvalidated();
331:
332: assertEquals(resolver.resolvePageNameToClassName("SimplePage"),
333: pageClassName);
334:
335: verify();
336: }
337:
338: @Test
339: public void page_found_in_core_lib() {
340: String className = CORE_ROOT_PACKAGE + ".pages.CorePage";
341:
342: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
343: ClassNameLocator locator = newClassNameLocator();
344:
345: train_for_packages(source, CORE_ROOT_PACKAGE);
346: train_for_app_packages(source);
347:
348: train_locateComponentClassNames(locator, CORE_ROOT_PACKAGE
349: + ".pages", className);
350:
351: replay();
352:
353: ComponentClassResolver resolver = create(source, locator,
354: new LibraryMapping(CORE_PREFIX, CORE_ROOT_PACKAGE));
355:
356: assertEquals(resolver.resolvePageNameToClassName("CorePage"),
357: className);
358:
359: verify();
360: }
361:
362: @Test
363: public void page_class_name_resolved_to_core_page() {
364: String className = CORE_ROOT_PACKAGE + ".pages.CorePage";
365:
366: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
367: ClassNameLocator locator = newClassNameLocator();
368:
369: train_for_packages(source, CORE_ROOT_PACKAGE);
370: train_for_app_packages(source);
371:
372: train_locateComponentClassNames(locator, CORE_ROOT_PACKAGE
373: + ".pages", className);
374:
375: replay();
376:
377: ComponentClassResolver resolver = create(source, locator,
378: new LibraryMapping(CORE_PREFIX, CORE_ROOT_PACKAGE));
379:
380: assertEquals(
381: resolver.resolvePageClassNameToPageName(className),
382: "core/CorePage");
383:
384: verify();
385: }
386:
387: @Test
388: public void page_found_in_library() {
389: String className = LIB_ROOT_PACKAGE + ".pages.LibPage";
390:
391: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
392: ClassNameLocator locator = newClassNameLocator();
393:
394: train_for_packages(source, LIB_ROOT_PACKAGE);
395: train_for_packages(source, CORE_ROOT_PACKAGE);
396: train_for_app_packages(source);
397:
398: train_locateComponentClassNames(locator, LIB_ROOT_PACKAGE
399: + ".pages", className);
400:
401: replay();
402:
403: ComponentClassResolver resolver = create(source, locator,
404: new LibraryMapping(LIB_PREFIX, LIB_ROOT_PACKAGE),
405: new LibraryMapping(CORE_PREFIX, CORE_ROOT_PACKAGE));
406:
407: assertEquals(
408: resolver.resolvePageNameToClassName("lib/LibPage"),
409: className);
410:
411: verify();
412: }
413:
414: @Test
415: public void lookup_by_logical_name_is_case_insensitive() {
416: String className = LIB_ROOT_PACKAGE + ".pages.LibPage";
417:
418: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
419: ClassNameLocator locator = newClassNameLocator();
420:
421: train_for_packages(source, LIB_ROOT_PACKAGE);
422: train_for_packages(source, CORE_ROOT_PACKAGE);
423: train_for_app_packages(source);
424:
425: train_locateComponentClassNames(locator, LIB_ROOT_PACKAGE
426: + ".pages", className);
427:
428: replay();
429:
430: ComponentClassResolver resolver = create(source, locator,
431: new LibraryMapping(LIB_PREFIX, LIB_ROOT_PACKAGE),
432: new LibraryMapping(CORE_PREFIX, CORE_ROOT_PACKAGE));
433:
434: assertEquals(
435: resolver.resolvePageNameToClassName("lib/libpage"),
436: className);
437: assertEquals(
438: resolver.resolvePageNameToClassName("LIB/LIBPAGE"),
439: className);
440:
441: verify();
442: }
443:
444: @Test
445: public void class_name_does_not_resolve_to_page_name() {
446: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
447: ClassNameLocator locator = newClassNameLocator();
448:
449: train_for_packages(source, CORE_ROOT_PACKAGE);
450: train_for_app_packages(source);
451:
452: replay();
453:
454: ComponentClassResolver resolver = create(source, locator,
455: new LibraryMapping(CORE_PREFIX, CORE_ROOT_PACKAGE));
456:
457: String className = LIB_ROOT_PACKAGE + ".pages.LibPage";
458:
459: try {
460: resolver.resolvePageClassNameToPageName(className);
461: unreachable();
462: } catch (IllegalArgumentException ex) {
463: assertEquals(ex.getMessage(),
464: "Unable to resolve class name " + className
465: + " to a logical page name.");
466: }
467:
468: verify();
469: }
470:
471: @Test
472: public void page_name_to_canonicalize_does_not_exist() {
473:
474: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
475: ClassNameLocator locator = newClassNameLocator();
476:
477: train_for_packages(source, CORE_ROOT_PACKAGE);
478: train_for_app_packages(source);
479:
480: train_locateComponentClassNames(locator, APP_ROOT_PACKAGE
481: + ".pages", APP_ROOT_PACKAGE + ".pages.Start");
482:
483: replay();
484:
485: ComponentClassResolver resolver = create(source, locator,
486: new LibraryMapping(CORE_PREFIX, CORE_ROOT_PACKAGE));
487:
488: try {
489: resolver.canonicalizePageName("MissingPage");
490: unreachable();
491: } catch (IllegalArgumentException ex) {
492: assertEquals(
493: ex.getMessage(),
494: "Unable to resolve page \'MissingPage\' to a known page name. Available page names: Start.");
495: }
496:
497: verify();
498: }
499:
500: @Test
501: public void class_name_not_in_a_pages_package() {
502: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
503: ClassNameLocator locator = newClassNameLocator();
504:
505: train_for_packages(source, CORE_ROOT_PACKAGE);
506: train_for_app_packages(source);
507:
508: replay();
509:
510: ComponentClassResolver resolver = create(source, locator,
511: new LibraryMapping(CORE_PREFIX, CORE_ROOT_PACKAGE));
512:
513: String className = CORE_ROOT_PACKAGE + ".foo.CorePage";
514:
515: try {
516: resolver.resolvePageClassNameToPageName(className);
517: unreachable();
518: } catch (IllegalArgumentException ex) {
519: assertEquals(ex.getMessage(),
520: "Unable to resolve class name " + className
521: + " to a logical page name.");
522: }
523:
524: verify();
525: }
526:
527: @Test
528: public void multiple_mappings_for_same_prefix() {
529: String secondaryLibPackage = "org.examples.addon.lib";
530: String className = secondaryLibPackage + ".pages.LibPage";
531:
532: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
533: ClassNameLocator locator = newClassNameLocator();
534:
535: train_for_packages(source, LIB_ROOT_PACKAGE);
536: train_for_packages(source, secondaryLibPackage);
537: train_for_packages(source, CORE_ROOT_PACKAGE);
538: train_for_app_packages(source);
539:
540: train_locateComponentClassNames(locator, secondaryLibPackage
541: + ".pages", className);
542:
543: replay();
544:
545: ComponentClassResolver resolver = create(source, locator,
546: new LibraryMapping(LIB_PREFIX, LIB_ROOT_PACKAGE),
547: new LibraryMapping(LIB_PREFIX, secondaryLibPackage),
548: new LibraryMapping(CORE_PREFIX, CORE_ROOT_PACKAGE));
549:
550: assertEquals(
551: resolver.resolvePageNameToClassName("lib/LibPage"),
552: className);
553:
554: verify();
555: }
556:
557: @Test
558: public void complex_prefix_search_fails() {
559: String deepPackage = "org.deep";
560:
561: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
562: ClassNameLocator locator = newClassNameLocator();
563:
564: train_for_packages(source, deepPackage);
565: train_for_packages(source, LIB_ROOT_PACKAGE);
566: train_for_packages(source, CORE_ROOT_PACKAGE);
567: train_for_app_packages(source);
568:
569: // Is this test even needed any more with the new algorithm?
570:
571: replay();
572:
573: ComponentClassResolver resolver = create(source, locator,
574: new LibraryMapping("lib/deep", deepPackage),
575: new LibraryMapping(LIB_PREFIX, LIB_ROOT_PACKAGE),
576: new LibraryMapping(CORE_PREFIX, CORE_ROOT_PACKAGE));
577:
578: try {
579: resolver.resolvePageNameToClassName("lib/deep/DeepPage");
580: unreachable();
581: } catch (IllegalArgumentException ex) {
582: assertTrue(ex
583: .getMessage()
584: .contains(
585: "Unable to resolve page 'lib/deep/DeepPage' to a component class name."));
586: }
587:
588: verify();
589: }
590:
591: private void train_for_packages(ComponentInstantiatorSource source,
592: String packageName) {
593: source.addPackage(packageName + ".pages");
594: source.addPackage(packageName + ".components");
595: source.addPackage(packageName + ".mixins");
596: source.addPackage(packageName + ".base");
597: }
598:
599: /**
600: * The logic for searching is pretty much identical for both components and pages, so even a
601: * cursory test of component types should nail it.
602: */
603: @Test
604: public void simple_component_type() {
605: String className = APP_ROOT_PACKAGE
606: + ".components.SimpleComponent";
607:
608: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
609: ClassNameLocator locator = newClassNameLocator();
610:
611: train_for_app_packages(source);
612:
613: train_locateComponentClassNames(locator, APP_ROOT_PACKAGE
614: + ".components", className);
615:
616: replay();
617:
618: ComponentClassResolver resolver = create(source, locator);
619:
620: assertEquals(resolver
621: .resolveComponentTypeToClassName("SimpleComponent"),
622: className);
623:
624: verify();
625: }
626:
627: /**
628: * Likewise for mixins; it's all just setup for a particular method.
629: */
630:
631: @Test
632: public void simple_mixin_type() {
633: String expectedClassName = APP_ROOT_PACKAGE
634: + ".mixins.SimpleMixin";
635:
636: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
637: ClassNameLocator locator = newClassNameLocator();
638:
639: train_for_app_packages(source);
640:
641: train_locateComponentClassNames(locator, APP_ROOT_PACKAGE
642: + ".mixins", expectedClassName);
643:
644: replay();
645:
646: ComponentClassResolver resolver = create(source, locator);
647:
648: assertEquals(resolver
649: .resolveMixinTypeToClassName("SimpleMixin"),
650: expectedClassName);
651:
652: verify();
653: }
654:
655: @Test
656: public void mixin_type_not_found() {
657: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
658: ClassNameLocator locator = newClassNameLocator();
659:
660: train_for_packages(source, CORE_ROOT_PACKAGE);
661: train_for_app_packages(source);
662:
663: replay();
664:
665: ComponentClassResolver resolver = create(source, locator,
666: new LibraryMapping(CORE_PREFIX, CORE_ROOT_PACKAGE));
667:
668: try {
669: resolver.resolveMixinTypeToClassName("SimpleMixin");
670: unreachable();
671: } catch (IllegalArgumentException ex) {
672: assertTrue(ex
673: .getMessage()
674: .contains(
675: "Unable to resolve mixin type 'SimpleMixin' to a component class name."));
676: }
677:
678: verify();
679:
680: }
681:
682: @Test
683: public void component_type_not_found() {
684: ComponentInstantiatorSource source = mockComponentInstantiatorSource();
685: ClassNameLocator locator = newClassNameLocator();
686:
687: train_for_packages(source, CORE_ROOT_PACKAGE);
688: train_for_app_packages(source);
689:
690: replay();
691:
692: ComponentClassResolver resolver = create(source, locator,
693: new LibraryMapping(CORE_PREFIX, CORE_ROOT_PACKAGE));
694:
695: try {
696: resolver.resolveComponentTypeToClassName("SimpleComponent");
697: unreachable();
698: } catch (IllegalArgumentException ex) {
699: assertTrue(ex
700: .getMessage()
701: .contains(
702: "Unable to resolve component type 'SimpleComponent' to a component class name."));
703: }
704:
705: verify();
706: }
707:
708: private void train_for_app_packages(
709: ComponentInstantiatorSource source) {
710: train_for_packages(source, APP_ROOT_PACKAGE);
711: }
712: }
|