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 21 import datetime 22 import optparse 23 import os 24 import string 25 import sys 26 27 # local imports 28 import android_mk 29 import android_manifest 30 31 32 class 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) 67 include $$(CLEAR_VARS) 68 69 LOCAL_MODULE_TAGS := tests 70 71 LOCAL_JAVA_LIBRARIES := android.test.runner 72 73 LOCAL_SRC_FILES := $$(call all-java-files-under, src) 74 75 LOCAL_PACKAGE_NAME := ${MODULE_NAME}Tests${CERTIFICATE} 76 77 LOCAL_INSTRUMENTATION_FOR := ${MODULE_NAME} 78 79 LOCAL_SDK_VERSION := current 80 81 include $$(BUILD_PACKAGE) 82 """ 83 TESTS_FOLDER = "tests" 84 85 86 def _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.app_path, 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 124 def _GenerateTestMK(mk, 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 mapping: optional user defined mapping of variable values, replaces 132 values stored in mk 133 Raises: 134 IOError: tests/Android.mk cannot be opened for writing 135 """ 136 # skip if file already exists 137 tests_path = "%s/%s" % (mk.app_path, TestsConsts.TESTS_FOLDER) 138 tests_mk_path = "%s/%s" % (tests_path, mk.FILENAME) 139 if os.path.exists(tests_mk_path): 140 _PrintMessage("%s already exists, not overwritten" % tests_mk_path) 141 return 142 143 # append test build if not existent in makefile 144 if not mk.HasInclude(TestsConsts.MK_BUILD_INCLUDE): 145 mk_path = "%s/%s" % (mk.app_path, mk.FILENAME) 146 mk_file = open(mk_path, mode="a") 147 mk_file.write(TestsConsts.MK_BUILD_STRING) 148 mk_file.close() 149 150 # construct tests/Android.mk 151 # include certificate definition if existent in makefile 152 certificate = mk.GetVariable(mk.CERTIFICATE) 153 if certificate: 154 cert_definition = ("\n%s := %s" % (mk.CERTIFICATE, certificate)) 155 else: 156 cert_definition = "" 157 if not mapping: 158 module_name = mk.GetVariable(mk.PACKAGE_NAME) 159 mapping = {"MODULE_NAME":module_name, "CERTIFICATE":cert_definition} 160 output = string.Template(TestsConsts.TEST_MK_TEMPLATE).substitute(mapping) 161 162 # create tests folder if not existent 163 if not os.path.exists(tests_path): 164 os.mkdir(tests_path) 165 166 # write tests/Android.mk to disk 167 tests_mk = open(tests_mk_path, mode="w") 168 tests_mk.write(output) 169 tests_mk.close() 170 _PrintMessage("Created %s" % tests_mk_path) 171 172 173 def _ParseArgs(argv): 174 """Parse the command line arguments. 175 176 Args: 177 argv: the list of command line arguments 178 Returns: 179 a tuple of options and individual command line arguments. 180 """ 181 parser = optparse.OptionParser(usage="%s <app_path>" % sys.argv[0]) 182 options, args = parser.parse_args(argv) 183 if len(args) < 1: 184 _PrintError("Error: Incorrect syntax") 185 parser.print_usage() 186 sys.exit() 187 return (options, args) 188 189 190 def _PrintMessage(msg): 191 print >> sys.stdout, msg 192 193 194 def _PrintError(msg): 195 print >> sys.stderr, msg 196 197 198 def _ValidateInputFiles(mk, manifest): 199 """Verify that required variables are defined in input files. 200 201 Args: 202 mk: AndroidMK object for application makefile 203 manifest: AndroidManifest object for application manifest 204 Raises: 205 RuntimeError: mk does not define LOCAL_PACKAGE_NAME or 206 manifest does not define package variable 207 """ 208 module_name = mk.GetVariable(mk.PACKAGE_NAME) 209 if not module_name: 210 raise RuntimeError("Variable %s missing from %s" % 211 (mk.PACKAGE_NAME, mk.FILENAME)) 212 213 package_name = manifest.GetPackageName() 214 if not package_name: 215 raise RuntimeError("Variable package missing from %s" % manifest.FILENAME) 216 217 218 def main(argv): 219 options, args = _ParseArgs(argv) 220 app_path = args[0]; 221 222 if not os.path.exists(app_path): 223 _PrintError("Error: Application path %s not found" % app_path) 224 sys.exit() 225 226 try: 227 mk = android_mk.AndroidMK(app_path=app_path) 228 manifest = android_manifest.AndroidManifest(app_path=app_path) 229 _ValidateInputFiles(mk, manifest) 230 231 module_name = mk.GetVariable(mk.PACKAGE_NAME) 232 _GenerateTestMK(mk) 233 _GenerateTestManifest(manifest, module_name) 234 except Exception, e: 235 _PrintError("Error: %s" % e) 236 _PrintError("Error encountered, script aborted") 237 sys.exit() 238 239 src_path = app_path + "/tests/src" 240 if not os.path.exists(src_path): 241 os.mkdir(src_path) 242 243 244 if __name__ == "__main__": 245 main(sys.argv[1:]) 246