19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.test;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaenimport android.content.ContentValues;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
21bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaenimport android.content.Intent;
22bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaenimport android.net.Uri;
23dd86cb7caf224de0df9c5fff7439677972424fecJeff Sharkey
24bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaenimport junit.framework.TestCase;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.Field;
27dd86cb7caf224de0df9c5fff7439677972424fecJeff Sharkeyimport java.lang.reflect.Modifier;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Extend this if you need to access Resources or other things that depend on Activity Context.
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class AndroidTestCase extends TestCase {
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected Context mContext;
3544a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov    private Context mTestContext;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void setUp() throws Exception {
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.setUp();
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void tearDown() throws Exception {
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.tearDown();
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void testAndroidTestCaseSetupProperly() {
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        assertNotNull("Context is null. setContext should be called before tests are run",
4944a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov                mContext);
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setContext(Context context) {
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Context getContext() {
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mContext;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6144a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     * Test context can be used to access resources from the test's own package
6244a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     * as opposed to the resources from the test target package. Access to the
6344a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     * latter is provided by the context set with the {@link #setContext}
6444a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     * method.
6544a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     *
6644a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     * @hide
6744a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     */
6844a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov    public void setTestContext(Context context) {
6944a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov        mTestContext = context;
7044a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov    }
7144a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov
7244a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov    /**
7344a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     * @hide
7444a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     */
7544a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov    public Context getTestContext() {
7644a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov        return mTestContext;
7744a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov    }
7844a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov
7944a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov    /**
80bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * Asserts that launching a given activity is protected by a particular permission by
81bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * attempting to start the activity and validating that a {@link SecurityException}
82bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * is thrown that mentions the permission in its error message.
83bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     *
84bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * Note that an instrumentation isn't needed because all we are looking for is a security error
85bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * and we don't need to wait for the activity to launch and get a handle to the activity.
86bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     *
87bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * @param packageName The package name of the activity to launch.
88bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * @param className The class of the activity to launch.
89bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * @param permission The name of the permission.
90bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     */
91bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen    public void assertActivityRequiresPermission(
92bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            String packageName, String className, String permission) {
93bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        final Intent intent = new Intent();
94bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        intent.setClassName(packageName, className);
95bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
96bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen
97bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        try {
98bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            getContext().startActivity(intent);
99bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            fail("expected security exception for " + permission);
100bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        } catch (SecurityException expected) {
101bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            assertNotNull("security exception's error message.", expected.getMessage());
102bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            assertTrue("error message should contain " + permission + ".",
103bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen                    expected.getMessage().contains(permission));
104bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        }
105bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen    }
106bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen
107bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen
108bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen    /**
109bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * Asserts that reading from the content uri requires a particular permission by querying the
110bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * uri and ensuring a {@link SecurityException} is thrown mentioning the particular permission.
111bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     *
112bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * @param uri The uri that requires a permission to query.
113bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * @param permission The permission that should be required.
114bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     */
115bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen    public void assertReadingContentUriRequiresPermission(Uri uri, String permission) {
116bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        try {
117bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            getContext().getContentResolver().query(uri, null, null, null, null);
118bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            fail("expected SecurityException requiring " + permission);
119bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        } catch (SecurityException expected) {
120bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            assertNotNull("security exception's error message.", expected.getMessage());
121bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            assertTrue("error message should contain " + permission + ".",
122bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen                    expected.getMessage().contains(permission));
123bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        }
124bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen    }
125bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen
126bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen    /**
127bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * Asserts that writing to the content uri requires a particular permission by inserting into
128bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * the uri and ensuring a {@link SecurityException} is thrown mentioning the particular
129bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * permission.
130bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     *
131bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * @param uri The uri that requires a permission to query.
132bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * @param permission The permission that should be required.
133bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     */
134bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen    public void assertWritingContentUriRequiresPermission(Uri uri, String permission) {
135bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        try {
136bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            getContext().getContentResolver().insert(uri, new ContentValues());
137bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            fail("expected SecurityException requiring " + permission);
138bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        } catch (SecurityException expected) {
139bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            assertNotNull("security exception's error message.", expected.getMessage());
140ff92aa74c133fd4abe30f97e6849e80db29af253Nick Kralevich            assertTrue("error message should contain \"" + permission + "\". Got: \""
141ff92aa74c133fd4abe30f97e6849e80db29af253Nick Kralevich                    + expected.getMessage() + "\".",
142bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen                    expected.getMessage().contains(permission));
143bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        }
144bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen    }
145bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen
146bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen    /**
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This function is called by various TestCase implementations, at tearDown() time, in order
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * to scrub out any class variables.  This protects against memory leaks in the case where a
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * test case creates a non-static inner class (thus referencing the test case) and gives it to
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * someone else to hold onto.
15144a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     *
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param testCaseClass The class of the derived TestCase implementation.
15344a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     *
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws IllegalAccessException
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void scrubClass(final Class<?> testCaseClass)
157dd86cb7caf224de0df9c5fff7439677972424fecJeff Sharkey            throws IllegalAccessException {
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Field[] fields = getClass().getDeclaredFields();
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (Field field : fields) {
160dd86cb7caf224de0df9c5fff7439677972424fecJeff Sharkey            if (!field.getType().isPrimitive() &&
161dd86cb7caf224de0df9c5fff7439677972424fecJeff Sharkey                    !Modifier.isStatic(field.getModifiers())) {
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    field.setAccessible(true);
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    field.set(this, null);
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (Exception e) {
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    android.util.Log.d("TestCase", "Error: Could not nullify field!");
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (field.get(this) != null) {
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    android.util.Log.d("TestCase", "Error: Could not nullify field!");
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
176