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;
23bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaenimport junit.framework.TestCase;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.Field;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Extend this if you need to access Resources or other things that depend on Activity Context.
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class AndroidTestCase extends TestCase {
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected Context mContext;
3344a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov    private Context mTestContext;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void setUp() throws Exception {
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.setUp();
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void tearDown() throws Exception {
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.tearDown();
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void testAndroidTestCaseSetupProperly() {
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        assertNotNull("Context is null. setContext should be called before tests are run",
4744a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov                mContext);
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setContext(Context context) {
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Context getContext() {
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mContext;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5944a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     * Test context can be used to access resources from the test's own package
6044a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     * as opposed to the resources from the test target package. Access to the
6144a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     * latter is provided by the context set with the {@link #setContext}
6244a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     * method.
6344a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     *
6444a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     * @hide
6544a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     */
6644a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov    public void setTestContext(Context context) {
6744a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov        mTestContext = context;
6844a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov    }
6944a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov
7044a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov    /**
7144a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     * @hide
7244a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     */
7344a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov    public Context getTestContext() {
7444a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov        return mTestContext;
7544a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov    }
7644a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov
7744a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov    /**
78bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * Asserts that launching a given activity is protected by a particular permission by
79bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * attempting to start the activity and validating that a {@link SecurityException}
80bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * is thrown that mentions the permission in its error message.
81bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     *
82bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * Note that an instrumentation isn't needed because all we are looking for is a security error
83bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * and we don't need to wait for the activity to launch and get a handle to the activity.
84bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     *
85bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * @param packageName The package name of the activity to launch.
86bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * @param className The class of the activity to launch.
87bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * @param permission The name of the permission.
88bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     */
89bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen    public void assertActivityRequiresPermission(
90bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            String packageName, String className, String permission) {
91bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        final Intent intent = new Intent();
92bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        intent.setClassName(packageName, className);
93bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
94bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen
95bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        try {
96bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            getContext().startActivity(intent);
97bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            fail("expected security exception for " + permission);
98bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        } catch (SecurityException expected) {
99bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            assertNotNull("security exception's error message.", expected.getMessage());
100bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            assertTrue("error message should contain " + permission + ".",
101bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen                    expected.getMessage().contains(permission));
102bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        }
103bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen    }
104bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen
105bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen
106bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen    /**
107bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * Asserts that reading from the content uri requires a particular permission by querying the
108bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * uri and ensuring a {@link SecurityException} is thrown mentioning the particular permission.
109bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     *
110bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * @param uri The uri that requires a permission to query.
111bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * @param permission The permission that should be required.
112bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     */
113bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen    public void assertReadingContentUriRequiresPermission(Uri uri, String permission) {
114bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        try {
115bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            getContext().getContentResolver().query(uri, null, null, null, null);
116bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            fail("expected SecurityException requiring " + permission);
117bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        } catch (SecurityException expected) {
118bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            assertNotNull("security exception's error message.", expected.getMessage());
119bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            assertTrue("error message should contain " + permission + ".",
120bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen                    expected.getMessage().contains(permission));
121bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        }
122bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen    }
123bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen
124bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen    /**
125bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * Asserts that writing to the content uri requires a particular permission by inserting into
126bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * the uri and ensuring a {@link SecurityException} is thrown mentioning the particular
127bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * permission.
128bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     *
129bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * @param uri The uri that requires a permission to query.
130bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     * @param permission The permission that should be required.
131bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen     */
132bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen    public void assertWritingContentUriRequiresPermission(Uri uri, String permission) {
133bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        try {
134bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            getContext().getContentResolver().insert(uri, new ContentValues());
135bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            fail("expected SecurityException requiring " + permission);
136bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        } catch (SecurityException expected) {
137bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen            assertNotNull("security exception's error message.", expected.getMessage());
138ff92aa74c133fd4abe30f97e6849e80db29af253Nick Kralevich            assertTrue("error message should contain \"" + permission + "\". Got: \""
139ff92aa74c133fd4abe30f97e6849e80db29af253Nick Kralevich                    + expected.getMessage() + "\".",
140bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen                    expected.getMessage().contains(permission));
141bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen        }
142bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen    }
143bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen
144bedf9df706ef1fe352c1ba0734f50f9e8ad2533eKarl Rosaen    /**
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This function is called by various TestCase implementations, at tearDown() time, in order
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * to scrub out any class variables.  This protects against memory leaks in the case where a
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * test case creates a non-static inner class (thus referencing the test case) and gives it to
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * someone else to hold onto.
14944a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     *
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param testCaseClass The class of the derived TestCase implementation.
15144a29dd097350e3050e44a2f64aa4c75d26ec695Dmitri Plotnikov     *
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws IllegalAccessException
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void scrubClass(final Class<?> testCaseClass)
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    throws IllegalAccessException {
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Field[] fields = getClass().getDeclaredFields();
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (Field field : fields) {
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Class<?> fieldClass = field.getDeclaringClass();
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (testCaseClass.isAssignableFrom(fieldClass) && !field.getType().isPrimitive()) {
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    field.setAccessible(true);
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    field.set(this, null);
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (Exception e) {
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    android.util.Log.d("TestCase", "Error: Could not nullify field!");
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (field.get(this) != null) {
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    android.util.Log.d("TestCase", "Error: Could not nullify field!");
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
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