MediaRecorderStateUnitTestTemplate.java revision f013e1afd1e68af5e3b868c26a653bbfb39538f8
1/*
2 * Copyright (C) 2008 The Android Open Source Project
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 */
16
17package com.android.mediaframeworktest.unit;
18
19import android.util.Log;
20import android.media.MediaRecorder;
21import android.test.AndroidTestCase;
22
23/**
24 * A template class for running a method under test in all possible
25 * states of a MediaRecorder object.
26 *
27 * @see com.android.mediaframeworktest.unit.MediaRecorderStopStateUnitTest
28 * for an example of using this class.
29 *
30 * A typical concrete unit test class would implement the
31 * MediaRecorderMethodUnderTest interface and have a reference to an object of
32 * this class. Then it calls runTestOnMethod() to actually perform the unit
33 * tests. It is recommended that the toString() method of the concrete unit test
34 * class be overridden to use the actual method name under test for logging
35 * purpose.
36 *
37 */
38class MediaRecorderStateUnitTestTemplate extends AndroidTestCase {
39    public static final String RECORD_OUTPUT_PATH = "/sdcard/recording.3gp";
40    public static final int OUTPUT_FORMAT= MediaRecorder.OutputFormat.THREE_GPP;
41    public static final int AUDIO_ENCODER = MediaRecorder.AudioEncoder.AMR_NB;
42    public static final int AUDIO_SOURCE = MediaRecorder.AudioSource.MIC;
43    private static final String TAG = "MediaRecorderStateUnitTest";
44    private MediaRecorderStateErrors mStateErrors = new MediaRecorderStateErrors();
45    private MediaRecorder mMediaRecorder = new MediaRecorder();
46    private MediaRecorderStateErrors.MediaRecorderState mMediaRecorderState = null;
47    private MediaRecorderMethodUnderTest mMethodUnderTest = null;
48
49    /**
50     * Runs the given method under test in all possible states of a MediaRecorder
51     * object.
52     *
53     * @param testMethod the method under test.
54     */
55    public void runTestOnMethod(MediaRecorderMethodUnderTest testMethod) {
56        mMethodUnderTest = testMethod;
57        if (mMethodUnderTest != null) {  // Method under test has been set?
58            checkMethodUnderTestInAllPossibleStates();
59            mMethodUnderTest.checkStateErrors(mStateErrors);
60            cleanUp();
61        }
62    }
63
64    /*
65     * Calls method under test in the given state of the MediaRecorder object.
66     *
67     * @param state the MediaRecorder state in which the method under test is called.
68     */
69    private void callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState state) {
70        Log.v(TAG, "call " + mMethodUnderTest + ": started in state " + state);
71        setMediaRecorderToState(state);
72        try {
73            mMethodUnderTest.invokeMethodUnderTest(mMediaRecorder);
74        } catch(Exception e) {
75            setStateError(mMediaRecorderState, true);
76        }
77        Log.v(TAG, "call " + mMethodUnderTest + ": ended in state " + state);
78    }
79
80    /*
81     * The following setMediaRecorderToXXXStateXXX methods sets the MediaRecorder
82     * object to the corresponding state, given the assumption that reset()
83     * always resets the MediaRecorder object to Initial (after reset) state.
84     */
85    private void setMediaRecorderToInitialStateAfterReset() {
86        try {
87            mMediaRecorder.reset();
88        } catch(Exception e) {
89            fail("setMediaRecorderToInitialStateAfterReset: Exception " + e.getClass().getName() + " was thrown.");
90        }
91    }
92
93    private void setMediaRecorderToInitialStateAfterStop() {
94        try {
95            mMediaRecorder.reset();
96            mMediaRecorder.setAudioSource(AUDIO_SOURCE);
97            mMediaRecorder.setOutputFormat(OUTPUT_FORMAT);
98            mMediaRecorder.setAudioEncoder(AUDIO_ENCODER);
99            mMediaRecorder.setOutputFile(RECORD_OUTPUT_PATH);
100            mMediaRecorder.prepare();
101            mMediaRecorder.start();
102            mMediaRecorder.stop();
103        } catch(Exception e) {
104            fail("setMediaRecorderToInitialStateAfterReset: Exception " + e.getClass().getName() + " was thrown.");
105        }
106    }
107
108    private void setMediaRecorderToInitializedState() {
109        try {
110            mMediaRecorder.reset();
111            if (mMethodUnderTest.toString() != "setAudioSource()") {
112                mMediaRecorder.setAudioSource(AUDIO_SOURCE);
113            }
114        } catch(Exception e) {
115            fail("setMediaRecorderToInitializedState: Exception " + e.getClass().getName() + " was thrown.");
116        }
117    }
118
119    private void setMediaRecorderToPreparedState() {
120        try {
121            mMediaRecorder.reset();
122            mMediaRecorder.setAudioSource(AUDIO_SOURCE);
123            mMediaRecorder.setOutputFormat(OUTPUT_FORMAT);
124            mMediaRecorder.setAudioEncoder(AUDIO_ENCODER);
125            mMediaRecorder.setOutputFile(RECORD_OUTPUT_PATH);
126            mMediaRecorder.prepare();
127        } catch(Exception e) {
128            fail("setMediaRecorderToPreparedState: Exception " + e.getClass().getName() + " was thrown.");
129        }
130    }
131
132    private void setMediaRecorderToRecordingState() {
133        try {
134            mMediaRecorder.reset();
135            mMediaRecorder.setAudioSource(AUDIO_SOURCE);
136            mMediaRecorder.setOutputFormat(OUTPUT_FORMAT);
137            mMediaRecorder.setAudioEncoder(AUDIO_ENCODER);
138            mMediaRecorder.setOutputFile(RECORD_OUTPUT_PATH);
139            mMediaRecorder.prepare();
140            mMediaRecorder.start();
141        } catch(Exception e) {
142            fail("setMediaRecorderToRecordingState: Exception " + e.getClass().getName() + " was thrown.");
143        }
144    }
145
146    private void setMediaRecorderToDataSourceConfiguredState() {
147        try {
148            mMediaRecorder.reset();
149            mMediaRecorder.setAudioSource(AUDIO_SOURCE);
150            mMediaRecorder.setOutputFormat(OUTPUT_FORMAT);
151
152            /* Skip setAudioEncoder() and setOutputFile() calls if
153             * the method under test is setAudioEncoder() since this
154             * method can only be called once even in the DATASOURCECONFIGURED state
155             */
156            if (mMethodUnderTest.toString() != "setAudioEncoder()") {
157                mMediaRecorder.setAudioEncoder(AUDIO_ENCODER);
158            }
159
160            if (mMethodUnderTest.toString() != "setOutputFile()") {
161                mMediaRecorder.setOutputFile(RECORD_OUTPUT_PATH);
162            }
163        } catch(Exception e) {
164            fail("setMediaRecorderToDataSourceConfiguredState: Exception " + e.getClass().getName() + " was thrown.");
165        }
166    }
167
168    /*
169     * There are a lot of ways to force the MediaRecorder object to enter
170     * the Error state. We arbitrary choose one here.
171     */
172    private void setMediaRecorderToErrorState() {
173        try {
174            mMediaRecorder.reset();
175
176            /* Skip setAudioSource() if the method under test is setAudioEncoder()
177             * Because, otherwise, it is valid to call setAudioEncoder() after
178             * start() since start() will fail, and then the mMediaRecorder
179             * won't be set to the Error state
180             */
181            if (mMethodUnderTest.toString() != "setAudioEncoder()") {
182                mMediaRecorder.setAudioSource(AUDIO_SOURCE);
183            }
184
185            /* Skip setOutputFormat if the method under test is setOutputFile()
186             *  Because, otherwise, it is valid to call setOutputFile() after
187             * start() since start() will fail, and then the mMediaRecorder
188             * won't be set to the Error state
189             */
190            if (mMethodUnderTest.toString() != "setOutputFile()") {
191                mMediaRecorder.setOutputFormat(OUTPUT_FORMAT);
192            }
193
194            mMediaRecorder.start();
195        } catch(Exception e) {
196            if (!(e instanceof IllegalStateException)) {
197                fail("setMediaRecorderToErrorState: Exception " + e.getClass().getName() + " was thrown.");
198            }
199        }
200        Log.v(TAG, "setMediaRecorderToErrorState: done.");
201    }
202
203    /*
204     * Sets the state of the MediaRecorder object to the specified one.
205     *
206     * @param state the state of the MediaRecorder object.
207     */
208    private void setMediaRecorderToState(MediaRecorderStateErrors.MediaRecorderState state) {
209        mMediaRecorderState = state;
210        switch(state) {
211            case INITIAL:
212                // Does nothing.
213                break;
214            case INITIAL_AFTER_RESET:
215                setMediaRecorderToInitialStateAfterReset();
216                break;
217            case INITIAL_AFTER_STOP:
218                setMediaRecorderToInitialStateAfterStop();
219                break;
220            case INITIALIZED:
221                setMediaRecorderToInitializedState();
222                break;
223            case DATASOURCECONFIGURED:
224                setMediaRecorderToDataSourceConfiguredState();
225                break;
226            case PREPARED:
227                setMediaRecorderToPreparedState();
228                break;
229            case RECORDING:
230                setMediaRecorderToRecordingState();
231                break;
232            case ERROR:
233                setMediaRecorderToErrorState();
234                break;
235        }
236    }
237
238    /*
239     * Sets the error value of the corresponding state to the given error.
240     *
241     * @param state the state of the MediaRecorder object.
242     * @param error the value of the state error to be set.
243     */
244    private void setStateError(MediaRecorderStateErrors.MediaRecorderState state, boolean error) {
245        switch(state) {
246            case INITIAL:
247                mStateErrors.errorInInitialState = error;
248                break;
249            case INITIAL_AFTER_RESET:
250                mStateErrors.errorInInitialStateAfterReset = error;
251                break;
252            case INITIAL_AFTER_STOP:
253                mStateErrors.errorInInitialStateAfterStop = error;
254                break;
255            case INITIALIZED:
256                mStateErrors.errorInInitializedState = error;
257                break;
258            case DATASOURCECONFIGURED:
259                mStateErrors.errorInDataSourceConfiguredState = error;
260                break;
261            case PREPARED:
262                mStateErrors.errorInPreparedState = error;
263                break;
264            case RECORDING:
265                mStateErrors.errorInRecordingState = error;
266                break;
267            case ERROR:
268                mStateErrors.errorInErrorState = error;
269                break;
270        }
271    }
272
273    private void checkInitialState() {
274        callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.INITIAL);
275    }
276
277    private void checkInitialStateAfterReset() {
278        callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.INITIAL_AFTER_RESET);
279    }
280
281    private void checkInitialStateAfterStop() {
282        callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.INITIAL_AFTER_STOP);
283    }
284
285    private void checkInitializedState() {
286        callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.INITIALIZED);
287    }
288
289    private void checkPreparedState() {
290        callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.PREPARED);
291    }
292
293    private void checkRecordingState() {
294        callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.RECORDING);
295    }
296
297    private void checkDataSourceConfiguredState() {
298        callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.DATASOURCECONFIGURED);
299    }
300
301    private void checkErrorState() {
302        callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.ERROR);
303    }
304
305    /*
306     * Checks the given method under test in all possible states of the MediaRecorder object.
307     */
308    private void checkMethodUnderTestInAllPossibleStates() {
309        // Must be called first.
310        checkInitialState();
311
312        // The sequence of the following method calls should not
313        // affect the test results.
314        checkErrorState();
315        checkInitialStateAfterReset();
316        checkInitialStateAfterStop();
317        checkInitializedState();
318        checkRecordingState();
319        checkDataSourceConfiguredState();
320        checkPreparedState();
321    }
322
323    /*
324     * Cleans up all the internal object references.
325     */
326    private void cleanUp() {
327        mMediaRecorder.release();
328        mMediaRecorder = null;
329        mMediaRecorderState = null;
330        mStateErrors = null;
331        mMethodUnderTest = null;
332    }
333}
334