001    package org.apache.tapestry;
002    
003    import org.apache.commons.logging.Log;
004    import org.apache.hivemind.*;
005    import org.apache.hivemind.impl.DefaultClassResolver;
006    import org.apache.hivemind.impl.RegistryBuilder;
007    import org.apache.hivemind.impl.XmlModuleDescriptorProvider;
008    import org.apache.hivemind.util.URLResource;
009    import org.apache.tapestry.components.ILinkComponent;
010    import org.apache.tapestry.engine.IEngineService;
011    import org.apache.tapestry.engine.ILink;
012    import org.apache.tapestry.engine.NullWriter;
013    import org.apache.tapestry.event.BrowserEvent;
014    import org.apache.tapestry.json.IJSONWriter;
015    import org.apache.tapestry.markup.AsciiMarkupFilter;
016    import org.apache.tapestry.markup.JSONWriterImpl;
017    import org.apache.tapestry.markup.MarkupWriterImpl;
018    import org.apache.tapestry.services.ResponseBuilder;
019    import org.apache.tapestry.services.impl.DefaultResponseBuilder;
020    import org.apache.tapestry.spec.IComponentSpecification;
021    import org.apache.tapestry.spec.IParameterSpecification;
022    import org.apache.tapestry.test.Creator;
023    import org.apache.tapestry.web.WebRequest;
024    import static org.easymock.EasyMock.*;
025    
026    import java.io.CharArrayWriter;
027    import java.io.PrintWriter;
028    import java.net.URL;
029    import java.util.ArrayList;
030    import java.util.Arrays;
031    import java.util.List;
032    import java.util.Locale;
033    
034    /**
035     * Base class for testing components, or testing classes that operate on components. Simplifies
036     * creating much of the infrastructure around the components.
037     *  
038     */
039    public class BaseComponentTestCase extends TestBase
040    {
041        private Creator _creator;
042    
043        protected Creator getCreator()
044        {
045            if (_creator == null)
046                _creator = new Creator();
047            
048            return _creator;
049        }
050    
051        protected ClassResolver getClassResolver()
052        {
053            return new DefaultClassResolver();
054        }
055        
056        protected CharArrayWriter _charArrayWriter;
057    
058        protected IMarkupWriter newBufferWriter()
059        {
060            _charArrayWriter = new CharArrayWriter();
061            PrintWriter pw = new PrintWriter(_charArrayWriter);
062    
063            return new MarkupWriterImpl("text/html", pw, new AsciiMarkupFilter());
064        }
065        
066        protected IJSONWriter newBufferJSONWriter()
067        {
068            _charArrayWriter = new CharArrayWriter();
069            PrintWriter pw = new PrintWriter(_charArrayWriter);
070            
071            return new JSONWriterImpl(pw);
072        }
073        
074        protected void assertBuffer(String expected)
075        {
076            String actual = _charArrayWriter.toString();
077    
078            assertEquals(actual, expected);
079    
080            _charArrayWriter.reset();
081        }
082    
083        protected void assertExceptionSubstring(Throwable t, String msg)
084        {
085            assertTrue(t.getMessage().contains(msg));
086        }
087        
088        protected Object newInstance(Class componentClass)
089        {
090            return newInstance(componentClass, null);
091        }
092    
093        protected Object newInstance(Class componentClass, String propertyName, Object propertyValue)
094        {
095            return getCreator().newInstance(componentClass, new Object[]
096            { propertyName, propertyValue });
097        }
098    
099        protected IRequestCycle newCycle()
100        {
101            return newMock(IRequestCycle.class);
102        }
103    
104        protected IRequestCycle newCycle(IMarkupWriter writer)
105        {
106            IRequestCycle cycle = newMock(IRequestCycle.class);
107            
108            trainResponseBuilder(cycle, writer);
109            
110            return cycle;
111        }
112        
113        protected IRequestCycle newCycle(boolean rewinding)
114        {
115            return newCycle(rewinding, null);
116        }
117        
118        protected IRequestCycle newCycle(boolean rewinding, boolean trainWriter)
119        {
120            IRequestCycle cycle = newRequestCycle();
121            
122            trainIsRewinding(cycle, rewinding);
123            
124            if (trainWriter)
125                trainResponseBuilder(cycle, null);
126            
127            return cycle;
128        }
129        
130        protected IRequestCycle newCycle(boolean rewinding, IMarkupWriter writer)
131        {
132            IRequestCycle cycle = newRequestCycle();
133            checkOrder(cycle, false);
134            
135            trainIsRewinding(cycle, rewinding);
136            
137            if (writer != null)
138                trainResponseBuilder(cycle, writer);
139            
140            return cycle;
141        }
142        
143        protected void trainResponseBuilder(IRequestCycle cycle, IMarkupWriter writer)
144        {
145            ResponseBuilder builder = 
146                new DefaultResponseBuilder(writer == null ? NullWriter.getSharedInstance() : writer);
147            
148            expect(cycle.getResponseBuilder()).andReturn(builder);
149        }
150        
151        protected void trainIsRewinding(IRequestCycle cycle, boolean rewinding)
152        {
153            expect(cycle.isRewinding()).andReturn(rewinding);
154        }
155    
156        protected IRequestCycle newCycleGetPage(String pageName, IPage page)
157        {
158            IRequestCycle cycle = newRequestCycle();
159    
160            expect(cycle.getPage(pageName)).andReturn(page);
161    
162            return cycle;
163        }
164    
165        protected IRequestCycle newCycleGetUniqueId(String id, String uniqueId)
166        {
167            IRequestCycle cycle = newRequestCycle();
168    
169            expect(cycle.getUniqueId(id)).andReturn(uniqueId);
170            return cycle;
171        }
172    
173        protected IRequestCycle newCycleGetParameter(String name, String value)
174        {
175            IRequestCycle cycle = newRequestCycle();
176    
177            expect(cycle.getParameter(name)).andReturn(value);
178            return cycle;
179        }
180    
181        protected IMarkupWriter newWriter()
182        {
183            return newMock(IMarkupWriter.class);
184        }
185    
186        protected IBinding newBinding(Object value)
187        {
188            IBinding binding = newMock(IBinding.class);
189            checkOrder(binding, false);
190            
191            expect(binding.getObject()).andReturn(value);
192            return binding;
193        }
194    
195        protected IBinding newBinding(Location location)
196        {
197            IBinding binding = newBinding();
198            checkOrder(binding, false);
199            
200            trainGetLocation(binding, location);
201    
202            return binding;
203        }
204    
205        protected IComponent newComponent(String extendedId, Location location)
206        {
207            IComponent component = newMock(IComponent.class);
208            checkOrder(component, false);
209            
210            expect(component.getExtendedId()).andReturn(extendedId);
211            expect(component.getLocation()).andReturn(location);
212            return component;
213        }
214    
215        protected IComponentSpecification newSpec(String parameterName, IParameterSpecification pspec)
216        {
217            IComponentSpecification spec = newMock(IComponentSpecification.class);
218    
219            expect(spec.getParameter(parameterName)).andReturn(pspec);
220            return spec;
221        }
222    
223        protected IRender newRender()
224        {
225            return newMock(IRender.class);
226        }
227    
228        protected IPage newPage()
229        {
230            return newMock(IPage.class);
231        }
232    
233        protected IPage newPage(String name)
234        {
235            return newPage(name, 1);
236        }
237    
238        protected IPage newPage(String name, int count)
239        {
240            IPage page = newMock(IPage.class);
241            checkOrder(page, false);
242            
243            expect(page.getPageName()).andReturn(name).times(count);
244            
245            return page;
246        }
247    
248        protected IForm newForm()
249        {
250            return newMock(IForm.class);
251        }
252    
253        protected IRender newBody()
254        {
255            return new IRender()
256            {
257                public void render(IMarkupWriter writer, IRequestCycle cycle)
258                {
259                    writer.print("BODY");
260                }
261            };
262        }
263    
264        protected PageRenderSupport newPageRenderSupport()
265        {
266            return newMock(PageRenderSupport.class);
267        }
268    
269        protected void trainGetSupport(IRequestCycle cycle, PageRenderSupport support)
270        {
271            trainGetAttribute(cycle, TapestryUtils.PAGE_RENDER_SUPPORT_ATTRIBUTE, support);
272        }
273    
274        protected void trainGetAttribute(IRequestCycle cycle, String attributeName, Object attribute)
275        {
276            expect(cycle.getAttribute(attributeName)).andReturn(attribute);
277        }
278    
279        protected void trainGetUniqueId(IRequestCycle cycle, String id, String uniqueId)
280        {
281            expect(cycle.getUniqueId(id)).andReturn(uniqueId);
282        }
283    
284        protected void trainGetIdPath(IComponent component, String idPath)
285        {
286            expect(component.getIdPath()).andReturn(idPath);
287        }
288    
289        protected void trainGetParameter(IRequestCycle cycle, String name, String value)
290        {
291            expect(cycle.getParameter(name)).andReturn(value);
292        }
293    
294        protected void trainGetPageName(IPage page, String pageName)
295        {
296            expect(page.getPageName()).andReturn(pageName);
297        }
298    
299        protected void trainBuildURL(IAsset asset, IRequestCycle cycle, String URL)
300        {
301            expect(asset.buildURL()).andReturn(URL);
302        }
303    
304        protected IAsset newAsset()
305        {
306            return newMock(IAsset.class);
307        }
308    
309        protected IEngine newEngine(ClassResolver resolver)
310        {   
311            return newMock(IEngine.class);
312        }
313    
314        protected void trainGetEngine(IPage page, IEngine engine)
315        {
316            expect(page.getEngine()).andReturn(engine);
317        }
318    
319        protected IComponent newComponent()
320        {
321            return newMock(IComponent.class);
322        }
323    
324        protected void trainGetPage(IComponent component, IPage page)
325        {
326            expect(component.getPage()).andReturn(page);
327        }
328    
329        protected void trainGetExtendedId(IComponent component, String extendedId)
330        {
331            expect(component.getExtendedId()).andReturn(extendedId);
332        }
333    
334        protected void trainGetLocation(Locatable locatable, Location location)
335        {
336            expect(locatable.getLocation()).andReturn(location);
337        }
338    
339        protected IBinding newBinding()
340        {
341            return newMock(IBinding.class);
342        }
343    
344        protected void trainGetComponent(IComponent container, String componentId, IComponent containee)
345        {
346            expect(container.getComponent(componentId)).andReturn(containee);
347        }
348    
349        protected IEngineService newEngineService()
350        {
351            return newMock(IEngineService.class);
352        }
353    
354        protected void trainGetLink(IEngineService service, IRequestCycle cycle, boolean post,
355                Object parameter, ILink link)
356        {
357            expect(service.getLink(post, parameter)).andReturn(link);
358        }
359    
360        protected void trainGetLinkCheckIgnoreParameter(IEngineService service, IRequestCycle cycle,
361                boolean post, Object parameter, ILink link)
362        {
363            expect(service.getLink(eq(post), anyObject())).andReturn(link);
364        }
365    
366        protected void trainGetURL(ILink link, String URL)
367        {
368            expect(link.getURL()).andReturn(URL);
369        }
370    
371        protected void trainGetPageRenderSupport(IRequestCycle cycle, PageRenderSupport support)
372        {
373            trainGetAttribute(cycle, TapestryUtils.PAGE_RENDER_SUPPORT_ATTRIBUTE, support);
374        }
375    
376        protected IComponentSpecification newSpec()
377        {
378            return newMock(IComponentSpecification.class);
379        }
380    
381        protected Resource newResource()
382        {
383            return newMock(Resource.class);
384        }
385    
386        protected WebRequest newRequest()
387        {
388            return newMock(WebRequest.class);
389        }
390    
391        protected Location newLocation()
392        {
393            return newMock(Location.class);
394        }
395        
396        protected Location fabricateLocation(int line)
397        {
398            Location location = newLocation();
399            checkOrder(location, false);
400            
401            expect(location.getLineNumber()).andReturn(line).anyTimes();
402            
403            return location;
404        }
405        
406        protected void trainEncodeURL(IRequestCycle rc, String URL, String encodedURL)
407        {
408            expect(rc.encodeURL(URL)).andReturn(encodedURL);
409        }
410    
411        protected void trainGetServerPort(WebRequest request, int port)
412        {
413            expect(request.getServerPort()).andReturn(port);
414        }
415    
416        protected void trainGetServerName(WebRequest request, String serverName)
417        {
418            expect(request.getServerName()).andReturn(serverName);
419        }
420    
421        protected void trainGetScheme(WebRequest request, String scheme)
422        {
423            expect(request.getScheme()).andReturn(scheme);
424        }
425    
426        protected NestedMarkupWriter newNestedWriter()
427        {
428            return newMock(NestedMarkupWriter.class);
429        }
430    
431        protected void trainGetNestedWriter(IMarkupWriter writer, NestedMarkupWriter nested)
432        {
433            expect(writer.getNestedWriter()).andReturn(nested);
434        }
435        
436        protected void trainGetURL(ILink link, String scheme, String anchor, String URL)
437        {
438            trainGetURL(link, scheme, anchor, URL, 0);
439        }
440        
441        protected void trainGetURL(ILink link, String scheme, String anchor, String URL, int port)
442        {
443            expect(link.getURL(scheme, null, port, anchor, true)).andReturn(URL);
444        }
445    
446        protected ILink newLink()
447        {
448            return newMock(ILink.class);
449        }
450    
451        protected void trainGetLink(ILinkComponent component, IRequestCycle cycle, ILink link)
452        {
453            expect(component.getLink(cycle)).andReturn(link);
454        }
455    
456        protected void trainGetEngine(IRequestCycle cycle, IEngine engine)
457        {
458            expect(cycle.getEngine()).andReturn(engine);
459        }
460    
461        protected void trainGetParameterValues(ILink link, String parameterName, String[] values)
462        {
463            expect(link.getParameterValues(parameterName)).andReturn(values);
464        }
465    
466        protected void trainGetParameterNames(ILink link, String[] names)
467        {
468            expect(link.getParameterNames()).andReturn(names);
469        }
470    
471        protected void trainGetSpecification(IComponent component, IComponentSpecification spec)
472        {
473            expect(component.getSpecification()).andReturn(spec);
474        }
475    
476        protected void trainGetBinding(IComponent component, String name, IBinding binding)
477        {
478            expect(component.getBinding(name)).andReturn(binding);
479        }
480    
481        protected Log newLog()
482        {
483            return newMock(Log.class);
484        }
485    
486        protected void trainGetId(IComponent component, String id)
487        {
488            expect(component.getId()).andReturn(id);
489        }
490        
491        protected void trainExtractBrowserEvent(IRequestCycle cycle)
492        {
493            expect(cycle.getParameter(BrowserEvent.NAME)).andReturn("onClick").anyTimes();
494            
495            expect(cycle.getParameter(BrowserEvent.TYPE)).andReturn("click");
496            expect(cycle.getParameters(BrowserEvent.KEYS)).andReturn(null);
497            expect(cycle.getParameter(BrowserEvent.CHAR_CODE)).andReturn(null);
498            expect(cycle.getParameter(BrowserEvent.PAGE_X)).andReturn("123");
499            expect(cycle.getParameter(BrowserEvent.PAGE_Y)).andReturn("1243");
500            expect(cycle.getParameter(BrowserEvent.LAYER_X)).andReturn(null);
501            expect(cycle.getParameter(BrowserEvent.LAYER_Y)).andReturn(null);
502            
503            expect(cycle.getParameter(BrowserEvent.TARGET + "." + BrowserEvent.TARGET_ATTR_ID))
504            .andReturn("element1");
505        }
506        
507        /**
508         * Convienience method for invoking {@link #buildFrameworkRegistry(String[])} with only a single
509         * file.
510         *
511         * @param file
512         *          The path to the hivemind xml configuration file.
513         * @return The constructed registry.
514         * 
515         * @throws Exception When file can't be found or parsed.
516         */
517        protected Registry buildFrameworkRegistry(String file)
518                throws Exception
519        {
520            return buildFrameworkRegistry(new String[] { file });
521        }
522        
523        /**
524         * Builds a minimal registry, containing only the specified files, plus the master module
525         * descriptor (i.e., those visible on the classpath).
526         *
527         * @param files
528         *          The path to the hivemind xml configuration files to parse.
529         * @return The constructed registry.
530         *
531         * @throws Exception When file can't be found or parsed.
532         */
533        protected Registry buildFrameworkRegistry(String[] files)
534                throws Exception
535        {
536            ClassResolver resolver = getClassResolver();
537    
538            List<Resource> descriptorResources = new ArrayList<Resource>();
539            for (String file : files)
540            {
541                Resource resource = getResource(file);
542    
543                descriptorResources.add(resource);
544            }
545            
546            ModuleDescriptorProvider provider = new XmlModuleDescriptorProvider(resolver, descriptorResources);
547    
548            return buildFrameworkRegistry(provider);
549        }
550        
551        /**
552         * Builds a registry, containing only the modules delivered by the specified
553         * {@link org.apache.hivemind.ModuleDescriptorProvider}, plus the master module descriptor
554         * (i.e., those visible on the classpath).
555         *
556         * @param customProvider
557         *          The custom module provider that should be added to the configuration.
558         *
559         * @return A constructed {@link Registry}.
560         */
561        protected Registry buildFrameworkRegistry(ModuleDescriptorProvider customProvider)
562        {
563            ClassResolver resolver = getClassResolver();
564    
565            RegistryBuilder builder = new RegistryBuilder();
566    
567            builder.addModuleDescriptorProvider(new XmlModuleDescriptorProvider(resolver));
568            builder.addModuleDescriptorProvider(customProvider);
569    
570            return builder.constructRegistry(Locale.getDefault());
571        }
572    
573        /**
574         * Builds a registry from exactly the provided resource; this registry will not include the
575         * <code>hivemind</code> module.
576         *
577         * @param l
578         *         The resource to build the registry from.
579         * @return A constructed {@link Registry} instance.
580         * 
581         * @throws Exception If error building registry.
582         */
583        protected Registry buildMinimalRegistry(Resource l)
584                throws Exception
585        {
586            RegistryBuilder builder = new RegistryBuilder();
587    
588            return builder.constructRegistry(Locale.getDefault());
589        }
590        
591        /**
592         * Returns the given file as a {@link Resource} from the classpath. Typically, this is to find
593         * files in the same folder as the invoking class.
594         *
595         * @param file
596         *          Gets a resource object for the file representing the path specified.
597         * @return A {@link Resource} object.
598         */
599        protected Resource getResource(String file)
600        {
601            URL url = getClass().getResource(file);
602    
603            if (url == null)
604                throw new NullPointerException("No resource named '" + file + "'.");
605    
606            return new URLResource(url);
607        }
608        
609        public static boolean assertListEquals(Object[] expected, Object[] actual)
610        {
611            if (expected == null || actual == null)
612                notEquals(expected, actual);
613            
614            if (!Arrays.equals(expected, actual))
615                notEquals(expected, actual);
616            
617            return true;
618        }
619        
620        public static boolean assertListEquals(Object[] expected, List actual)
621        {
622            if (expected == null || actual == null)
623                notEquals(expected, actual);
624            
625            Object[] acarr = actual.toArray(new Object[actual.size()]);
626            return assertListEquals(expected, acarr);
627        }
628        
629        public static void notEquals(Object expected, Object actual)
630        {
631            throw new AssertionError("Parameters don't match, expected: <"
632                    + expected + "> actual: <" + actual + ">");
633        }
634    }