001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.chain.config;
018
019import static org.junit.jupiter.api.Assertions.assertEquals;
020import static org.junit.jupiter.api.Assertions.assertFalse;
021import static org.junit.jupiter.api.Assertions.assertInstanceOf;
022import static org.junit.jupiter.api.Assertions.assertNotNull;
023import static org.junit.jupiter.api.Assertions.assertNull;
024import static org.junit.jupiter.api.Assertions.assertTrue;
025
026import java.util.Iterator;
027
028import org.apache.commons.chain.Catalog;
029import org.apache.commons.chain.CatalogFactory;
030import org.apache.commons.chain.Command;
031import org.apache.commons.chain.Context;
032import org.apache.commons.chain.impl.AddingCommand;
033import org.apache.commons.chain.impl.CatalogBase;
034import org.apache.commons.chain.impl.ChainBase;
035import org.apache.commons.chain.impl.ContextBase;
036import org.apache.commons.chain.impl.DelegatingCommand;
037import org.apache.commons.chain.impl.DelegatingFilter;
038import org.apache.commons.chain.impl.ExceptionCommand;
039import org.apache.commons.chain.impl.ExceptionFilter;
040import org.apache.commons.chain.impl.NonDelegatingCommand;
041import org.apache.commons.chain.impl.NonDelegatingFilter;
042import org.apache.commons.digester.Digester;
043import org.junit.jupiter.api.AfterEach;
044import org.junit.jupiter.api.BeforeEach;
045import org.junit.jupiter.api.Test;
046
047/**
048 * Test case identical to {@link ConfigParserTestCase} except
049 * that it uses the {@code define} rule to define aliases
050 * for the commands and chains used in the test.
051 */
052public class ConfigParser2TestCase {
053    private static final String DEFAULT_XML =
054        "/org/apache/commons/chain/config/test-config-2.xml";
055
056    // ------------------------------------------------------ Instance Variables
057
058    /**
059     * The {@code Catalog} to contain our configured commands.
060     */
061    protected Catalog<Context> catalog = null;
062
063    /**
064     * The {@code Context} to use for execution tests.
065     */
066    protected Context context = null;
067
068    /**
069     * The {@code ConfigParser} instance under test.
070     */
071    protected ConfigParser parser = null;
072
073    // ------------------------------------------------------------ Constructors
074
075    /**
076     * The Default-Constructor for this class.
077     */
078    public ConfigParser2TestCase() {
079    }
080
081    // ---------------------------------------------------- Overall Test Methods
082
083    /**
084     * Set up instance variables required by this test case.
085     */
086    @BeforeEach
087    public void init() {
088        catalog = new CatalogBase<>();
089        context = new ContextBase();
090        parser = new ConfigParser();
091    }
092
093    /**
094     * Tear down instance variables required by this test case.
095     */
096    @AfterEach
097    public void tearDown() {
098        parser = null;
099        context = null;
100        catalog = null;
101    }
102
103    // ------------------------------------------------ Individual Test Methods
104
105    /**
106     * Load the default test-config.xml file and examine the results
107     *
108     * @throws Exception any error
109     */
110    @Test
111    public void testDefaut() throws Exception {
112        // Check overall command count
113        load(DEFAULT_XML);
114        checkCommandCount(17);
115
116        // Check individual single command instances
117        Command<Context> command = null;
118
119        command = catalog.getCommand("AddingCommand");
120        assertNotNull(command);
121        assertInstanceOf(AddingCommand.class, command);
122
123        command = catalog.getCommand("DelegatingCommand");
124        assertNotNull(command);
125        assertInstanceOf(DelegatingCommand.class, command);
126
127        command = catalog.getCommand("DelegatingFilter");
128        assertNotNull(command);
129        assertInstanceOf(DelegatingFilter.class, command);
130
131        command = catalog.getCommand("ExceptionCommand");
132        assertNotNull(command);
133        assertInstanceOf(ExceptionCommand.class, command);
134
135        command = catalog.getCommand("ExceptionFilter");
136        assertNotNull(command);
137        assertInstanceOf(ExceptionFilter.class, command);
138
139        command = catalog.getCommand("NonDelegatingCommand");
140        assertNotNull(command);
141        assertInstanceOf(NonDelegatingCommand.class, command);
142
143        command = catalog.getCommand("NonDelegatingFilter");
144        assertNotNull(command);
145        assertInstanceOf(NonDelegatingFilter.class, command);
146
147        command = catalog.getCommand("ChainBase");
148        assertNotNull(command);
149        assertInstanceOf(ChainBase.class, command);
150        assertInstanceOf(TestChain.class, command);
151
152        // Check configurable properties instance
153        TestCommand tcommand = (TestCommand) catalog.getCommand("Configurable");
154        assertNotNull(tcommand);
155        assertEquals(tcommand.getFoo(), "Foo Value");
156        assertEquals(tcommand.getBar(), "Bar Value");
157    }
158
159    /**
160     * Test execution of chain "Execute2a"
161     *
162     * @throws Exception any error
163     */
164    @Test
165    public void testExecute2a() throws Exception {
166        load(DEFAULT_XML);
167        assertTrue(catalog.getCommand("Execute2a").execute(context),
168                   "Chain returned true");
169        checkExecuteLog("1/2/3");
170    }
171
172    /**
173     * Test execution of chain "Execute2b"
174     *
175     * @throws Exception any error
176     */
177    @Test
178    public void testExecute2b() throws Exception {
179        load(DEFAULT_XML);
180        assertFalse(catalog.getCommand("Execute2b").execute(context),
181                    "Chain returned false");
182        checkExecuteLog("1/2/3");
183    }
184
185    /**
186     * Test execution of chain "Execute2c"
187     *
188     * @throws Exception any error
189     */
190    @Test
191    public void testExecute2c() throws Exception {
192        load(DEFAULT_XML);
193        try {
194            catalog.getCommand("Execute2c").execute(context);
195        } catch (ArithmeticException e) {
196            assertEquals("3", e.getMessage(),
197                         "Correct exception id");
198        }
199        checkExecuteLog("1/2/3");
200    }
201
202    /**
203     * Test execution of chain "Execute2d"
204     *
205     * @throws Exception any error
206     */
207    @Test
208    public void testExecute2d() throws Exception {
209        load(DEFAULT_XML);
210        try {
211            catalog.getCommand("Execute2d").execute(context);
212        } catch (ArithmeticException e) {
213            assertEquals("2", e.getMessage(),
214                         "Correct exception id");
215        }
216        checkExecuteLog("1/2");
217    }
218
219    /**
220     * Test execution of chain "Execute4a"
221     *
222     * @throws Exception any error
223     */
224    @Test
225    public void testExecute4a() throws Exception {
226        load(DEFAULT_XML);
227        assertTrue(catalog.getCommand("Execute4a").execute(context),
228                   "Chain returned true");
229        checkExecuteLog("1/2/3/c/a");
230    }
231
232    /**
233     * Test execution of chain "Execute2b"
234     *
235     * @throws Exception any error
236     */
237    @Test
238    public void testExecute4b() throws Exception {
239        load(DEFAULT_XML);
240        assertFalse(catalog.getCommand("Execute4b").execute(context),
241                    "Chain returned false");
242        checkExecuteLog("1/2/3/b");
243    }
244
245    /**
246     * Test execution of chain "Execute4c"
247     *
248     * @throws Exception any error
249     */
250    @Test
251    public void testExecute4c() throws Exception {
252        load(DEFAULT_XML);
253        try {
254            catalog.getCommand("Execute4c").execute(context);
255        } catch (ArithmeticException e) {
256            assertEquals("3", e.getMessage(),
257                         "Correct exception id");
258        }
259        checkExecuteLog("1/2/3/c/b/a");
260    }
261
262    /**
263     * Test execution of chain "Execute4d"
264     *
265     * @throws Exception any error
266     */
267    @Test
268    public void testExecute4d() throws Exception {
269        load(DEFAULT_XML);
270        try {
271            catalog.getCommand("Execute4d").execute(context);
272        } catch (ArithmeticException e) {
273            assertEquals("2", e.getMessage(),
274                         "Correct exception id");
275        }
276        checkExecuteLog("1/2/b/a");
277    }
278
279    /**
280     * Test a pristine ConfigParser instance
281     */
282    @Test
283    public void testPristine() {
284        // Validate the "digester" property
285        Digester digester = parser.getDigester();
286        assertNotNull(digester, "Returned a Digester instance");
287        assertFalse(digester.getNamespaceAware(),
288                    "Default namespaceAware");
289        assertTrue(digester.getUseContextClassLoader(),
290                   "Default useContextClassLoader");
291        assertFalse(digester.getValidating(),
292                   "Default validating");
293
294        // Validate the "ruleSet" property
295        ConfigRuleSet ruleSet = (ConfigRuleSet) parser.getRuleSet();
296        assertNotNull(ruleSet, "Returned a RuleSet instance");
297        assertEquals("chain", ruleSet.getChainElement(),
298                     "Default chainElement");
299        assertEquals("className", ruleSet.getClassAttribute(),
300                     "Default classAttribute");
301        assertEquals("command", ruleSet.getCommandElement(),
302                     "Default commandElement");
303        assertEquals("name", ruleSet.getNameAttribute(),
304                     "Default nameAttribute");
305        assertNull(ruleSet.getNamespaceURI(),
306                   "Default namespaceURI");
307
308        // Validate the "useContextClassLoader" property
309        assertTrue(parser.getUseContextClassLoader(),
310                   "Defaults to use context class loader");
311
312        // Ensure that there are no preconfigured commands in the catalog
313        checkCommandCount(0);
314    }
315
316    // --------------------------------------------------------- Private Methods
317
318    /**
319     * Verify the number of configured commands
320     *
321     * @param expected the expected value
322     */
323    protected void checkCommandCount(int expected) {
324        int n = 0;
325        Iterator<String> names = catalog.getNames();
326        while (names.hasNext()) {
327            String name = names.next();
328            n++;
329            assertNotNull(catalog.getCommand(name), name + " exists");
330        }
331        assertEquals(expected, n, "Correct command count");
332    }
333
334    /**
335     * Verify the contents of the execution log
336     *
337     * @param expected the expected value
338     */
339    protected void checkExecuteLog(String expected) {
340        StringBuffer log = (StringBuffer) context.get("log");
341        assertNotNull(log, "Context returned log");
342        assertEquals(expected, log.toString(),
343                     "Context returned correct log");
344    }
345
346    /**
347     * Load the specified catalog from the specified resource path
348     *
349     * @param path resource path to load specified catalog
350     *
351     * @throws Exception any error
352     */
353    protected void load(String path) throws Exception {
354        CatalogFactory.clear();
355        parser.parse(this.getClass().getResource(path));
356        catalog = CatalogFactory.getInstance().getCatalog("foo");
357    }
358}