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