Home | History | Annotate | Download | only in testrunner
      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.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 
    124 def _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 
    174 def _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 
    191 def _PrintMessage(msg):
    192   print >> sys.stdout, msg
    193 
    194 
    195 def _PrintError(msg):
    196   print >> sys.stderr, msg
    197 
    198 
    199 def _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 
    219 def 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 
    245 if __name__ == "__main__":
    246   main(sys.argv[1:])
    247