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, 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