1/*
2 * Copyright (C) 2012 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 */
16package android.support.test.runner;
17
18import android.content.Context;
19import android.os.Bundle;
20import android.os.Handler;
21import android.os.Looper;
22import android.os.Message;
23import android.support.test.internal.runner.TestRequestBuilder;
24
25import junit.framework.Assert;
26
27import org.junit.Before;
28import org.junit.Rule;
29import org.junit.Test;
30import org.junit.rules.TemporaryFolder;
31import org.mockito.Mock;
32import org.mockito.Mockito;
33import org.mockito.MockitoAnnotations;
34
35
36import java.io.BufferedWriter;
37import java.io.ByteArrayOutputStream;
38import java.io.File;
39import java.io.FileWriter;
40import java.io.IOException;
41import java.io.PrintStream;
42
43/**
44 * Unit tests for {@link AndroidJUnitRunner}.
45 */
46public class AndroidJUnitRunnerTest {
47    public static final int SLEEP_TIME = 300;
48
49    private final Thread mInstantiationThread = Thread.currentThread();
50
51    private AndroidJUnitRunner mAndroidJUnitRunner;
52    private PrintStream mStubStream;
53    @Mock
54    private TestRequestBuilder mMockBuilder;
55    @Mock
56    private Context mMockContext;
57
58    @Before
59    public void setUp() throws Exception {
60        mAndroidJUnitRunner = new AndroidJUnitRunner() {
61
62            @Override
63            TestRequestBuilder createTestRequestBuilder(PrintStream writer,
64                    String... packageCodePaths) {
65                return mMockBuilder;
66            }
67
68            @Override
69            public Context getContext() {
70                return mMockContext;
71            }
72        };
73        mAndroidJUnitRunner.setArguments(new Bundle());
74        mStubStream = new PrintStream(new ByteArrayOutputStream());
75        MockitoAnnotations.initMocks(this);
76    }
77
78    /**
79     * Test {@link AndroidJUnitRunner#buildRequest(Bundle, PrintStream)} when
80     * a single class name is provided.
81     */
82    @Test
83    public void testBuildRequest_singleClass() {
84        Bundle b = new Bundle();
85        b.putString(AndroidJUnitRunner.ARGUMENT_TEST_CLASS, "ClassName");
86        mAndroidJUnitRunner.buildRequest(b, mStubStream);
87        Mockito.verify(mMockBuilder).addTestClass("ClassName");
88    }
89
90    /**
91     * Test {@link AndroidJUnitRunner#buildRequest(Bundle, PrintStream)} when
92     * multiple class names are provided.
93     */
94    @Test
95    public void testBuildRequest_multiClass() {
96        Bundle b = new Bundle();
97        b.putString(AndroidJUnitRunner.ARGUMENT_TEST_CLASS, "ClassName1,ClassName2");
98        mAndroidJUnitRunner.buildRequest(b, mStubStream);
99        Mockito.verify(mMockBuilder).addTestClass("ClassName1");
100        Mockito.verify(mMockBuilder).addTestClass("ClassName2");
101    }
102
103    /**
104     * Test {@link AndroidJUnitRunner#buildRequest(Bundle, PrintStream)} when
105     * class name and method name is provided.
106     */
107    @Test
108    public void testBuildRequest_method() {
109        Bundle b = new Bundle();
110        b.putString(AndroidJUnitRunner.ARGUMENT_TEST_CLASS, "ClassName1#method");
111        mAndroidJUnitRunner.buildRequest(b, mStubStream);
112        Mockito.verify(mMockBuilder).addTestMethod("ClassName1", "method");
113    }
114
115    /**
116     * Test {@link AndroidJUnitRunner#buildRequest(Bundle, PrintStream)} when
117     * class name and method name is provided along with an additional class name.
118     */
119    @Test
120    public void testBuildRequest_classAndMethodCombo() {
121        Bundle b = new Bundle();
122        b.putString(AndroidJUnitRunner.ARGUMENT_TEST_CLASS, "ClassName1#method,ClassName2");
123        mAndroidJUnitRunner.buildRequest(b, mStubStream);
124        Mockito.verify(mMockBuilder).addTestMethod("ClassName1", "method");
125        Mockito.verify(mMockBuilder).addTestClass("ClassName2");
126    }
127
128    /**
129     * Temp file used for testing
130     */
131    @Rule
132    public TemporaryFolder mTmpFolder = new TemporaryFolder();
133
134    /**
135     * Test {@link AndroidJUnitRunner#buildRequest(Bundle, PrintStream)} when
136     * multiple class and method names are provided within a test file
137     */
138    @Test
139    public void testBuildRequest_testFile() throws IOException {
140        final File file = mTmpFolder.newFile("myTestFile.txt");
141        BufferedWriter out = new BufferedWriter(new FileWriter(file));
142        out.write("ClassName3\n");
143        out.write("ClassName4#method2\n");
144        out.close();
145
146        Bundle b = new Bundle();
147        b.putString(AndroidJUnitRunner.ARGUMENT_TEST_FILE, file.getPath());
148        b.putString(AndroidJUnitRunner.ARGUMENT_TEST_CLASS, "ClassName1#method1,ClassName2");
149        mAndroidJUnitRunner.buildRequest(b, mStubStream);
150        Mockito.verify(mMockBuilder).addTestMethod("ClassName1", "method1");
151        Mockito.verify(mMockBuilder).addTestClass("ClassName2");
152        Mockito.verify(mMockBuilder).addTestClass("ClassName3");
153        Mockito.verify(mMockBuilder).addTestMethod("ClassName4", "method2");
154    }
155
156    /**
157     * Ensures that the main looper is not blocked and can process
158     * messages during test execution.
159     */
160    @Test
161    public void testMainLooperIsAlive() throws InterruptedException {
162        final boolean[] called = new boolean[1];
163        Handler handler = new Handler(Looper.getMainLooper()) {
164            @Override
165            public void handleMessage(Message msg) {
166                called[0] = true;
167            }
168        };
169        handler.sendEmptyMessage(0);
170        Thread.sleep(SLEEP_TIME);
171        Assert.assertTrue(called[0]);
172    }
173
174    /**
175     * Ensures that the thread the test runs on has not been
176     * prepared as a looper.  It doesn't make sense for it
177     * to be a looper because it will be blocked for the entire
178     * duration of test execution.  Tests should instead post
179     * messages to the main looper or a new handler thread
180     * of their own as appropriate while running.
181     */
182    @Test
183    public void testTestThreadIsNotALooper() {
184        Assert.assertNull(Looper.myLooper());
185    }
186
187    /**
188     * Ensures that tests run on the same thread they were
189     * instantiated on.  This is needed to ensure that
190     * objects created by the test don't accidentally bind
191     * to thread-local state belonging to other threads.
192     * In particular, this ensures that the test cannot
193     * create Handlers that are bound to the wrong thread.
194     */
195    @Test
196    public void testTestRunsOnSameThreadAsInstantiation() {
197        Assert.assertEquals(Thread.currentThread(), mInstantiationThread);
198    }
199}
200