1#!/usr/bin/python2.4 2# 3# 4# Copyright 2009, The Android Open Source Project 5# 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17 18"""Utility to create Android project files for tests.""" 19 20# python imports 21import datetime 22import optparse 23import os 24import string 25import sys 26 27# local imports 28import android_mk 29import android_manifest 30 31 32class TestsConsts(object): 33 """Constants for test Android.mk and AndroidManifest.xml creation.""" 34 35 MK_BUILD_INCLUDE = "call all-makefiles-under,$(LOCAL_PATH)" 36 MK_BUILD_STRING = "\ninclude $(%s)\n" % MK_BUILD_INCLUDE 37 TEST_MANIFEST_TEMPLATE = """<?xml version="1.0" encoding="utf-8"?> 38<!-- Copyright (C) $YEAR The Android Open Source Project 39 40 Licensed under the Apache License, Version 2.0 (the "License"); 41 you may not use this file except in compliance with the License. 42 You may obtain a copy of the License at 43 44 http://www.apache.org/licenses/LICENSE-2.0 45 46 Unless required by applicable law or agreed to in writing, software 47 distributed under the License is distributed on an "AS IS" BASIS, 48 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 49 See the License for the specific language governing permissions and 50 limitations under the License. 51--> 52 53<manifest xmlns:android="http://schemas.android.com/apk/res/android" 54 package="$PACKAGE_NAME.tests"> 55 56 <application> 57 <uses-library android:name="android.test.runner" /> 58 </application> 59 60 <instrumentation android:name="android.test.InstrumentationTestRunner" 61 android:targetPackage="$PACKAGE_NAME" 62 android:label="Tests for $MODULE_NAME"> 63 </instrumentation> 64</manifest> 65""" 66 TEST_MK_TEMPLATE = """LOCAL_PATH := $$(call my-dir) 67include $$(CLEAR_VARS) 68 69LOCAL_MODULE_TAGS := tests 70 71LOCAL_JAVA_LIBRARIES := android.test.runner 72 73LOCAL_SRC_FILES := $$(call all-java-files-under, src) 74 75LOCAL_PACKAGE_NAME := ${MODULE_NAME}Tests${CERTIFICATE} 76 77LOCAL_INSTRUMENTATION_FOR := ${MODULE_NAME} 78 79LOCAL_SDK_VERSION := current 80 81include $$(BUILD_PACKAGE) 82""" 83 TESTS_FOLDER = "tests" 84 85 86def _GenerateTestManifest(manifest, module_name, mapping=None): 87 """Create and populate tests/AndroidManifest.xml with variable values from 88 Android.mk and AndroidManifest.xml. 89 90 Does nothing if tests/AndroidManifest.xml already exists. 91 92 Args: 93 manifest: AndroidManifest object for application manifest 94 module_name: module name used for labelling 95 mapping: optional user defined mapping of variable values, replaces values 96 extracted from AndroidManifest.xml 97 Raises: 98 IOError: tests/AndroidManifest.xml cannot be opened for writing 99 """ 100 # skip if file already exists 101 tests_path = "%s/%s" % (manifest.GetAppPath(), TestsConsts.TESTS_FOLDER) 102 tests_manifest_path = "%s/%s" % (tests_path, manifest.FILENAME) 103 if os.path.exists(tests_manifest_path): 104 _PrintMessage("%s already exists, not overwritten" % tests_manifest_path) 105 return 106 107 if not mapping: 108 package_name = manifest.GetPackageName() 109 mapping = {"PACKAGE_NAME":package_name, "MODULE_NAME":module_name, 110 "YEAR":datetime.date.today().year} 111 output = string.Template(TestsConsts.TEST_MANIFEST_TEMPLATE).substitute(mapping) 112 113 # create tests folder if not existent 114 if not os.path.exists(tests_path): 115 os.mkdir(tests_path) 116 117 # write tests/AndroidManifest.xml 118 tests_manifest = open(tests_manifest_path, mode="w") 119 tests_manifest.write(output) 120 tests_manifest.close() 121 _PrintMessage("Created %s" % tests_manifest_path) 122 123 124def _GenerateTestMK(mk, app_path, mapping=None): 125 """Create and populate tests/Android.mk with variable values from Android.mk. 126 127 Does nothing if tests/Android.mk already exists. 128 129 Args: 130 mk: AndroidMK object for application makefile 131 app_path: path to the application being tested 132 mapping: optional user defined mapping of variable values, replaces 133 values stored in mk 134 Raises: 135 IOError: tests/Android.mk cannot be opened for writing 136 """ 137 # skip if file already exists 138 tests_path = "%s/%s" % (app_path, TestsConsts.TESTS_FOLDER) 139 tests_mk_path = "%s/%s" % (tests_path, mk.FILENAME) 140 if os.path.exists(tests_mk_path): 141 _PrintMessage("%s already exists, not overwritten" % tests_mk_path) 142 return 143 144 # append test build if not existent in makefile 145 if not mk.HasInclude(TestsConsts.MK_BUILD_INCLUDE): 146 mk_path = "%s/%s" % (app_path, mk.FILENAME) 147 mk_file = open(mk_path, mode="a") 148 mk_file.write(TestsConsts.MK_BUILD_STRING) 149 mk_file.close() 150 151 # construct tests/Android.mk 152 # include certificate definition if existent in makefile 153 certificate = mk.GetVariable(mk.CERTIFICATE) 154 if certificate: 155 cert_definition = ("\n%s := %s" % (mk.CERTIFICATE, certificate)) 156 else: 157 cert_definition = "" 158 if not mapping: 159 module_name = mk.GetVariable(mk.PACKAGE_NAME) 160 mapping = {"MODULE_NAME":module_name, "CERTIFICATE":cert_definition} 161 output = string.Template(TestsConsts.TEST_MK_TEMPLATE).substitute(mapping) 162 163 # create tests folder if not existent 164 if not os.path.exists(tests_path): 165 os.mkdir(tests_path) 166 167 # write tests/Android.mk to disk 168 tests_mk = open(tests_mk_path, mode="w") 169 tests_mk.write(output) 170 tests_mk.close() 171 _PrintMessage("Created %s" % tests_mk_path) 172 173 174def _ParseArgs(argv): 175 """Parse the command line arguments. 176 177 Args: 178 argv: the list of command line arguments 179 Returns: 180 a tuple of options and individual command line arguments. 181 """ 182 parser = optparse.OptionParser(usage="%s <app_path>" % sys.argv[0]) 183 options, args = parser.parse_args(argv) 184 if len(args) < 1: 185 _PrintError("Error: Incorrect syntax") 186 parser.print_usage() 187 sys.exit() 188 return (options, args) 189 190 191def _PrintMessage(msg): 192 print >> sys.stdout, msg 193 194 195def _PrintError(msg): 196 print >> sys.stderr, msg 197 198 199def _ValidateInputFiles(mk, manifest): 200 """Verify that required variables are defined in input files. 201 202 Args: 203 mk: AndroidMK object for application makefile 204 manifest: AndroidManifest object for application manifest 205 Raises: 206 RuntimeError: mk does not define LOCAL_PACKAGE_NAME or 207 manifest does not define package variable 208 """ 209 module_name = mk.GetVariable(mk.PACKAGE_NAME) 210 if not module_name: 211 raise RuntimeError("Variable %s missing from %s" % 212 (mk.PACKAGE_NAME, mk.FILENAME)) 213 214 package_name = manifest.GetPackageName() 215 if not package_name: 216 raise RuntimeError("Variable package missing from %s" % manifest.FILENAME) 217 218 219def main(argv): 220 options, args = _ParseArgs(argv) 221 app_path = args[0]; 222 223 if not os.path.exists(app_path): 224 _PrintError("Error: Application path %s not found" % app_path) 225 sys.exit() 226 227 try: 228 mk = android_mk.CreateAndroidMK(path=app_path) 229 manifest = android_manifest.AndroidManifest(app_path=app_path) 230 _ValidateInputFiles(mk, manifest) 231 232 module_name = mk.GetVariable(mk.PACKAGE_NAME) 233 _GenerateTestMK(mk, app_path) 234 _GenerateTestManifest(manifest, module_name) 235 except Exception, e: 236 _PrintError("Error: %s" % e) 237 _PrintError("Error encountered, script aborted") 238 sys.exit() 239 240 src_path = app_path + "/tests/src" 241 if not os.path.exists(src_path): 242 os.mkdir(src_path) 243 244 245if __name__ == "__main__": 246 main(sys.argv[1:]) 247