diff options
Diffstat (limited to 'testutils')
-rw-r--r-- | testutils/.classpath | 10 | ||||
-rw-r--r-- | testutils/.gitignore | 2 | ||||
-rw-r--r-- | testutils/.project | 17 | ||||
-rw-r--r-- | testutils/.settings/org.eclipse.jdt.core.prefs | 98 | ||||
-rw-r--r-- | testutils/Android.mk | 38 | ||||
-rw-r--r-- | testutils/NOTICE | 189 | ||||
-rw-r--r-- | testutils/manifest.txt | 1 | ||||
-rw-r--r-- | testutils/src/com/android/testutils/SdkTestCase.java | 436 | ||||
-rw-r--r-- | testutils/tests/.classpath | 9 | ||||
-rw-r--r-- | testutils/tests/.project | 17 | ||||
-rw-r--r-- | testutils/tests/Android.mk | 27 | ||||
-rw-r--r-- | testutils/tests/src/com/android/testutils/SdkTestCaseTest.java | 161 |
12 files changed, 1005 insertions, 0 deletions
diff --git a/testutils/.classpath b/testutils/.classpath new file mode 100644 index 0000000..45f7edb --- /dev/null +++ b/testutils/.classpath @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="src" path="tests/src"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/> + <classpathentry kind="var" path="ANDROID_SRC/prebuilts/tools/common/guava-tools/guava-13.0.1.jar" sourcepath="/ANDROID_SRC/prebuilts/tools/common/guava-tools/src.zip"/> + <classpathentry combineaccessrules="false" kind="src" path="/common"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/testutils/.gitignore b/testutils/.gitignore new file mode 100644 index 0000000..c745919 --- /dev/null +++ b/testutils/.gitignore @@ -0,0 +1,2 @@ +bin +build diff --git a/testutils/.project b/testutils/.project new file mode 100644 index 0000000..53319e5 --- /dev/null +++ b/testutils/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>testutils</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/testutils/.settings/org.eclipse.jdt.core.prefs b/testutils/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..9dbff07 --- /dev/null +++ b/testutils/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,98 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore +org.eclipse.jdt.core.compiler.annotation.nonnull=com.android.annotations.NonNull +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=com.android.annotations.NonNullByDefault +org.eclipse.jdt.core.compiler.annotation.nonnullisdefault=disabled +org.eclipse.jdt.core.compiler.annotation.nullable=com.android.annotations.Nullable +org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore +org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=error +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=enabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore +org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=error +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error +org.eclipse.jdt.core.compiler.problem.nullReference=error +org.eclipse.jdt.core.compiler.problem.nullSpecInsufficientInfo=warning +org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error +org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=ignore +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning +org.eclipse.jdt.core.compiler.problem.potentialNullSpecViolation=error +org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=warning +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=enabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.unclosedCloseable=error +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedImport=warning +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/testutils/Android.mk b/testutils/Android.mk new file mode 100644 index 0000000..2a1f6dc --- /dev/null +++ b/testutils/Android.mk @@ -0,0 +1,38 @@ +# +# Copyright (C) 2008 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-java-files-under,src) + +LOCAL_JAR_MANIFEST := manifest.txt + +# IMPORTANT: if you add a new dependency here, please make sure +# to also check the following files: +# testutils/manifest.txt +LOCAL_JAVA_LIBRARIES := \ + common \ + junit \ + guava-tools + +LOCAL_MODULE := sdktestutils + +LOCAL_MODULE_TAGS := optional + +include $(BUILD_HOST_JAVA_LIBRARY) + +# Build all sub-directories +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/testutils/NOTICE b/testutils/NOTICE new file mode 100644 index 0000000..002f1cb --- /dev/null +++ b/testutils/NOTICE @@ -0,0 +1,189 @@ + + Copyright (c) 2005-2012, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/testutils/manifest.txt b/testutils/manifest.txt new file mode 100644 index 0000000..b0f908d --- /dev/null +++ b/testutils/manifest.txt @@ -0,0 +1 @@ +Class-Path: guava-tools.jar diff --git a/testutils/src/com/android/testutils/SdkTestCase.java b/testutils/src/com/android/testutils/SdkTestCase.java new file mode 100644 index 0000000..6a4d54a --- /dev/null +++ b/testutils/src/com/android/testutils/SdkTestCase.java @@ -0,0 +1,436 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.testutils; + +import com.android.SdkConstants; +import com.google.common.base.Charsets; +import com.google.common.collect.Sets; +import com.google.common.io.ByteStreams; +import com.google.common.io.Closeables; +import com.google.common.io.Files; +import com.google.common.io.InputSupplier; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Set; + +import junit.framework.TestCase; + +/** + * Common test case for SDK unit tests. Contains a number of general utility methods + * to help writing test cases, such as looking up a temporary directory, comparing golden + * files, computing string diffs, etc. + */ +@SuppressWarnings("javadoc") +public class SdkTestCase extends TestCase { + public static final String TEST_PROJECT_PACKAGE = "com.android.eclipse.tests"; //$NON-NLS-1$ + + /** Update golden files if different from the actual results */ + private static final boolean UPDATE_DIFFERENT_FILES = false; + /** Create golden files if missing */ + private static final boolean UPDATE_MISSING_FILES = true; + private static File sTempDir = null; + protected static Set<File> sCleanDirs = Sets.newHashSet(); + + protected String getTestDataRelPath() { + return "eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/" + + "internal/editors/layout/refactoring/testdata"; + } + + public static int getCaretOffset(String fileContent, String caretLocation) { + assertTrue(caretLocation, caretLocation.contains("^")); //$NON-NLS-1$ + + int caretDelta = caretLocation.indexOf("^"); //$NON-NLS-1$ + assertTrue(caretLocation, caretDelta != -1); + + // String around caret/range without the range and caret marker characters + String caretContext; + if (caretLocation.contains("[^")) { //$NON-NLS-1$ + caretDelta--; + assertTrue(caretLocation, caretLocation.startsWith("[^", caretDelta)); //$NON-NLS-1$ + int caretRangeEnd = caretLocation.indexOf(']', caretDelta + 2); + assertTrue(caretLocation, caretRangeEnd != -1); + caretContext = caretLocation.substring(0, caretDelta) + + caretLocation.substring(caretDelta + 2, caretRangeEnd) + + caretLocation.substring(caretRangeEnd + 1); + } else { + caretContext = caretLocation.substring(0, caretDelta) + + caretLocation.substring(caretDelta + 1); // +1: skip "^" + } + + int caretContextIndex = fileContent.indexOf(caretContext); + assertTrue("Caret content " + caretContext + " not found in file", + caretContextIndex != -1); + return caretContextIndex + caretDelta; + } + + public static String addSelection(String newFileContents, int selectionBegin, int selectionEnd) { + // Insert selection markers -- [ ] for the selection range, ^ for the caret + String newFileWithCaret; + if (selectionBegin < selectionEnd) { + newFileWithCaret = newFileContents.substring(0, selectionBegin) + "[^" + + newFileContents.substring(selectionBegin, selectionEnd) + "]" + + newFileContents.substring(selectionEnd); + } else { + // Selected range + newFileWithCaret = newFileContents.substring(0, selectionBegin) + "^" + + newFileContents.substring(selectionBegin); + } + + return newFileWithCaret; + } + + public static String getCaretContext(String file, int offset) { + int windowSize = 20; + int begin = Math.max(0, offset - windowSize / 2); + int end = Math.min(file.length(), offset + windowSize / 2); + + return "..." + file.substring(begin, offset) + "^" + file.substring(offset, end) + "..."; + } + + /** Get the location to write missing golden files to */ + protected File getTargetDir() { + // Set $ADT_SDK_SOURCE_PATH to point to your git "sdk" directory; if done, then + // if you run a unit test which refers to a golden file which does not exist, it + // will be created directly into the test data directory and you can rerun the + // test + // and it should pass (after you verify that the golden file contains the correct + // result of course). + String sdk = System.getenv("ADT_SDK_SOURCE_PATH"); + if (sdk != null) { + File sdkPath = new File(sdk); + if (sdkPath.exists()) { + File testData = new File(sdkPath, getTestDataRelPath().replace('/', + File.separatorChar)); + if (testData.exists()) { + addCleanupDir(testData); + return testData; + } + } + } + return getTempDir(); + } + + public static File getTempDir() { + if (sTempDir == null) { + File base = new File(System.getProperty("java.io.tmpdir")); //$NON-NLS-1$ + if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_DARWIN) { + base = new File("/tmp"); //$NON-NLS-1$ + } + + // On Windows, we don't want to pollute the temp folder (which is generally + // already incredibly busy). So let's create a temp folder for the results. + + Calendar c = Calendar.getInstance(); + String name = String.format("sdkTests_%1$tF_%1$tT", c).replace(':', '-'); //$NON-NLS-1$ + File tmpDir = new File(base, name); + if (!tmpDir.exists() && tmpDir.mkdir()) { + sTempDir = tmpDir; + } else { + sTempDir = base; + } + addCleanupDir(sTempDir); + } + + return sTempDir; + } + + protected String removeSessionData(String data) { + return data; + } + + protected InputStream getTestResource(String relativePath, boolean expectExists) { + String path = "testdata" + File.separator + relativePath; //$NON-NLS-1$ + InputStream stream = SdkTestCase.class.getResourceAsStream(path); + if (!expectExists && stream == null) { + return null; + } + return stream; + } + + @SuppressWarnings("resource") + protected String readTestFile(String relativePath, boolean expectExists) throws IOException { + InputStream stream = getTestResource(relativePath, expectExists); + if (expectExists) { + assertNotNull(relativePath + " does not exist", stream); + } else if (stream == null) { + return null; + } + + String xml = new String(ByteStreams.toByteArray(stream), Charsets.UTF_8); + Closeables.closeQuietly(stream); + assertTrue(xml.length() > 0); + + // Remove any references to the project name such that we are isolated from + // that in golden file. + // Appears in strings.xml etc. + xml = removeSessionData(xml); + + return xml; + } + + protected void assertEqualsGolden(String basename, String actual) throws IOException { + assertEqualsGolden(basename, actual, basename.substring(basename.lastIndexOf('.') + 1)); + } + + protected void assertEqualsGolden(String basename, String actual, String newExtension) + throws IOException { + String testName = getName(); + if (testName.startsWith("test")) { + testName = testName.substring(4); + if (Character.isUpperCase(testName.charAt(0))) { + testName = Character.toLowerCase(testName.charAt(0)) + testName.substring(1); + } + } + String expectedName; + String extension = basename.substring(basename.lastIndexOf('.') + 1); + if (newExtension == null) { + newExtension = extension; + } + expectedName = basename.substring(0, basename.indexOf('.')) + + "-expected-" + testName + '.' + newExtension; + String expected = readTestFile(expectedName, false); + if (expected == null) { + File expectedPath = new File( + UPDATE_MISSING_FILES ? getTargetDir() : getTempDir(), expectedName); + Files.write(actual, expectedPath, Charsets.UTF_8); + System.out.println("Expected - written to " + expectedPath + ":\n"); + System.out.println(actual); + fail("Did not find golden file (" + expectedName + "): Wrote contents as " + + expectedPath); + } else { + if (!expected.replaceAll("\r\n", "\n").equals(actual.replaceAll("\r\n", "\n"))) { + File expectedPath = new File(getTempDir(), expectedName); + File actualPath = new File(getTempDir(), + expectedName.replace("expected", "actual")); + Files.write(expected, expectedPath, Charsets.UTF_8); + Files.write(actual, actualPath, Charsets.UTF_8); + // Also update data dir with the current value + if (UPDATE_DIFFERENT_FILES) { + Files.write(actual, new File(getTargetDir(), expectedName), Charsets.UTF_8); + } + System.out.println("The files differ: diff " + expectedPath + " " + + actualPath); + assertEquals("The files differ - see " + expectedPath + " versus " + actualPath, + expected, actual); + } + } + } + + /** Creates a diff of two strings */ + public static String getDiff(String before, String after) { + return getDiff(before.split("\n"), after.split("\n")); + } + + public static String getDiff(String[] before, String[] after) { + // Based on the LCS section in http://introcs.cs.princeton.edu/java/96optimization/ + StringBuilder sb = new StringBuilder(); + + int n = before.length; + int m = after.length; + + // Compute longest common subsequence of x[i..m] and y[j..n] bottom up + int[][] lcs = new int[n + 1][m + 1]; + for (int i = n - 1; i >= 0; i--) { + for (int j = m - 1; j >= 0; j--) { + if (before[i].equals(after[j])) { + lcs[i][j] = lcs[i + 1][j + 1] + 1; + } else { + lcs[i][j] = Math.max(lcs[i + 1][j], lcs[i][j + 1]); + } + } + } + + int i = 0; + int j = 0; + while ((i < n) && (j < m)) { + if (before[i].equals(after[j])) { + i++; + j++; + } else { + sb.append("@@ -"); + sb.append(Integer.toString(i + 1)); + sb.append(" +"); + sb.append(Integer.toString(j + 1)); + sb.append('\n'); + while (i < n && j < m && !before[i].equals(after[j])) { + if (lcs[i + 1][j] >= lcs[i][j + 1]) { + sb.append('-'); + if (!before[i].trim().isEmpty()) { + sb.append(' '); + } + sb.append(before[i]); + sb.append('\n'); + i++; + } else { + sb.append('+'); + if (!after[j].trim().isEmpty()) { + sb.append(' '); + } + sb.append(after[j]); + sb.append('\n'); + j++; + } + } + } + } + + if (i < n || j < m) { + assert i == n || j == m; + sb.append("@@ -"); + sb.append(Integer.toString(i + 1)); + sb.append(" +"); + sb.append(Integer.toString(j + 1)); + sb.append('\n'); + for (; i < n; i++) { + sb.append('-'); + if (!before[i].trim().isEmpty()) { + sb.append(' '); + } + sb.append(before[i]); + sb.append('\n'); + } + for (; j < m; j++) { + sb.append('+'); + if (!after[j].trim().isEmpty()) { + sb.append(' '); + } + sb.append(after[j]); + sb.append('\n'); + } + } + + return sb.toString(); + } + + protected void deleteFile(File dir) { + if (dir.isDirectory()) { + for (File f : dir.listFiles()) { + deleteFile(f); + } + } else if (dir.isFile()) { + assertTrue(dir.getPath(), dir.delete()); + } + } + + protected File makeTestFile(String name, String relative, + final InputStream contents) throws IOException { + return makeTestFile(getTargetDir(), name, relative, contents); + } + + protected File makeTestFile(File dir, String name, String relative, + final InputStream contents) throws IOException { + if (relative != null) { + dir = new File(dir, relative); + if (!dir.exists()) { + boolean mkdir = dir.mkdirs(); + assertTrue(dir.getPath(), mkdir); + } + } else if (!dir.exists()) { + boolean mkdir = dir.mkdirs(); + assertTrue(dir.getPath(), mkdir); + } + File tempFile = new File(dir, name); + if (tempFile.exists()) { + tempFile.delete(); + } + + Files.copy(new InputSupplier<InputStream>() { + @Override + public InputStream getInput() throws IOException { + return contents; + } + }, tempFile); + + return tempFile; + } + + protected File getTestfile(File targetDir, String relativePath) throws IOException { + // Support replacing filenames and paths with a => syntax, e.g. + // dir/file.txt=>dir2/dir3/file2.java + // will read dir/file.txt from the test data and write it into the target + // directory as dir2/dir3/file2.java + + String targetPath = relativePath; + int replaceIndex = relativePath.indexOf("=>"); //$NON-NLS-1$ + if (replaceIndex != -1) { + // foo=>bar + targetPath = relativePath.substring(replaceIndex + "=>".length()); + relativePath = relativePath.substring(0, replaceIndex); + } + + InputStream stream = getTestResource(relativePath, true); + assertNotNull(relativePath + " does not exist", stream); + int index = targetPath.lastIndexOf('/'); + String relative = null; + String name = targetPath; + if (index != -1) { + name = targetPath.substring(index + 1); + relative = targetPath.substring(0, index); + } + + return makeTestFile(targetDir, name, relative, stream); + } + + protected static void addCleanupDir(File dir) { + sCleanDirs.add(dir); + try { + sCleanDirs.add(dir.getCanonicalFile()); + } catch (IOException e) { + fail(e.getLocalizedMessage()); + } + sCleanDirs.add(dir.getAbsoluteFile()); + } + + protected String cleanup(String result) { + List<File> sorted = new ArrayList<File>(sCleanDirs); + // Process dirs in order such that we match longest substrings first + Collections.sort(sorted, new Comparator<File>() { + @Override + public int compare(File file1, File file2) { + String path1 = file1.getPath(); + String path2 = file2.getPath(); + int delta = path2.length() - path1.length(); + if (delta != 0) { + return delta; + } else { + return path1.compareTo(path2); + } + } + }); + + for (File dir : sorted) { + if (result.contains(dir.getPath())) { + result = result.replace(dir.getPath(), "/TESTROOT"); + } + } + + // The output typically contains a few directory/filenames. + // On Windows we need to change the separators to the unix-style + // forward slash to make the test as OS-agnostic as possible. + if (File.separatorChar != '/') { + result = result.replace(File.separatorChar, '/'); + } + + return result; + } +} diff --git a/testutils/tests/.classpath b/testutils/tests/.classpath new file mode 100644 index 0000000..0ac1351 --- /dev/null +++ b/testutils/tests/.classpath @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/> + <classpathentry combineaccessrules="false" kind="src" path="/sdktestutils"/> + <classpathentry kind="var" path="ANDROID_SRC/prebuilts/tools/common/guava-tools/guava-13.0.1.jar" sourcepath="/ANDROID_SRC/prebuilts/tools/common/guava-tools/src.zip"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/testutils/tests/.project b/testutils/tests/.project new file mode 100644 index 0000000..3191084 --- /dev/null +++ b/testutils/tests/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>testutils-tests</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/testutils/tests/Android.mk b/testutils/tests/Android.mk new file mode 100644 index 0000000..e203ab4 --- /dev/null +++ b/testutils/tests/Android.mk @@ -0,0 +1,27 @@ +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +# Only compile source java files in this lib. +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_MODULE := sdktestutils-tests +LOCAL_MODULE_TAGS := optional + +LOCAL_JAVA_LIBRARIES := common sdktestutils junit + +include $(BUILD_HOST_JAVA_LIBRARY) diff --git a/testutils/tests/src/com/android/testutils/SdkTestCaseTest.java b/testutils/tests/src/com/android/testutils/SdkTestCaseTest.java new file mode 100644 index 0000000..9ab1a68 --- /dev/null +++ b/testutils/tests/src/com/android/testutils/SdkTestCaseTest.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.testutils; + +import junit.framework.TestCase; + +@SuppressWarnings("javadoc") +public class SdkTestCaseTest extends TestCase { + public void testDiff() throws Exception { + assertEquals( + "", + SdkTestCase.getDiff( + "", + "")); + assertEquals( + "", + SdkTestCase.getDiff( + "aaa", + "aaa")); + assertEquals( + "@@ -1 +1\n" + + "- aaa\n" + + "@@ -2 +1\n" + + "+ bbb\n", + SdkTestCase.getDiff( + "aaa", + "bbb")); + assertEquals( + "@@ -1 +1\n" + + "- this\n" + + "@@ -4 +3\n" + + "+ new\n", + SdkTestCase.getDiff( + "this\n" + + "is\n" + + "a\n" + + "test\n", + + "is\n" + + "a\n" + + "new\n" + + "test\n")); + assertEquals( + "@@ -4 +4\n" + + "- line4\n" + + "- line5\n" + + "@@ -8 +6\n" + + "- line8\n" + + "+ line7.5\n", + SdkTestCase.getDiff( + "line1\n" + + "line2\n" + + "line3\n" + + "line4\n" + + "line5\n" + + "line6\n" + + "line7\n" + + "line8\n" + + "line9\n", + + "line1\n" + + "line2\n" + + "line3\n" + + "line6\n" + + "line7\n" + + "line7.5\n" + + "line9\n")); + assertEquals( + "@@ -8 +8\n" + + "- android:id=\"@+id/textView1\"\n" + + "+ android:id=\"@+id/output\"\n" + + "@@ -19 +19\n" + + "- android:layout_alignLeft=\"@+id/textView1\"\n" + + "- android:layout_below=\"@+id/textView1\"\n" + + "+ android:layout_alignLeft=\"@+id/output\"\n" + + "+ android:layout_below=\"@+id/output\"\n", + + SdkTestCase.getDiff( + "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + + " xmlns:tools=\"http://schemas.android.com/tools\"\n" + + " android:layout_width=\"match_parent\"\n" + + " android:layout_height=\"match_parent\"\n" + + " tools:context=\".MainActivity\" >\n" + + "\n" + + " <TextView\n" + + " android:id=\"@+id/textView1\"\n" + + " android:layout_width=\"wrap_content\"\n" + + " android:layout_height=\"wrap_content\"\n" + + " android:layout_centerVertical=\"true\"\n" + + " android:layout_toRightOf=\"@+id/button2\"\n" + + " android:text=\"@string/hello_world\" />\n" + + "\n" + + " <Button\n" + + " android:id=\"@+id/button1\"\n" + + " android:layout_width=\"wrap_content\"\n" + + " android:layout_height=\"wrap_content\"\n" + + " android:layout_alignLeft=\"@+id/textView1\"\n" + + " android:layout_below=\"@+id/textView1\"\n" + + " android:layout_marginLeft=\"22dp\"\n" + + " android:layout_marginTop=\"24dp\"\n" + + " android:text=\"Button\" />\n" + + "\n" + + " <Button\n" + + " android:id=\"@+id/button2\"\n" + + " android:layout_width=\"wrap_content\"\n" + + " android:layout_height=\"wrap_content\"\n" + + " android:layout_alignParentLeft=\"true\"\n" + + " android:layout_alignParentTop=\"true\"\n" + + " android:text=\"Button\" />\n" + + "\n" + + "</RelativeLayout>", + + "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + + " xmlns:tools=\"http://schemas.android.com/tools\"\n" + + " android:layout_width=\"match_parent\"\n" + + " android:layout_height=\"match_parent\"\n" + + " tools:context=\".MainActivity\" >\n" + + "\n" + + " <TextView\n" + + " android:id=\"@+id/output\"\n" + + " android:layout_width=\"wrap_content\"\n" + + " android:layout_height=\"wrap_content\"\n" + + " android:layout_centerVertical=\"true\"\n" + + " android:layout_toRightOf=\"@+id/button2\"\n" + + " android:text=\"@string/hello_world\" />\n" + + "\n" + + " <Button\n" + + " android:id=\"@+id/button1\"\n" + + " android:layout_width=\"wrap_content\"\n" + + " android:layout_height=\"wrap_content\"\n" + + " android:layout_alignLeft=\"@+id/output\"\n" + + " android:layout_below=\"@+id/output\"\n" + + " android:layout_marginLeft=\"22dp\"\n" + + " android:layout_marginTop=\"24dp\"\n" + + " android:text=\"Button\" />\n" + + "\n" + + " <Button\n" + + " android:id=\"@+id/button2\"\n" + + " android:layout_width=\"wrap_content\"\n" + + " android:layout_height=\"wrap_content\"\n" + + " android:layout_alignParentLeft=\"true\"\n" + + " android:layout_alignParentTop=\"true\"\n" + + " android:text=\"Button\" />\n" + + "\n" + + "</RelativeLayout>")); + } +} |