| #!/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.app_path, 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, 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 |
| 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" % (mk.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" % (mk.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.AndroidMK(app_path=app_path) |
| manifest = android_manifest.AndroidManifest(app_path=app_path) |
| _ValidateInputFiles(mk, manifest) |
| |
| module_name = mk.GetVariable(mk.PACKAGE_NAME) |
| _GenerateTestMK(mk) |
| _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:]) |