1/*
2 * Copyright (C) 2006 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 android.test;
18
19import android.content.ContentValues;
20import android.content.Context;
21import android.content.Intent;
22import android.net.Uri;
23import junit.framework.TestCase;
24
25import java.lang.reflect.Field;
26
27/**
28 * Extend this if you need to access Resources or other things that depend on Activity Context.
29 */
30public class AndroidTestCase extends TestCase {
31
32    protected Context mContext;
33    private Context mTestContext;
34
35    @Override
36    protected void setUp() throws Exception {
37        super.setUp();
38    }
39
40    @Override
41    protected void tearDown() throws Exception {
42        super.tearDown();
43    }
44
45    public void testAndroidTestCaseSetupProperly() {
46        assertNotNull("Context is null. setContext should be called before tests are run",
47                mContext);
48    }
49
50    public void setContext(Context context) {
51        mContext = context;
52    }
53
54    public Context getContext() {
55        return mContext;
56    }
57
58    /**
59     * Test context can be used to access resources from the test's own package
60     * as opposed to the resources from the test target package. Access to the
61     * latter is provided by the context set with the {@link #setContext}
62     * method.
63     *
64     * @hide
65     */
66    public void setTestContext(Context context) {
67        mTestContext = context;
68    }
69
70    /**
71     * @hide
72     */
73    public Context getTestContext() {
74        return mTestContext;
75    }
76
77    /**
78     * Asserts that launching a given activity is protected by a particular permission by
79     * attempting to start the activity and validating that a {@link SecurityException}
80     * is thrown that mentions the permission in its error message.
81     *
82     * Note that an instrumentation isn't needed because all we are looking for is a security error
83     * and we don't need to wait for the activity to launch and get a handle to the activity.
84     *
85     * @param packageName The package name of the activity to launch.
86     * @param className The class of the activity to launch.
87     * @param permission The name of the permission.
88     */
89    public void assertActivityRequiresPermission(
90            String packageName, String className, String permission) {
91        final Intent intent = new Intent();
92        intent.setClassName(packageName, className);
93        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
94
95        try {
96            getContext().startActivity(intent);
97            fail("expected security exception for " + permission);
98        } catch (SecurityException expected) {
99            assertNotNull("security exception's error message.", expected.getMessage());
100            assertTrue("error message should contain " + permission + ".",
101                    expected.getMessage().contains(permission));
102        }
103    }
104
105
106    /**
107     * Asserts that reading from the content uri requires a particular permission by querying the
108     * uri and ensuring a {@link SecurityException} is thrown mentioning the particular permission.
109     *
110     * @param uri The uri that requires a permission to query.
111     * @param permission The permission that should be required.
112     */
113    public void assertReadingContentUriRequiresPermission(Uri uri, String permission) {
114        try {
115            getContext().getContentResolver().query(uri, null, null, null, null);
116            fail("expected SecurityException requiring " + permission);
117        } catch (SecurityException expected) {
118            assertNotNull("security exception's error message.", expected.getMessage());
119            assertTrue("error message should contain " + permission + ".",
120                    expected.getMessage().contains(permission));
121        }
122    }
123
124    /**
125     * Asserts that writing to the content uri requires a particular permission by inserting into
126     * the uri and ensuring a {@link SecurityException} is thrown mentioning the particular
127     * permission.
128     *
129     * @param uri The uri that requires a permission to query.
130     * @param permission The permission that should be required.
131     */
132    public void assertWritingContentUriRequiresPermission(Uri uri, String permission) {
133        try {
134            getContext().getContentResolver().insert(uri, new ContentValues());
135            fail("expected SecurityException requiring " + permission);
136        } catch (SecurityException expected) {
137            assertNotNull("security exception's error message.", expected.getMessage());
138            assertTrue("error message should contain " + permission + ".",
139                    expected.getMessage().contains(permission));
140        }
141    }
142
143    /**
144     * This function is called by various TestCase implementations, at tearDown() time, in order
145     * to scrub out any class variables.  This protects against memory leaks in the case where a
146     * test case creates a non-static inner class (thus referencing the test case) and gives it to
147     * someone else to hold onto.
148     *
149     * @param testCaseClass The class of the derived TestCase implementation.
150     *
151     * @throws IllegalAccessException
152     */
153    protected void scrubClass(final Class<?> testCaseClass)
154    throws IllegalAccessException {
155        final Field[] fields = getClass().getDeclaredFields();
156        for (Field field : fields) {
157            final Class<?> fieldClass = field.getDeclaringClass();
158            if (testCaseClass.isAssignableFrom(fieldClass) && !field.getType().isPrimitive()) {
159                try {
160                    field.setAccessible(true);
161                    field.set(this, null);
162                } catch (Exception e) {
163                    android.util.Log.d("TestCase", "Error: Could not nullify field!");
164                }
165
166                if (field.get(this) != null) {
167                    android.util.Log.d("TestCase", "Error: Could not nullify field!");
168                }
169            }
170        }
171    }
172
173
174}
175