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 for {@code org.apache.commons.chain.config.ConfigParser}.
049 */
050public class ConfigParserTestCase {
051    private static final String DEFAULT_XML =
052        "/org/apache/commons/chain/config/test-config.xml";
053
054    // ------------------------------------------------------ Instance Variables
055
056    /**
057     * The {@code Catalog} to contain our configured commands.
058     */
059    protected Catalog<Context> catalog = null;
060
061    /**
062     * The {@code Context} to use for execution tests.
063     */
064    protected Context context = null;
065
066    /**
067     * The {@code ConfigParser} instance under test.
068     */
069    protected ConfigParser parser = null;
070
071    // ------------------------------------------------------------ Constructors
072
073    /**
074     * The Default-Constructor for this class.
075     */
076    public ConfigParserTestCase() {
077    }
078
079    // ---------------------------------------------------- Overall Test Methods
080
081    /**
082     * Set up instance variables required by this test case.
083     */
084    @BeforeEach
085    public void init() {
086        catalog = new CatalogBase<>();
087        context = new ContextBase();
088        parser = new ConfigParser();
089    }
090
091    /**
092     * Tear down instance variables required by this test case.
093     */
094    @AfterEach
095    public void tearDown() {
096        parser = null;
097        context = null;
098        catalog = null;
099    }
100
101    // ------------------------------------------------ Individual Test Methods
102
103    /**
104     *  Load the default test-config.xml file and examine the results
105     *
106     * @throws Exception any error
107     */
108    @Test
109    public void testDefaut() throws Exception {
110        // Check overall command count
111        load(DEFAULT_XML);
112        checkCommandCount(17);
113
114        // Check individual single command instances
115        Command<Context> command = null;
116
117        command = catalog.getCommand("AddingCommand");
118        assertNotNull(command);
119        assertInstanceOf(AddingCommand.class, command);
120
121        command = catalog.getCommand("DelegatingCommand");
122        assertNotNull(command);
123        assertInstanceOf(DelegatingCommand.class, command);
124
125        command = catalog.getCommand("DelegatingFilter");
126        assertNotNull(command);
127        assertInstanceOf(DelegatingFilter.class, command);
128
129        command = catalog.getCommand("ExceptionCommand");
130        assertNotNull(command);
131        assertInstanceOf(ExceptionCommand.class, command);
132
133        command = catalog.getCommand("ExceptionFilter");
134        assertNotNull(command);
135        assertInstanceOf(ExceptionFilter.class, command);
136
137        command = catalog.getCommand("NonDelegatingCommand");
138        assertNotNull(command);
139        assertInstanceOf(NonDelegatingCommand.class, command);
140
141        command = catalog.getCommand("NonDelegatingFilter");
142        assertNotNull(command);
143        assertInstanceOf(NonDelegatingFilter.class, command);
144
145        command = catalog.getCommand("ChainBase");
146        assertNotNull(command);
147        assertInstanceOf(ChainBase.class, command);
148        assertInstanceOf(TestChain.class, command);
149
150        // Check configurable properties instance
151        TestCommand tcommand = (TestCommand) catalog.getCommand("Configurable");
152        assertNotNull(tcommand);
153        assertEquals(tcommand.getFoo(), "Foo Value");
154        assertEquals(tcommand.getBar(), "Bar Value");
155    }
156
157    /**
158     * Test execution of chain "Execute2a"
159     *
160     * @throws Exception any error
161     */
162    @Test
163    public void testExecute2a() throws Exception {
164        load(DEFAULT_XML);
165        assertTrue(catalog.getCommand("Execute2a").execute(context),
166                   "Chain returned true");
167        checkExecuteLog("1/2/3");
168    }
169
170    /**
171     * Test execution of chain "Execute2b"
172     *
173     * @throws Exception any error
174     */
175    @Test
176    public void testExecute2b() throws Exception {
177        load(DEFAULT_XML);
178        assertFalse(catalog.getCommand("Execute2b").execute(context),
179                    "Chain returned false");
180        checkExecuteLog("1/2/3");
181    }
182
183    /**
184     * Test execution of chain "Execute2c"
185     *
186     * @throws Exception any error
187     */
188    @Test
189    public void testExecute2c() throws Exception {
190        load(DEFAULT_XML);
191        try {
192            catalog.getCommand("Execute2c").execute(context);
193        } catch (ArithmeticException e) {
194            assertEquals("3", e.getMessage(),
195                         "Correct exception id");
196        }
197        checkExecuteLog("1/2/3");
198    }
199
200    /**
201     * Test execution of chain "Execute2d"
202     *
203     * @throws Exception any error
204     */
205    @Test
206    public void testExecute2d() throws Exception {
207        load(DEFAULT_XML);
208        try {
209            catalog.getCommand("Execute2d").execute(context);
210        } catch (ArithmeticException e) {
211            assertEquals("2", e.getMessage(),
212                         "Correct exception id");
213        }
214        checkExecuteLog("1/2");
215    }
216
217    /**
218     * Test execution of chain "Execute4a"
219     *
220     * @throws Exception any error
221     */
222    @Test
223    public void testExecute4a() throws Exception {
224        load(DEFAULT_XML);
225        assertTrue(catalog.getCommand("Execute4a").execute(context),
226                   "Chain returned true");
227        checkExecuteLog("1/2/3/c/a");
228    }
229
230    /**
231     * Test execution of chain "Execute2b"
232     *
233     * @throws Exception any error
234     */
235    @Test
236    public void testExecute4b() throws Exception {
237        load(DEFAULT_XML);
238        assertFalse(catalog.getCommand("Execute4b").execute(context),
239                    "Chain returned false");
240        checkExecuteLog("1/2/3/b");
241    }
242
243    /**
244     * Test execution of chain "Execute4c"
245     *
246     * @throws Exception any error
247     */
248    @Test
249    public void testExecute4c() throws Exception {
250        load(DEFAULT_XML);
251        try {
252            catalog.getCommand("Execute4c").execute(context);
253        } catch (ArithmeticException e) {
254            assertEquals("3", e.getMessage(),
255                         "Correct exception id");
256        }
257        checkExecuteLog("1/2/3/c/b/a");
258    }
259
260    /**
261     * Test execution of chain "Execute4d"
262     *
263     * @throws Exception any error
264     */
265    @Test
266    public void testExecute4d() throws Exception {
267        load(DEFAULT_XML);
268        try {
269            catalog.getCommand("Execute4d").execute(context);
270        } catch (ArithmeticException e) {
271            assertEquals("2", e.getMessage(),
272                         "Correct exception id");
273        }
274        checkExecuteLog("1/2/b/a");
275    }
276
277    /**
278     * Test a pristine ConfigParser instance
279     */
280    @Test
281    public void testPristine() {
282        // Validate the "digester" property
283        Digester digester = parser.getDigester();
284        assertNotNull(digester, "Returned a Digester instance");
285        assertFalse(digester.getNamespaceAware(),
286                    "Default namespaceAware");
287        assertTrue(digester.getUseContextClassLoader(),
288                   "Default useContextClassLoader");
289        assertFalse(digester.getValidating(),
290                    "Default validating");
291
292        // Validate the "ruleSet" property
293        ConfigRuleSet ruleSet = (ConfigRuleSet) parser.getRuleSet();
294        assertNotNull(ruleSet, "Returned a RuleSet instance");
295        assertEquals("chain", ruleSet.getChainElement(),
296                     "Default chainElement");
297        assertEquals("className", ruleSet.getClassAttribute(),
298                     "Default classAttribute");
299        assertEquals("command", ruleSet.getCommandElement(),
300                     "Default commandElement");
301        assertEquals("name", ruleSet.getNameAttribute(),
302                     "Default nameAttribute");
303        assertNull(ruleSet.getNamespaceURI(),
304                   "Default namespaceURI");
305
306        // Validate the "useContextClassLoader" property
307        assertTrue(parser.getUseContextClassLoader(),
308                   "Defaults to use context class loader");
309
310        // Ensure that there are no preconfigured commands in the catalog
311        checkCommandCount(0);
312    }
313
314    // --------------------------------------------------------- Private Methods
315
316    /**
317     * Verify the number of configured commands
318     *
319     * @param expected the expected value
320     */
321    protected void checkCommandCount(int expected) {
322        int n = 0;
323        Iterator<String> names = catalog.getNames();
324        while (names.hasNext()) {
325            String name = names.next();
326            n++;
327            assertNotNull(catalog.getCommand(name), name + " exists");
328        }
329        assertEquals(expected, n, "Correct command count");
330    }
331
332    /**
333     * Verify the contents of the execution log
334     *
335     * @param expected the expected value
336     */
337    protected void checkExecuteLog(String expected) {
338        StringBuffer log = (StringBuffer) context.get("log");
339        assertNotNull(log, "Context returned log");
340        assertEquals(expected, log.toString(),
341                     "Context returned correct log");
342    }
343
344    /**
345     * Load the specified catalog from the specified resource path
346     *
347     * @param path resource path to load specified catalog
348     *
349     * @throws Exception any error
350     */
351    protected void load(String path) throws Exception {
352        CatalogFactory.clear();
353        parser.parse(this.getClass().getResource(path));
354        catalog = CatalogFactory.getInstance().getCatalog();
355    }
356}