#!/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:])