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.stub.command;
17
18import java.text.MessageFormat;
19import java.util.ListResourceBundle;
20import java.util.ResourceBundle;
21
22import org.apache.log4j.Logger;
23import org.easymock.MockControl;
24import org.mockftpserver.core.command.AbstractCommandHandler;
25import org.mockftpserver.core.command.Command;
26import org.mockftpserver.core.command.InvocationHistory;
27import org.mockftpserver.core.command.InvocationRecord;
28import org.mockftpserver.core.session.Session;
29import org.mockftpserver.core.util.AssertFailedException;
30import org.mockftpserver.test.AbstractTest;
31
32/**
33 * Abstract superclass for CommandHandler tests
34 *
35 * @version $Revision$ - $Date$
36 *
37 * @author Chris Mair
38 */
39public abstract class AbstractCommandHandlerTest extends AbstractTest {
40
41    private static final Logger LOG = Logger.getLogger(AbstractCommandHandlerTest.class);
42
43    // Some common test constants
44    protected static final String DIR1 = "dir1";
45    protected static final String DIR2 = "dir2";
46    protected static final String FILENAME1 = "sample1.txt";
47    protected static final String FILENAME2 = "sample2.txt";
48
49    protected Session session;
50    protected ResourceBundle replyTextBundle;
51
52    /**
53     * Test the handleCommand() method, when one or more parameter is missing or invalid
54     *
55     * @param commandHandler - the CommandHandler to test
56     * @param commandName - the name for the Command
57     * @param parameters - the Command parameters
58     */
59    protected void testHandleCommand_InvalidParameters(AbstractCommandHandler commandHandler,
60            String commandName, String[] parameters) throws Exception {
61
62        try {
63            commandHandler.handleCommand(new Command(commandName, parameters), session);
64            fail("Expected AssertFailedException");
65        }
66        catch (AssertFailedException expected) {
67            LOG.info("Expected: " + expected);
68            assertTrue("Error message must contain [" + commandName + "]", expected.getMessage().indexOf(
69                    commandName) != -1);
70        }
71        verifyNumberOfInvocations(commandHandler, 1);
72    }
73
74    /**
75     * Verify that the CommandHandler contains the specified number of invocation records
76     *
77     * @param commandHandler - the CommandHandler
78     * @param expected - the expected number of invocations
79     */
80    protected void verifyNumberOfInvocations(InvocationHistory commandHandler, int expected) {
81        assertEquals("number of invocations", expected, commandHandler.numberOfInvocations());
82    }
83
84    /**
85     * Verify that the InvocationRecord contains no data elements
86     *
87     * @param invocationRecord - the InvocationRecord
88     */
89    protected void verifyNoDataElements(InvocationRecord invocationRecord) {
90        LOG.info("Verifying: " + invocationRecord);
91        assertEquals("number of data elements", 0, invocationRecord.keySet().size());
92    }
93
94    /**
95     * Verify that the InvocationRecord contains exactly one data element, with the specified key
96     * and value.
97     *
98     * @param invocationRecord - the InvocationRecord
99     * @param key - the expected key
100     * @param value - the expected value
101     */
102    protected void verifyOneDataElement(InvocationRecord invocationRecord, String key, Object value) {
103        LOG.info("Verifying: " + invocationRecord);
104        assertEquals("number of data elements", 1, invocationRecord.keySet().size());
105        assertEqualsAllTypes("value:" + value, value, invocationRecord.getObject(key));
106    }
107
108    /**
109     * Verify that the InvocationRecord contains exactly two data element, with the specified keys
110     * and values.
111     *
112     * @param invocationRecord - the InvocationRecord
113     * @param key1 - the expected key1
114     * @param value1 - the expected value1
115     * @param key2 - the expected key2
116     * @param value12- the expected value2
117     */
118    protected void verifyTwoDataElements(InvocationRecord invocationRecord, String key1, Object value1,
119            String key2, Object value2) {
120
121        LOG.info("Verifying: " + invocationRecord);
122        assertEquals("number of data elements", 2, invocationRecord.keySet().size());
123        assertEqualsAllTypes("value1:" + value1, value1, invocationRecord.getObject(key1));
124        assertEqualsAllTypes("value2:" + value2, value2, invocationRecord.getObject(key2));
125    }
126
127    /**
128     * Assert that the actual is equal to the expected, using arrays equality comparison if
129     * necessary
130     *
131     * @param message - the message, used if the comparison fails
132     * @param expected - the expected value
133     * @param actual - the actual value
134     */
135    private void assertEqualsAllTypes(String message, Object expected, Object actual) {
136
137        if (expected instanceof byte[] || actual instanceof byte[]) {
138            assertEquals(message, (byte[]) expected, (byte[]) actual);
139        }
140        else if (expected instanceof Object[] || actual instanceof Object[]) {
141            assertEquals(message, (Object[]) expected, (Object[]) actual);
142        }
143        else {
144            assertEquals(message, expected, actual);
145        }
146    }
147
148    /**
149     * Perform setup before each test
150     *
151     * @see org.mockftpserver.test.AbstractTest#setUp()
152     */
153    protected void setUp() throws Exception {
154        super.setUp();
155
156        session = (Session) createMock(Session.class);
157        control(session).setDefaultMatcher(MockControl.ARRAY_MATCHER);
158        control(session).expectAndDefaultReturn(session.getClientHost(), DEFAULT_HOST);
159
160        replyTextBundle = new ListResourceBundle() {
161            protected Object[][] getContents() {
162                return new Object[][] {
163                        { "150", replyTextFor(150) },
164                        { "200", replyTextFor(200) },
165                        { "211", replyTextWithParameterFor(211) },
166                        { "213", replyTextWithParameterFor(213) },
167                        { "214", replyTextWithParameterFor(214) },
168                        { "215", replyTextWithParameterFor(215) },
169                        { "220", replyTextFor(220) },
170                        { "221", replyTextFor(221) },
171                        { "226", replyTextFor(226) },
172                        { "226.WithFilename", replyTextWithParameterFor("226.WithFilename") },
173                        { "227", replyTextWithParameterFor(227) },
174                        { "230", replyTextFor(230) },
175                        { "250", replyTextFor(250) },
176                        { "257", replyTextWithParameterFor(257) },
177                        { "331", replyTextFor(331) },
178                        { "350", replyTextFor(350) },
179                };
180            }
181        };
182    }
183
184    /**
185     * Return the test-specific reply text for the specified reply code
186     * @param replyCode - the reply code
187     * @return the reply text for the specified reply code
188     */
189    protected String replyTextFor(int replyCode) {
190        return "Reply for " + replyCode;
191    }
192
193    /**
194     * Return the test-specific parameterized reply text for the specified reply code
195     * @param replyCode - the reply code
196     * @return the reply text for the specified reply code
197     */
198    protected String replyTextWithParameterFor(int replyCode) {
199        return "Reply for " + replyCode + ":{0}";
200    }
201
202    /**
203     * Return the test-specific parameterized reply text for the specified messageKey
204     * @param messageKey - the messageKey
205     * @return the reply text for the specified messageKey
206     */
207    protected String replyTextWithParameterFor(String messageKey) {
208        return "Reply for " + messageKey + ":{0}";
209    }
210
211    /**
212     * Return the test-specific reply text for the specified reply code and message parameter
213     * @param replyCode - the reply code
214     * @param parameter - the message parameter value
215     * @return the reply text for the specified reply code
216     */
217    protected String formattedReplyTextFor(int replyCode, Object parameter) {
218        return MessageFormat.format(replyTextWithParameterFor(replyCode), objArray(parameter));
219    }
220
221    /**
222     * Return the test-specific reply text for the specified message key and message parameter
223     * @param messageKey - the messageKey
224     * @param parameter - the message parameter value
225     * @return the reply text for the specified message key and parameter
226     */
227    protected String formattedReplyTextFor(String messageKey, Object parameter) {
228        return MessageFormat.format(replyTextWithParameterFor(messageKey), objArray(parameter));
229    }
230
231}
232