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.AbstractTest;
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 AbstractCommandHandlerTest extends AbstractTest {
34
35    private static final Logger LOG = Logger.getLogger(AbstractCommandHandlerTest.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.AbstractTest#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                        {"230", replyTextFor(230)},
165                        {"250", replyTextFor(250)},
166                        {"257", replyTextWithParameterFor(257)},
167                        {"331", replyTextFor(331)},
168                        {"350", replyTextFor(350)},
169                        {"501", replyTextFor(501)},
170                        {"502", replyTextFor(502)},
171                };
172            }
173        };
174    }
175
176    /**
177     * Return the test-specific reply text for the specified reply code
178     *
179     * @param replyCode - the reply code
180     * @return the reply text for the specified reply code
181     */
182    protected String replyTextFor(int replyCode) {
183        return "Reply for " + replyCode;
184    }
185
186    /**
187     * Return the test-specific parameterized reply text for the specified reply code
188     *
189     * @param replyCode - the reply code
190     * @return the reply text for the specified reply code
191     */
192    protected String replyTextWithParameterFor(int replyCode) {
193        return "Reply for " + replyCode + ":{0}";
194    }
195
196    /**
197     * Return the test-specific parameterized reply text for the specified messageKey
198     *
199     * @param messageKey - the messageKey
200     * @return the reply text for the specified messageKey
201     */
202    protected String replyTextWithParameterFor(String messageKey) {
203        return "Reply for " + messageKey + ":{0}";
204    }
205
206    /**
207     * Return the test-specific reply text for the specified reply code and message parameter
208     *
209     * @param replyCode - the reply code
210     * @param parameter - the message parameter value
211     * @return the reply text for the specified reply code
212     */
213    protected String formattedReplyTextFor(int replyCode, Object parameter) {
214        return MessageFormat.format(replyTextWithParameterFor(replyCode), objArray(parameter));
215    }
216
217    /**
218     * Return the test-specific reply text for the specified message key and message parameter
219     *
220     * @param messageKey - the messageKey
221     * @param parameter  - the message parameter value
222     * @return the reply text for the specified message key and parameter
223     */
224    protected String formattedReplyTextFor(String messageKey, Object parameter) {
225        return MessageFormat.format(replyTextWithParameterFor(messageKey), objArray(parameter));
226    }
227
228}
229