1/*
2 * Copyright 2007 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.mockftpserver.core.command;
17
18import org.apache.log4j.Logger;
19import org.easymock.MockControl;
20import org.mockftpserver.core.session.Session;
21import org.mockftpserver.test.AbstractTestCase;
22
23import java.text.MessageFormat;
24import java.util.ListResourceBundle;
25import java.util.ResourceBundle;
26
27/**
28 * Abstract superclass for CommandHandler tests
29 *
30 * @author Chris Mair
31 * @version $Revision$ - $Date$
32 */
33public abstract class AbstractCommandHandlerTestCase extends AbstractTestCase {
34
35    private static final Logger LOG = Logger.getLogger(AbstractCommandHandlerTestCase.class);
36
37    // Some common test constants
38    protected static final String DIR1 = "dir1";
39    protected static final String DIR2 = "dir2";
40    protected static final String FILENAME1 = "sample1.txt";
41    protected static final String FILENAME2 = "sample2.txt";
42
43    protected Session session;
44    protected ResourceBundle replyTextBundle;
45
46    /**
47     * Test the handleCommand() method, when one or more parameter is missing or invalid
48     *
49     * @param commandHandler - the CommandHandler to test
50     * @param commandName    - the name for the Command
51     * @param parameters     - the Command parameters
52     */
53    protected void testHandleCommand_InvalidParameters(AbstractTrackingCommandHandler commandHandler,
54                                                       String commandName, String[] parameters) throws Exception {
55        Command command = new Command(commandName, parameters);
56        session.sendReply(ReplyCodes.COMMAND_SYNTAX_ERROR, replyTextFor(ReplyCodes.COMMAND_SYNTAX_ERROR));
57        replay(session);
58
59        commandHandler.handleCommand(command, session);
60        verify(session);
61
62        verifyNumberOfInvocations(commandHandler, 1);
63        verifyNoDataElements(commandHandler.getInvocation(0));
64    }
65
66    /**
67     * Verify that the CommandHandler contains the specified number of invocation records
68     *
69     * @param commandHandler - the CommandHandler
70     * @param expected       - the expected number of invocations
71     */
72    protected void verifyNumberOfInvocations(InvocationHistory commandHandler, int expected) {
73        assertEquals("number of invocations", expected, commandHandler.numberOfInvocations());
74    }
75
76    /**
77     * Verify that the InvocationRecord contains no data elements
78     *
79     * @param invocationRecord - the InvocationRecord
80     */
81    protected void verifyNoDataElements(InvocationRecord invocationRecord) {
82        LOG.info("Verifying: " + invocationRecord);
83        assertEquals("number of data elements", 0, invocationRecord.keySet().size());
84    }
85
86    /**
87     * Verify that the InvocationRecord contains exactly one data element, with the specified key
88     * and value.
89     *
90     * @param invocationRecord - the InvocationRecord
91     * @param key              - the expected key
92     * @param value            - the expected value
93     */
94    protected void verifyOneDataElement(InvocationRecord invocationRecord, String key, Object value) {
95        LOG.info("Verifying: " + invocationRecord);
96        assertEquals("number of data elements", 1, invocationRecord.keySet().size());
97        assertEqualsAllTypes("value:" + value, value, invocationRecord.getObject(key));
98    }
99
100    /**
101     * Verify that the InvocationRecord contains exactly two data element, with the specified keys
102     * and values.
103     *
104     * @param invocationRecord - the InvocationRecord
105     * @param key1             - the expected key1
106     * @param value1           - the expected value1
107     * @param key2             - the expected key2
108     * @param value2-          the expected value2
109     */
110    protected void verifyTwoDataElements(InvocationRecord invocationRecord, String key1, Object value1,
111                                         String key2, Object value2) {
112
113        LOG.info("Verifying: " + invocationRecord);
114        assertEquals("number of data elements", 2, invocationRecord.keySet().size());
115        assertEqualsAllTypes("value1:" + value1, value1, invocationRecord.getObject(key1));
116        assertEqualsAllTypes("value2:" + value2, value2, invocationRecord.getObject(key2));
117    }
118
119    /**
120     * Assert that the actual is equal to the expected, using arrays equality comparison if
121     * necessary
122     *
123     * @param message  - the message, used if the comparison fails
124     * @param expected - the expected value
125     * @param actual   - the actual value
126     */
127    private void assertEqualsAllTypes(String message, Object expected, Object actual) {
128
129        if (expected instanceof byte[] || actual instanceof byte[]) {
130            assertEquals(message, (byte[]) expected, (byte[]) actual);
131        } else if (expected instanceof Object[] || actual instanceof Object[]) {
132            assertEquals(message, (Object[]) expected, (Object[]) actual);
133        } else {
134            assertEquals(message, expected, actual);
135        }
136    }
137
138    /**
139     * Perform setup before each test
140     *
141     * @see org.mockftpserver.test.AbstractTestCase#setUp()
142     */
143    protected void setUp() throws Exception {
144        super.setUp();
145
146        session = (Session) createMock(Session.class);
147        control(session).setDefaultMatcher(MockControl.ARRAY_MATCHER);
148        control(session).expectAndDefaultReturn(session.getClientHost(), DEFAULT_HOST);
149
150        replyTextBundle = new ListResourceBundle() {
151            protected Object[][] getContents() {
152                return new Object[][]{
153                        {"150", replyTextFor(150)},
154                        {"200", replyTextFor(200)},
155                        {"211", replyTextWithParameterFor(211)},
156                        {"213", replyTextWithParameterFor(213)},
157                        {"214", replyTextWithParameterFor(214)},
158                        {"215", replyTextWithParameterFor(215)},
159                        {"220", replyTextFor(220)},
160                        {"221", replyTextFor(221)},
161                        {"226", replyTextFor(226)},
162                        {"226.WithFilename", replyTextWithParameterFor("226.WithFilename")},
163                        {"227", replyTextWithParameterFor(227)},
164                        {"229", replyTextWithParameterFor(229)},
165                        {"230", replyTextFor(230)},
166                        {"250", replyTextFor(250)},
167                        {"257", replyTextWithParameterFor(257)},
168                        {"331", replyTextFor(331)},
169                        {"350", replyTextFor(350)},
170                        {"501", replyTextFor(501)},
171                        {"502", replyTextFor(502)},
172                };
173            }
174        };
175    }
176
177    /**
178     * Return the test-specific reply text for the specified reply code
179     *
180     * @param replyCode - the reply code
181     * @return the reply text for the specified reply code
182     */
183    protected String replyTextFor(int replyCode) {
184        return "Reply for " + replyCode;
185    }
186
187    /**
188     * Return the test-specific parameterized reply text for the specified reply code
189     *
190     * @param replyCode - the reply code
191     * @return the reply text for the specified reply code
192     */
193    protected String replyTextWithParameterFor(int replyCode) {
194        return "Reply for " + replyCode + ":{0}";
195    }
196
197    /**
198     * Return the test-specific parameterized reply text for the specified messageKey
199     *
200     * @param messageKey - the messageKey
201     * @return the reply text for the specified messageKey
202     */
203    protected String replyTextWithParameterFor(String messageKey) {
204        return "Reply for " + messageKey + ":{0}";
205    }
206
207    /**
208     * Return the test-specific reply text for the specified reply code and message parameter
209     *
210     * @param replyCode - the reply code
211     * @param parameter - the message parameter value
212     * @return the reply text for the specified reply code
213     */
214    protected String formattedReplyTextFor(int replyCode, Object parameter) {
215        return MessageFormat.format(replyTextWithParameterFor(replyCode), objArray(parameter));
216    }
217
218    /**
219     * Return the test-specific reply text for the specified message key and message parameter
220     *
221     * @param messageKey - the messageKey
222     * @param parameter  - the message parameter value
223     * @return the reply text for the specified message key and parameter
224     */
225    protected String formattedReplyTextFor(String messageKey, Object parameter) {
226        return MessageFormat.format(replyTextWithParameterFor(messageKey), objArray(parameter));
227    }
228
229}
230