|  | #!/usr/bin/python2.4 | 
|  | # | 
|  | # | 
|  | # Copyright 2009, 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. | 
|  |  | 
|  | """Utility to create Android project files for tests.""" | 
|  |  | 
|  | # python imports | 
|  | import datetime | 
|  | import optparse | 
|  | import os | 
|  | import string | 
|  | import sys | 
|  |  | 
|  | # local imports | 
|  | import android_mk | 
|  | import android_manifest | 
|  |  | 
|  |  | 
|  | class TestsConsts(object): | 
|  | """Constants for test Android.mk and AndroidManifest.xml creation.""" | 
|  |  | 
|  | MK_BUILD_INCLUDE = "call all-makefiles-under,$(LOCAL_PATH)" | 
|  | MK_BUILD_STRING = "\ninclude $(%s)\n" % MK_BUILD_INCLUDE | 
|  | TEST_MANIFEST_TEMPLATE = """<?xml version="1.0" encoding="utf-8"?> | 
|  | <!-- Copyright (C) $YEAR 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. | 
|  | --> | 
|  |  | 
|  | <manifest xmlns:android="http://schemas.android.com/apk/res/android" | 
|  | package="$PACKAGE_NAME.tests"> | 
|  |  | 
|  | <application> | 
|  | <uses-library android:name="android.test.runner" /> | 
|  | </application> | 
|  |  | 
|  | <instrumentation android:name="android.test.InstrumentationTestRunner" | 
|  | android:targetPackage="$PACKAGE_NAME" | 
|  | android:label="Tests for $MODULE_NAME"> | 
|  | </instrumentation> | 
|  | </manifest> | 
|  | """ | 
|  | TEST_MK_TEMPLATE = """LOCAL_PATH := $$(call my-dir) | 
|  | include $$(CLEAR_VARS) | 
|  |  | 
|  | LOCAL_MODULE_TAGS := tests | 
|  |  | 
|  | LOCAL_JAVA_LIBRARIES := android.test.runner | 
|  |  | 
|  | LOCAL_SRC_FILES := $$(call all-java-files-under, src) | 
|  |  | 
|  | LOCAL_PACKAGE_NAME := ${MODULE_NAME}Tests${CERTIFICATE} | 
|  |  | 
|  | LOCAL_INSTRUMENTATION_FOR := ${MODULE_NAME} | 
|  |  | 
|  | LOCAL_SDK_VERSION := current | 
|  |  | 
|  | include $$(BUILD_PACKAGE) | 
|  | """ | 
|  | TESTS_FOLDER = "tests" | 
|  |  | 
|  |  | 
|  | def _GenerateTestManifest(manifest, module_name, mapping=None): | 
|  | """Create and populate tests/AndroidManifest.xml with variable values from | 
|  | Android.mk and AndroidManifest.xml. | 
|  |  | 
|  | Does nothing if tests/AndroidManifest.xml already exists. | 
|  |  | 
|  | Args: | 
|  | manifest: AndroidManifest object for application manifest | 
|  | module_name: module name used for labelling | 
|  | mapping: optional user defined mapping of variable values, replaces values | 
|  | extracted from AndroidManifest.xml | 
|  | Raises: | 
|  | IOError: tests/AndroidManifest.xml cannot be opened for writing | 
|  | """ | 
|  | # skip if file already exists | 
|  | tests_path = "%s/%s" % (manifest.GetAppPath(), TestsConsts.TESTS_FOLDER) | 
|  | tests_manifest_path = "%s/%s" % (tests_path, manifest.FILENAME) | 
|  | if os.path.exists(tests_manifest_path): | 
|  | _PrintMessage("%s already exists, not overwritten" % tests_manifest_path) | 
|  | return | 
|  |  | 
|  | if not mapping: | 
|  | package_name = manifest.GetPackageName() | 
|  | mapping = {"PACKAGE_NAME":package_name, "MODULE_NAME":module_name, | 
|  | "YEAR":datetime.date.today().year} | 
|  | output = string.Template(TestsConsts.TEST_MANIFEST_TEMPLATE).substitute(mapping) | 
|  |  | 
|  | # create tests folder if not existent | 
|  | if not os.path.exists(tests_path): | 
|  | os.mkdir(tests_path) | 
|  |  | 
|  | # write tests/AndroidManifest.xml | 
|  | tests_manifest = open(tests_manifest_path, mode="w") | 
|  | tests_manifest.write(output) | 
|  | tests_manifest.close() | 
|  | _PrintMessage("Created %s" % tests_manifest_path) | 
|  |  | 
|  |  | 
|  | def _GenerateTestMK(mk, app_path, mapping=None): | 
|  | """Create and populate tests/Android.mk with variable values from Android.mk. | 
|  |  | 
|  | Does nothing if tests/Android.mk already exists. | 
|  |  | 
|  | Args: | 
|  | mk: AndroidMK object for application makefile | 
|  | app_path: path to the application being tested | 
|  | mapping: optional user defined mapping of variable values, replaces | 
|  | values stored in mk | 
|  | Raises: | 
|  | IOError: tests/Android.mk cannot be opened for writing | 
|  | """ | 
|  | # skip if file already exists | 
|  | tests_path = "%s/%s" % (app_path, TestsConsts.TESTS_FOLDER) | 
|  | tests_mk_path = "%s/%s" % (tests_path, mk.FILENAME) | 
|  | if os.path.exists(tests_mk_path): | 
|  | _PrintMessage("%s already exists, not overwritten" % tests_mk_path) | 
|  | return | 
|  |  | 
|  | # append test build if not existent in makefile | 
|  | if not mk.HasInclude(TestsConsts.MK_BUILD_INCLUDE): | 
|  | mk_path = "%s/%s" % (app_path, mk.FILENAME) | 
|  | mk_file = open(mk_path, mode="a") | 
|  | mk_file.write(TestsConsts.MK_BUILD_STRING) | 
|  | mk_file.close() | 
|  |  | 
|  | # construct tests/Android.mk | 
|  | # include certificate definition if existent in makefile | 
|  | certificate = mk.GetVariable(mk.CERTIFICATE) | 
|  | if certificate: | 
|  | cert_definition = ("\n%s := %s" % (mk.CERTIFICATE, certificate)) | 
|  | else: | 
|  | cert_definition = "" | 
|  | if not mapping: | 
|  | module_name = mk.GetVariable(mk.PACKAGE_NAME) | 
|  | mapping = {"MODULE_NAME":module_name, "CERTIFICATE":cert_definition} | 
|  | output = string.Template(TestsConsts.TEST_MK_TEMPLATE).substitute(mapping) | 
|  |  | 
|  | # create tests folder if not existent | 
|  | if not os.path.exists(tests_path): | 
|  | os.mkdir(tests_path) | 
|  |  | 
|  | # write tests/Android.mk to disk | 
|  | tests_mk = open(tests_mk_path, mode="w") | 
|  | tests_mk.write(output) | 
|  | tests_mk.close() | 
|  | _PrintMessage("Created %s" % tests_mk_path) | 
|  |  | 
|  |  | 
|  | def _ParseArgs(argv): | 
|  | """Parse the command line arguments. | 
|  |  | 
|  | Args: | 
|  | argv: the list of command line arguments | 
|  | Returns: | 
|  | a tuple of options and individual command line arguments. | 
|  | """ | 
|  | parser = optparse.OptionParser(usage="%s <app_path>" % sys.argv[0]) | 
|  | options, args = parser.parse_args(argv) | 
|  | if len(args) < 1: | 
|  | _PrintError("Error: Incorrect syntax") | 
|  | parser.print_usage() | 
|  | sys.exit() | 
|  | return (options, args) | 
|  |  | 
|  |  | 
|  | def _PrintMessage(msg): | 
|  | print >> sys.stdout, msg | 
|  |  | 
|  |  | 
|  | def _PrintError(msg): | 
|  | print >> sys.stderr, msg | 
|  |  | 
|  |  | 
|  | def _ValidateInputFiles(mk, manifest): | 
|  | """Verify that required variables are defined in input files. | 
|  |  | 
|  | Args: | 
|  | mk: AndroidMK object for application makefile | 
|  | manifest: AndroidManifest object for application manifest | 
|  | Raises: | 
|  | RuntimeError: mk does not define LOCAL_PACKAGE_NAME or | 
|  | manifest does not define package variable | 
|  | """ | 
|  | module_name = mk.GetVariable(mk.PACKAGE_NAME) | 
|  | if not module_name: | 
|  | raise RuntimeError("Variable %s missing from %s" % | 
|  | (mk.PACKAGE_NAME, mk.FILENAME)) | 
|  |  | 
|  | package_name = manifest.GetPackageName() | 
|  | if not package_name: | 
|  | raise RuntimeError("Variable package missing from %s" % manifest.FILENAME) | 
|  |  | 
|  |  | 
|  | def main(argv): | 
|  | options, args = _ParseArgs(argv) | 
|  | app_path = args[0]; | 
|  |  | 
|  | if not os.path.exists(app_path): | 
|  | _PrintError("Error: Application path %s not found" % app_path) | 
|  | sys.exit() | 
|  |  | 
|  | try: | 
|  | mk = android_mk.CreateAndroidMK(path=app_path) | 
|  | manifest = android_manifest.AndroidManifest(app_path=app_path) | 
|  | _ValidateInputFiles(mk, manifest) | 
|  |  | 
|  | module_name = mk.GetVariable(mk.PACKAGE_NAME) | 
|  | _GenerateTestMK(mk, app_path) | 
|  | _GenerateTestManifest(manifest, module_name) | 
|  | except Exception, e: | 
|  | _PrintError("Error: %s" % e) | 
|  | _PrintError("Error encountered, script aborted") | 
|  | sys.exit() | 
|  |  | 
|  | src_path = app_path + "/tests/src" | 
|  | if not os.path.exists(src_path): | 
|  | os.mkdir(src_path) | 
|  |  | 
|  |  | 
|  | if __name__ == "__main__": | 
|  | main(sys.argv[1:]) |