View Javadoc

1   /*
2    * $Id: TestActionServlet.java 421119 2006-07-12 04:49:11Z wsmoak $
3    *
4    * Copyright 1999-2004 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.struts.action;
19  
20  import junit.framework.Test;
21  import junit.framework.TestCase;
22  import junit.framework.TestSuite;
23  
24  import org.apache.struts.config.ActionConfig;
25  import org.apache.struts.config.ExceptionConfig;
26  import org.apache.struts.config.FormBeanConfig;
27  import org.apache.struts.config.FormPropertyConfig;
28  import org.apache.struts.config.ForwardConfig;
29  import org.apache.struts.config.ModuleConfig;
30  import org.apache.struts.config.ModuleConfigFactory;
31  import org.apache.struts.util.MessageResources;
32  
33  import javax.servlet.ServletException;
34  import javax.servlet.UnavailableException;
35  
36  import java.util.List;
37  
38  /***
39   * Suite of unit tests for the <code>org.apache.struts.action.ActionServlet</code>
40   * class.
41   */
42  public class TestActionServlet extends TestCase {
43      // ----------------------------------------------------- Instance Variables
44  
45      /***
46       * The ModuleConfig we'll use.
47       */
48      protected ModuleConfig moduleConfig = null;
49  
50      /***
51       * The common form bean we'll use.
52       */
53      protected FormBeanConfig baseFormBean = null;
54  
55      /***
56       * The common exception config we'll use.
57       */
58      protected ExceptionConfig baseException = null;
59  
60      /***
61       * The common action config we'll use.
62       */
63      protected ActionMapping baseAction = null;
64  
65      /***
66       * The common action forward we'll use.
67       */
68      protected ActionForward baseForward = null;
69  
70      /***
71       * The ActionServlet we'll test.
72       */
73      protected ActionServlet actionServlet = null;
74  
75      // ------------------------------------------ Constructors, suite, and main
76  
77      /***
78       * Defines the testcase name for JUnit.
79       *
80       * @param theName the testcase's name.
81       */
82      public TestActionServlet(String theName) {
83          super(theName);
84      }
85  
86      /***
87       * Start the tests.
88       *
89       * @param theArgs the arguments. Not used
90       */
91      public static void main(String[] theArgs) {
92          junit.awtui.TestRunner.main(new String[] {
93                  TestActionServlet.class.getName()
94              });
95      }
96  
97      /***
98       * @return a test suite (<code>TestSuite</code>) that includes all methods
99       *         starting with "test"
100      */
101     public static Test suite() {
102         // All methods starting with "test" will be executed in the test suite.
103         return new TestSuite(TestActionServlet.class);
104     }
105 
106     // ------------------------------------------------- setUp() and tearDown()
107 
108     /***
109      * Set up instance variables required by this test case.
110      */
111     public void setUp() throws Exception {
112         actionServlet = new ActionServlet();
113         actionServlet.initInternal();
114 
115         ModuleConfigFactory factoryObject = ModuleConfigFactory.createFactory();
116 
117         moduleConfig = factoryObject.createModuleConfig("");
118 
119         // Setup the base form
120         baseFormBean = new FormBeanConfig();
121         baseFormBean.setName("baseForm");
122         baseFormBean.setType("org.apache.struts.action.DynaActionForm");
123 
124         // Set up id, name, and score
125         FormPropertyConfig property = new FormPropertyConfig();
126 
127         property.setName("id");
128         property.setType("java.lang.String");
129         baseFormBean.addFormPropertyConfig(property);
130 
131         property = new FormPropertyConfig();
132         property.setName("name");
133         property.setType("java.lang.String");
134         baseFormBean.addFormPropertyConfig(property);
135 
136         property = new FormPropertyConfig();
137         property.setName("score");
138         property.setType("java.lang.String");
139         baseFormBean.addFormPropertyConfig(property);
140 
141         // Setup the exception handler
142         baseException = new ExceptionConfig();
143         baseException.setType("java.lang.NullPointerException");
144         baseException.setKey("msg.exception.npe");
145 
146         // Setup the forward config
147         baseForward = new ActionForward("success", "/succes.jsp", false);
148 
149         // Setup the action config
150         baseAction = new ActionMapping();
151         baseAction.setPath("/index");
152         baseAction.setType("org.apache.struts.actions.DummyAction");
153         baseAction.setName("someForm");
154         baseAction.setInput("/input.jsp");
155         baseAction.addForwardConfig(new ActionForward("next", "/next.jsp", false));
156         baseAction.addForwardConfig(new ActionForward("prev", "/prev.jsp", false));
157 
158         ExceptionConfig exceptionConfig = new ExceptionConfig();
159 
160         exceptionConfig.setType("java.sql.SQLException");
161         exceptionConfig.setKey("msg.exception.sql");
162         baseAction.addExceptionConfig(exceptionConfig);
163 
164         // Nothing is registered to our module config until they are needed
165     }
166 
167     /***
168      * Tear down instance variables required by this test case.
169      */
170     public void tearDown() {
171         moduleConfig = null;
172     }
173 
174     // ----------------------------- initInternal() and destroyInternal() tests
175 
176     /***
177      * Verify that we can initialize and destroy our internal message
178      * resources object.
179      */
180     public void testInitDestroyInternal() {
181         ActionServlet servlet = new ActionServlet();
182 
183         try {
184             servlet.initInternal();
185         } catch (ServletException e) {
186             fail("initInternal() threw exception: " + e);
187         }
188 
189         assertTrue("internal was initialized", servlet.getInternal() != null);
190         assertTrue("internal of correct type",
191             servlet.getInternal() instanceof MessageResources);
192         servlet.destroyInternal();
193         assertTrue("internal was destroyed", servlet.getInternal() == null);
194     }
195 
196     /***
197      * Test class loader resolution and splitting.
198      */
199     public void notestSplitAndResolvePaths()
200         throws Exception {
201         ActionServlet servlet = new ActionServlet();
202         List list =
203             servlet.splitAndResolvePaths(
204                 "org/apache/struts/config/struts-config.xml");
205 
206         assertNotNull(list);
207         assertTrue("List size should be 1", list.size() == 1);
208 
209         list =
210             servlet.splitAndResolvePaths(
211                 "org/apache/struts/config/struts-config.xml, "
212                 + "org/apache/struts/config/struts-config-1.1.xml");
213         assertNotNull(list);
214         assertTrue("List size should be 2, was " + list.size(), list.size() == 2);
215 
216         list = servlet.splitAndResolvePaths("META-INF/MANIFEST.MF");
217         assertNotNull(list);
218         assertTrue("Number of manifests should be more than 5, was "
219             + list.size(), list.size() > 5);
220 
221         // test invalid path
222         try {
223             list =
224                 servlet.splitAndResolvePaths(
225                     "org/apache/struts/config/struts-asdfasdfconfig.xml");
226             fail("Should have thrown an exception on bad path");
227         } catch (NullPointerException ex) {
228             // correct behavior since internal error resources aren't loaded
229         }
230     }
231 
232     //----- Test initApplication() method --------------------------------------
233 
234     /***
235      * Verify that nothing happens if no "application" property is defined in
236      * the servlet configuration.
237      */
238 
239     /*
240     public void testInitApplicationNull() throws ServletException
241     {
242         ActionServlet servlet = new ActionServlet();
243         servlet.init(config);
244 
245         // Test the initApplication() method
246         servlet.initApplication();
247 
248         // As no "application" object is found in the servlet config, no
249         // attribute should be set in the context
250         assertTrue(config.getServletContext().getAttribute(Action.MESSAGES_KEY) == null);
251     }
252     */
253 
254     /***
255      * Verify that eveything is fine when only a "application" parameter is
256      * defined in the servlet configuration.
257      */
258 
259     /*
260     public void testInitApplicationOk1() throws ServletException
261     {
262         // initialize config
263         config.setInitParameter("application", "org.apache.struts.webapp.example.ApplicationResources");
264 
265         ActionServlet servlet = new ActionServlet();
266         servlet.init(config);
267 
268         // Test the initApplication() method
269         servlet.initApplication();
270 
271         assertTrue(servlet.application != null);
272         assertTrue(servlet.application.getReturnNull() == true);
273 
274         assertTrue(config.getServletContext().getAttribute(Action.MESSAGES_KEY) != null);
275         assertEquals(servlet.application, config.getServletContext().getAttribute(Action.MESSAGES_KEY));
276 
277     }
278     */
279 
280     // --------------------------------------------------- FormBeanConfig Tests
281 
282     /***
283      * Test that nothing fails if there are no extensions.
284      */
285     public void testInitModuleFormBeansNoExtends()
286         throws ServletException {
287         moduleConfig.addFormBeanConfig(baseFormBean);
288 
289         try {
290             actionServlet.initModuleExceptionConfigs(moduleConfig);
291         } catch (Exception e) {
292             fail("Unexpected exception caught.");
293         }
294     }
295 
296     /***
297      * Test that initModuleFormBeans throws an exception when a form with a
298      * null type is present.
299      */
300     public void testInitModuleFormBeansNullFormType()
301         throws ServletException {
302         FormBeanConfig formBean = new FormBeanConfig();
303 
304         formBean.setName("noTypeForm");
305         moduleConfig.addFormBeanConfig(formBean);
306 
307         try {
308             actionServlet.initModuleFormBeans(moduleConfig);
309             fail("An exception should've been thrown here.");
310         } catch (UnavailableException e) {
311             // success
312         } catch (Exception e) {
313             fail("Unrecognized exception thrown: " + e);
314         }
315     }
316 
317     /***
318      * Test that initModuleFormBeans throws an exception when a form whose
319      * prop type is null is present.
320      */
321     public void testInitModuleFormBeansNullPropType()
322         throws ServletException {
323         moduleConfig.addFormBeanConfig(baseFormBean);
324         baseFormBean.findFormPropertyConfig("name").setType(null);
325 
326         try {
327             actionServlet.initModuleFormBeans(moduleConfig);
328             fail("An exception should've been thrown here.");
329         } catch (UnavailableException e) {
330             // success
331         } catch (Exception e) {
332             fail("Unrecognized exception thrown: " + e);
333         }
334     }
335 
336     /***
337      * Test that processFormBeanExtension() calls processExtends()
338      */
339     public void testProcessFormBeanExtension()
340         throws ServletException {
341         CustomFormBeanConfig form = new CustomFormBeanConfig();
342 
343         actionServlet.processFormBeanExtension(form, moduleConfig);
344 
345         assertTrue("processExtends() was not called", form.processExtendsCalled);
346     }
347 
348     /***
349      * Make sure processFormBeanConfigClass() returns an instance of the
350      * correct class if the base config is using a custom class.
351      */
352     public void testProcessFormBeanConfigClass()
353         throws Exception {
354         CustomFormBeanConfig customBase = new CustomFormBeanConfig();
355 
356         customBase.setName("customBase");
357         moduleConfig.addFormBeanConfig(customBase);
358 
359         FormBeanConfig customSub = new FormBeanConfig();
360 
361         customSub.setName("customSub");
362         customSub.setExtends("customBase");
363         customSub.setType("org.apache.struts.action.DynaActionForm");
364         moduleConfig.addFormBeanConfig(customSub);
365 
366         FormBeanConfig result =
367             actionServlet.processFormBeanConfigClass(customSub, moduleConfig);
368 
369         assertTrue("Incorrect class of form bean config",
370             result instanceof CustomFormBeanConfig);
371         assertEquals("Incorrect name", customSub.getName(), result.getName());
372         assertEquals("Incorrect type", customSub.getType(), result.getType());
373         assertEquals("Incorrect extends", customSub.getExtends(),
374             result.getExtends());
375         assertEquals("Incorrect 'restricted' value", customSub.isRestricted(),
376             result.isRestricted());
377 
378         assertSame("Result was not registered in the module config", result,
379             moduleConfig.findFormBeanConfig("customSub"));
380     }
381 
382     /***
383      * Make sure processFormBeanConfigClass() returns what it was given if the
384      * form passed to it doesn't extend anything.
385      */
386     public void testProcessFormBeanConfigClassNoExtends()
387         throws Exception {
388         moduleConfig.addFormBeanConfig(baseFormBean);
389 
390         FormBeanConfig result = null;
391 
392         try {
393             result =
394                 actionServlet.processFormBeanConfigClass(baseFormBean,
395                     moduleConfig);
396         } catch (UnavailableException e) {
397             fail("An exception should not be thrown when there's nothing to do");
398         }
399 
400         assertSame("Result should be the same as the input.", baseFormBean,
401             result);
402     }
403 
404     /***
405      * Make sure processFormBeanConfigClass() returns the same class instance
406      * if the base config isn't using a custom class.
407      */
408     public void testProcessFormBeanConfigClassSubFormCustomClass()
409         throws Exception {
410         moduleConfig.addFormBeanConfig(baseFormBean);
411 
412         FormBeanConfig customSub = new FormBeanConfig();
413 
414         customSub.setName("customSub");
415         customSub.setExtends("baseForm");
416         moduleConfig.addFormBeanConfig(customSub);
417 
418         FormBeanConfig result =
419             actionServlet.processFormBeanConfigClass(customSub, moduleConfig);
420 
421         assertSame("The instance returned should be the param given it.",
422             customSub, result);
423     }
424 
425     /***
426      * Make sure the code throws the correct exception when it can't create an
427      * instance of the base config's custom class.
428      */
429     public void notestProcessFormBeanConfigClassError()
430         throws Exception {
431         CustomFormBeanConfigArg customBase =
432             new CustomFormBeanConfigArg("customBase");
433 
434         moduleConfig.addFormBeanConfig(customBase);
435 
436         FormBeanConfig customSub = new FormBeanConfig();
437 
438         customSub.setName("customSub");
439         customSub.setExtends("customBase");
440         moduleConfig.addFormBeanConfig(customSub);
441 
442         try {
443             actionServlet.processFormBeanConfigClass(customSub, moduleConfig);
444             fail("Exception should be thrown");
445         } catch (UnavailableException e) {
446             // success
447         } catch (Exception e) {
448             fail("Unexpected exception thrown.");
449         }
450     }
451 
452     /***
453      * Test the case where the subform has already specified its own form bean
454      * config class.  If the code still attempts to create a new instance, an
455      * error will be thrown.
456      */
457     public void testProcessFormBeanConfigClassOverriddenSubFormClass()
458         throws Exception {
459         CustomFormBeanConfigArg customBase =
460             new CustomFormBeanConfigArg("customBase");
461 
462         moduleConfig.addFormBeanConfig(customBase);
463 
464         FormBeanConfig customSub = new CustomFormBeanConfigArg("customSub");
465 
466         customSub.setExtends("customBase");
467         moduleConfig.addFormBeanConfig(customSub);
468 
469         try {
470             actionServlet.processFormBeanConfigClass(customSub, moduleConfig);
471         } catch (Exception e) {
472             fail("Exception should not be thrown");
473         }
474     }
475 
476     // -------------------------------------------------- ExceptionConfig Tests
477 
478     /***
479      * Test that nothing fails if there are no extensions.
480      */
481     public void testInitModuleExceptionConfigsNoExtends()
482         throws ServletException {
483         moduleConfig.addExceptionConfig(baseException);
484 
485         try {
486             actionServlet.initModuleExceptionConfigs(moduleConfig);
487         } catch (Exception e) {
488             fail("Unexpected exception caught.");
489         }
490     }
491 
492     /***
493      * Test that initModuleExceptionConfigs throws an exception when a handler
494      * with a null key is present.
495      */
496     public void testInitModuleExceptionConfigsNullFormType()
497         throws ServletException {
498         ExceptionConfig handler = new ExceptionConfig();
499 
500         handler.setType("java.lang.NullPointerException");
501         moduleConfig.addExceptionConfig(handler);
502 
503         try {
504             actionServlet.initModuleExceptionConfigs(moduleConfig);
505             fail("An exception should've been thrown here.");
506         } catch (UnavailableException e) {
507             // success
508         } catch (Exception e) {
509             fail("Unrecognized exception thrown: " + e);
510         }
511     }
512 
513     /***
514      * Test that processExceptionExtension() calls processExtends()
515      */
516     public void testProcessExceptionExtension()
517         throws ServletException {
518         CustomExceptionConfig handler = new CustomExceptionConfig();
519 
520         handler.setType("java.lang.NullPointerException");
521         moduleConfig.addExceptionConfig(handler);
522         actionServlet.processExceptionExtension(handler, moduleConfig);
523 
524         assertTrue("processExtends() was not called",
525             handler.processExtendsCalled);
526     }
527 
528     /***
529      * Make sure processExceptionConfigClass() returns an instance of the
530      * correct class if the base config is using a custom class.
531      */
532     public void testProcessExceptionConfigClass()
533         throws Exception {
534         CustomExceptionConfig customBase = new CustomExceptionConfig();
535 
536         customBase.setType("java.lang.NullPointerException");
537         customBase.setKey("msg.exception.npe");
538         moduleConfig.addExceptionConfig(customBase);
539 
540         ExceptionConfig customSub = new ExceptionConfig();
541 
542         customSub.setType("java.lang.IllegalStateException");
543         customSub.setExtends("java.lang.NullPointerException");
544         moduleConfig.addExceptionConfig(customSub);
545 
546         ExceptionConfig result =
547             actionServlet.processExceptionConfigClass(customSub, moduleConfig);
548 
549         assertTrue("Incorrect class of exception config",
550             result instanceof CustomExceptionConfig);
551         assertEquals("Incorrect type", customSub.getType(), result.getType());
552         assertEquals("Incorrect key", customSub.getKey(), result.getKey());
553         assertEquals("Incorrect extends", customSub.getExtends(),
554             result.getExtends());
555 
556         assertSame("Result was not registered in the module config", result,
557             moduleConfig.findExceptionConfig("java.lang.IllegalStateException"));
558     }
559 
560     /***
561      * Make sure processExceptionConfigClass() returns what it was given if
562      * the handler passed to it doesn't extend anything.
563      */
564     public void testProcessExceptionConfigClassNoExtends()
565         throws Exception {
566         moduleConfig.addExceptionConfig(baseException);
567 
568         ExceptionConfig result = null;
569 
570         try {
571             result =
572                 actionServlet.processExceptionConfigClass(baseException,
573                     moduleConfig);
574         } catch (UnavailableException e) {
575             fail("An exception should not be thrown when there's nothing to do");
576         }
577 
578         assertSame("Result should be the same as the input.", baseException,
579             result);
580     }
581 
582     /***
583      * Make sure processExceptionConfigClass() returns the same class instance
584      * if the base config isn't using a custom class.
585      */
586     public void testProcessExceptionConfigClassSubConfigCustomClass()
587         throws Exception {
588         moduleConfig.addExceptionConfig(baseException);
589 
590         ExceptionConfig customSub = new ExceptionConfig();
591 
592         customSub.setType("java.lang.IllegalStateException");
593         customSub.setExtends("java.lang.NullPointerException");
594         moduleConfig.addExceptionConfig(customSub);
595 
596         ExceptionConfig result =
597             actionServlet.processExceptionConfigClass(customSub, moduleConfig);
598 
599         assertSame("The instance returned should be the param given it.",
600             customSub, result);
601     }
602 
603     /***
604      * Make sure the code throws the correct exception when it can't create an
605      * instance of the base config's custom class.
606      */
607     public void notestProcessExceptionConfigClassError()
608         throws Exception {
609         ExceptionConfig customBase =
610             new CustomExceptionConfigArg("java.lang.NullPointerException");
611 
612         moduleConfig.addExceptionConfig(customBase);
613 
614         ExceptionConfig customSub = new ExceptionConfig();
615 
616         customSub.setType("java.lang.IllegalStateException");
617         customSub.setExtends("java.lang.NullPointerException");
618         moduleConfig.addExceptionConfig(customSub);
619 
620         try {
621             actionServlet.processExceptionConfigClass(customSub, moduleConfig);
622             fail("Exception should be thrown");
623         } catch (UnavailableException e) {
624             // success
625         } catch (Exception e) {
626             fail("Unexpected exception thrown.");
627         }
628     }
629 
630     /***
631      * Test the case where the subconfig has already specified its own config
632      * class.  If the code still attempts to create a new instance, an error
633      * will be thrown.
634      */
635     public void testProcessExceptionConfigClassOverriddenSubFormClass()
636         throws Exception {
637         moduleConfig.addExceptionConfig(baseException);
638 
639         ExceptionConfig customSub =
640             new CustomExceptionConfigArg("java.lang.IllegalStateException");
641 
642         customSub.setExtends("java.lang.NullPointerException");
643         moduleConfig.addExceptionConfig(customSub);
644 
645         try {
646             actionServlet.processExceptionConfigClass(customSub, moduleConfig);
647         } catch (Exception e) {
648             fail("Exception should not be thrown");
649         }
650     }
651 
652     // ---------------------------------------------------- ForwardConfig Tests
653 
654     /***
655      * Test that nothing fails if there are no extensions.
656      */
657     public void testInitModuleForwardConfigsNoExtends()
658         throws ServletException {
659         moduleConfig.addForwardConfig(baseForward);
660 
661         try {
662             actionServlet.initModuleForwards(moduleConfig);
663         } catch (Exception e) {
664             fail("Unexpected exception caught.");
665         }
666     }
667 
668     /***
669      * Test that initModuleForwards throws an exception when a forward with a
670      * null path is present.
671      */
672     public void testInitModuleForwardsNullFormType()
673         throws ServletException {
674         ActionForward forward = new ActionForward("success", null, false);
675 
676         moduleConfig.addForwardConfig(forward);
677 
678         try {
679             actionServlet.initModuleForwards(moduleConfig);
680             fail("An exception should've been thrown here.");
681         } catch (UnavailableException e) {
682             // success
683         } catch (Exception e) {
684             fail("Unrecognized exception thrown: " + e);
685         }
686     }
687 
688     /***
689      * Test that processForwardExtension() calls processExtends()
690      */
691     public void testProcessForwardExtension()
692         throws ServletException {
693         CustomForwardConfig forward =
694             new CustomForwardConfig("forward", "/forward.jsp");
695 
696         moduleConfig.addForwardConfig(forward);
697         actionServlet.processForwardExtension(forward, moduleConfig);
698 
699         assertTrue("processExtends() was not called",
700             forward.processExtendsCalled);
701     }
702 
703     /***
704      * Make sure processForwardConfigClass() returns an instance of the
705      * correct class if the base config is using a custom class.
706      */
707     public void testProcessForwardConfigClass()
708         throws Exception {
709         CustomForwardConfig customBase =
710             new CustomForwardConfig("success", "/success.jsp");
711 
712         moduleConfig.addForwardConfig(customBase);
713 
714         ActionForward customSub = new ActionForward();
715 
716         customSub.setName("failure");
717         customSub.setExtends("success");
718         moduleConfig.addForwardConfig(customSub);
719 
720         ForwardConfig result =
721             actionServlet.processForwardConfigClass(customSub, moduleConfig);
722 
723         assertTrue("Incorrect class of forward config",
724             result instanceof CustomForwardConfig);
725         assertEquals("Incorrect name", customSub.getName(), result.getName());
726         assertEquals("Incorrect path", customSub.getPath(), result.getPath());
727         assertEquals("Incorrect extends", customSub.getExtends(),
728             result.getExtends());
729 
730         assertSame("Result was not registered in the module config", result,
731             moduleConfig.findForwardConfig("failure"));
732     }
733 
734     /***
735      * Make sure processForwardConfigClass() returns what it was given if the
736      * forward passed to it doesn't extend anything.
737      */
738     public void testProcessForwardConfigClassNoExtends()
739         throws Exception {
740         moduleConfig.addForwardConfig(baseForward);
741 
742         ForwardConfig result = null;
743 
744         try {
745             result =
746                 actionServlet.processForwardConfigClass(baseForward,
747                     moduleConfig);
748         } catch (UnavailableException e) {
749             fail("An exception should not be thrown when there's nothing to do");
750         }
751 
752         assertSame("Result should be the same as the input.", baseForward,
753             result);
754     }
755 
756     /***
757      * Make sure processForwardConfigClass() returns the same class instance
758      * if the base config isn't using a custom class.
759      */
760     public void testProcessForwardConfigClassSubConfigCustomClass()
761         throws Exception {
762         moduleConfig.addForwardConfig(baseForward);
763 
764         ForwardConfig customSub = new ActionForward();
765 
766         customSub.setName("failure");
767         customSub.setExtends("success");
768         moduleConfig.addForwardConfig(customSub);
769 
770         ForwardConfig result =
771             actionServlet.processForwardConfigClass(customSub, moduleConfig);
772 
773         assertSame("The instance returned should be the param given it.",
774             customSub, result);
775     }
776 
777     /***
778      * Make sure the code throws the correct exception when it can't create an
779      * instance of the base config's custom class.
780      */
781     public void notestProcessForwardConfigClassError()
782         throws Exception {
783         ForwardConfig customBase =
784             new CustomForwardConfigArg("success", "/success.jsp");
785 
786         moduleConfig.addForwardConfig(customBase);
787 
788         ForwardConfig customSub = new ActionForward();
789 
790         customSub.setName("failure");
791         customSub.setExtends("success");
792         moduleConfig.addForwardConfig(customSub);
793 
794         try {
795             actionServlet.processForwardConfigClass(customSub, moduleConfig);
796             fail("Exception should be thrown");
797         } catch (UnavailableException e) {
798             // success
799         } catch (Exception e) {
800             fail("Unexpected exception thrown.");
801         }
802     }
803 
804     /***
805      * Test the case where the subconfig has already specified its own config
806      * class.  If the code still attempts to create a new instance, an error
807      * will be thrown.
808      */
809     public void testProcessForwardConfigClassOverriddenSubConfigClass()
810         throws Exception {
811         moduleConfig.addForwardConfig(baseForward);
812 
813         ForwardConfig customSub =
814             new CustomForwardConfigArg("failure", "/failure.jsp");
815 
816         customSub.setExtends("success");
817         moduleConfig.addForwardConfig(customSub);
818 
819         try {
820             actionServlet.processForwardConfigClass(customSub, moduleConfig);
821         } catch (Exception e) {
822             fail("Exception should not be thrown");
823         }
824     }
825 
826     // --------------------------------------------------- ActionConfig Tests
827 
828     /***
829      * Test that nothing fails if there are no extensions.
830      */
831     public void testInitModuleActionConfigsNoExtends()
832         throws ServletException {
833         moduleConfig.addActionConfig(baseAction);
834 
835         try {
836             actionServlet.initModuleActions(moduleConfig);
837         } catch (Exception e) {
838             fail("Unexpected exception caught.");
839         }
840     }
841 
842     /***
843      * Test that processActionConfigExtension() calls processExtends()
844      */
845     public void testProcessActionExtension()
846         throws ServletException {
847         CustomActionConfig action = new CustomActionConfig("/action");
848 
849         moduleConfig.addActionConfig(action);
850         actionServlet.processActionConfigExtension(action, moduleConfig);
851 
852         assertTrue("processExtends() was not called",
853             action.processExtendsCalled);
854     }
855 
856     /***
857      * Make sure processActionConfigClass() returns an instance of the correct
858      * class if the base config is using a custom class.
859      */
860     public void testProcessActionConfigClass()
861         throws Exception {
862         CustomActionConfig customBase = new CustomActionConfig("/base");
863 
864         moduleConfig.addActionConfig(customBase);
865 
866         ActionMapping customSub = new ActionMapping();
867 
868         customSub.setPath("/sub");
869         customSub.setExtends("/base");
870         moduleConfig.addActionConfig(customSub);
871 
872         ActionConfig result =
873             actionServlet.processActionConfigClass(customSub, moduleConfig);
874 
875         assertTrue("Incorrect class of action config",
876             result instanceof CustomActionConfig);
877         assertEquals("Incorrect path", customSub.getPath(), result.getPath());
878         assertEquals("Incorrect extends", customSub.getExtends(),
879             result.getExtends());
880 
881         assertSame("Result was not registered in the module config", result,
882             moduleConfig.findActionConfig("/sub"));
883     }
884 
885     /***
886      * Make sure processActionConfigClass() returns what it was given if the
887      * action passed to it doesn't extend anything.
888      */
889     public void testProcessActionConfigClassNoExtends()
890         throws Exception {
891         moduleConfig.addActionConfig(baseAction);
892 
893         ActionConfig result = null;
894 
895         try {
896             result =
897                 actionServlet.processActionConfigClass(baseAction, moduleConfig);
898         } catch (UnavailableException e) {
899             fail("An exception should not be thrown here");
900         }
901 
902         assertSame("Result should be the same as the input.", baseAction, result);
903     }
904 
905     /***
906      * Make sure processActionConfigClass() returns the same class instance if
907      * the base config isn't using a custom class.
908      */
909     public void testProcessActionConfigClassSubConfigCustomClass()
910         throws Exception {
911         moduleConfig.addActionConfig(baseAction);
912 
913         ActionConfig customSub = new ActionMapping();
914 
915         customSub.setPath("/sub");
916         customSub.setExtends("/index");
917         moduleConfig.addActionConfig(customSub);
918 
919         ActionConfig result =
920             actionServlet.processActionConfigClass(customSub, moduleConfig);
921 
922         assertSame("The instance returned should be the param given it.",
923             customSub, result);
924     }
925 
926     /***
927      * Make sure the code throws the correct exception when it can't create an
928      * instance of the base config's custom class.
929      */
930     public void notestProcessActionConfigClassError()
931         throws Exception {
932         ActionConfig customBase = new CustomActionConfigArg("/index");
933 
934         moduleConfig.addActionConfig(customBase);
935 
936         ActionConfig customSub = new ActionMapping();
937 
938         customSub.setPath("/sub");
939         customSub.setExtends("/index");
940         moduleConfig.addActionConfig(customSub);
941 
942         try {
943             actionServlet.processActionConfigClass(customSub, moduleConfig);
944             fail("Exception should be thrown");
945         } catch (UnavailableException e) {
946             // success
947         } catch (Exception e) {
948             fail("Unexpected exception thrown.");
949         }
950     }
951 
952     /***
953      * Test the case where the subconfig has already specified its own config
954      * class.  If the code still attempts to create a new instance, an error
955      * will be thrown.
956      */
957     public void testProcessActionConfigClassOverriddenSubConfigClass()
958         throws Exception {
959         moduleConfig.addActionConfig(baseAction);
960 
961         ActionConfig customSub = new CustomActionConfigArg("/sub");
962 
963         customSub.setExtends("/index");
964         moduleConfig.addActionConfig(customSub);
965 
966         try {
967             actionServlet.processActionConfigClass(customSub, moduleConfig);
968         } catch (Exception e) {
969             fail("Exception should not be thrown");
970         }
971     }
972 
973     /***
974      * Used for testing custom FormBeanConfig classes.
975      */
976     public static class CustomFormBeanConfig extends FormBeanConfig {
977         public boolean processExtendsCalled = false;
978 
979         public CustomFormBeanConfig() {
980             super();
981         }
982 
983         /***
984          * Set a flag so we know this method was called.
985          */
986         public void processExtends(ModuleConfig moduleConfig)
987             throws ClassNotFoundException, IllegalAccessException,
988                 InstantiationException {
989             processExtendsCalled = true;
990         }
991     }
992 
993     /***
994      * Used to test cases where the subclass cannot be created with a no-arg
995      * constructor.
996      */
997     private class CustomFormBeanConfigArg extends FormBeanConfig {
998         CustomFormBeanConfigArg(String name) {
999             super();
1000             setName(name);
1001         }
1002     }
1003 
1004     /***
1005      * Used for testing custom ExceptionConfig classes.
1006      */
1007     public static class CustomExceptionConfig extends ExceptionConfig {
1008         public boolean processExtendsCalled = false;
1009 
1010         public CustomExceptionConfig() {
1011             super();
1012         }
1013 
1014         /***
1015          * Set a flag so we know this method was called.
1016          */
1017         public void processExtends(ModuleConfig moduleConfig,
1018             ActionConfig actionConfig)
1019             throws ClassNotFoundException, IllegalAccessException,
1020                 InstantiationException {
1021             processExtendsCalled = true;
1022         }
1023     }
1024 
1025     /***
1026      * Used to test cases where the subclass cannot be created with a no-arg
1027      * constructor.
1028      */
1029     private class CustomExceptionConfigArg extends ExceptionConfig {
1030         CustomExceptionConfigArg(String type) {
1031             super();
1032             setType(type);
1033         }
1034     }
1035 
1036     /***
1037      * Used for testing custom ForwardConfig classes.
1038      */
1039     public static class CustomForwardConfig extends ForwardConfig {
1040         public boolean processExtendsCalled = false;
1041 
1042         public CustomForwardConfig() {
1043             super();
1044         }
1045 
1046         public CustomForwardConfig(String name, String path) {
1047             super(name, path, false);
1048         }
1049 
1050         /***
1051          * Set a flag so we know this method was called.
1052          */
1053         public void processExtends(ModuleConfig moduleConfig,
1054             ActionConfig actionConfig)
1055             throws ClassNotFoundException, IllegalAccessException,
1056                 InstantiationException {
1057             processExtendsCalled = true;
1058         }
1059     }
1060 
1061     /***
1062      * Used to test cases where the subclass cannot be created with a no-arg
1063      * constructor.
1064      */
1065     private class CustomForwardConfigArg extends ForwardConfig {
1066         CustomForwardConfigArg(String name, String path) {
1067             super();
1068             setName(name);
1069             setPath(path);
1070         }
1071     }
1072 
1073     /***
1074      * Used for testing custom ActionConfig classes.
1075      */
1076     public static class CustomActionConfig extends ActionConfig {
1077         public boolean processExtendsCalled = false;
1078 
1079         public CustomActionConfig() {
1080             super();
1081         }
1082 
1083         public CustomActionConfig(String path) {
1084             super();
1085             setPath(path);
1086         }
1087 
1088         /***
1089          * Set a flag so we know this method was called.
1090          */
1091         public void processExtends(ModuleConfig moduleConfig)
1092             throws ClassNotFoundException, IllegalAccessException,
1093                 InstantiationException {
1094             processExtendsCalled = true;
1095         }
1096     }
1097 
1098     /***
1099      * Used to test cases where the subclass cannot be created with a no-arg
1100      * constructor.
1101      */
1102     private class CustomActionConfigArg extends ActionConfig {
1103         CustomActionConfigArg(String path) {
1104             super();
1105             setPath(path);
1106         }
1107     }
1108 
1109     // [...]
1110 }