blob: 6d0de232a50249bd6de6b5fec06a4fa65282fa23 [file] [log] [blame]
#! /usr/bin/env python
"""
generate_webview_crash_tests.py
generate_webview_crash_tests.py <path_to_tests>
Specializes WebViewSecurityBaseTest.java with the appropriate values.
This script exists as an ugly hack around the lack of real parameterized testing
support. Its basic flow is:
1. Get the path to a directory containing the tests you want.
2. Copy those files to ../assets/
3. Filter those tests so that we only load the .html files (test roots).
4. For each of those, generate a test from WebViewBaseTest.java
5. Place the generated tests under src/android/webkitsecurity/cts
The process of generating the tests is very simple:
1. From each test root generate a Java-style name
2. Replace the class name and constructor name with the Java name
3. From the Java-style name generate a logtag
4. Replace the logtag with the generated logtag value
5. Replace the base path with the on-device path to the test root
6. TODO: remove the comment at the top of the base file.
"""
import re
import sys
import string
import shutil
import os.path
BASE_FILE = "WebViewBaseTest"
HOST_ASSETS_PATH = os.path.join("..", "assets")
HOST_SOURCE_PATH = os.path.join("..", "src", "android", "webkitsecurity", "cts")
DEVICE_ASSETS_PATH = ""
def print_help():
"""Prints the docstring, which is also our help text"""
print(sys.modules[__name__].__doc__)
def get_arguments():
"""Processes the only argument, ensuring it is sane before returning"""
# if we don't get the correct number of arguments
if len(sys.argv) != 2:
print("Sorry, but we need tests to run! Please see the help text below.\n")
print_help()
exit(1)
# get the argument
argument = os.path.realpath(sys.argv[1])
# if the given argument isn't a valid directory
if not os.path.isdir(argument):
print("Given path is not a directory. Please see the help text below.\n")
print_help()
exit(1)
# TODO: if the directory is empty or contains no .html files, error out.
# go home
return argument
def is_crashing_test(path):
"""Checks for the string 'crash' in the file name"""
if not path.endswith('expected.txt'):
if 'crash' in path.lower():
if 'svn' not in path.lower():
return True
return False
def get_test_paths(directory):
"""Returns a list of canonical pathnames to the files in the directory"""
canonical_test_paths = []
for top, dirs, files in os.walk(directory):
for fname in files:
name = os.path.join(top, fname)
if is_crashing_test(name):
canonical_test_paths.append(os.path.join(directory, name))
# make sure there are some
if not canonical_test_paths:
print("No test files found! Please specify some and try again.\n")
print_help()
exit(1)
# otherwise, head home
return canonical_test_paths
def copy_assets(test_files):
"""Copies each of the given test files to the host asset directory"""
for path in test_files:
shutil.copy(path, HOST_ASSETS_PATH)
def get_test_roots(test_files):
"""Filters out non-HTML files from the list, returning only entry points"""
# get all the test roots
test_roots = [t for t in test_files if t.endswith('.html')]
# if there aren't any, die
if not test_roots:
print("No test roots found! Please specify some tests.\n")
print_help()
exit(1)
# otherwise, go home
return test_roots
def read_base_test(base_file):
"""Reads in the base test file"""
with open(base_file) as f:
contents = f.read()
return contents
def get_asset_path(test):
"""Get the path to the test file on the device"""
return DEVICE_ASSETS_PATH + os.path.basename(test)
def get_java_name(test):
"""Returns a Java-style name based on the path of the test.
This is actually a surprisingly ugly thing to do. The Java convention is:
* Must start with an uppercase letter
* Must not contain the $ or whitespace
* Should be CamelCased
* Should not contain any other punctuation
To which we add the following requirements:
* Must start with 'Webkit'
* Must end with 'Test'
* Should not contain any other numerals
* Should not conflict with any other test
* Should not duplicate any words
Unfortunately, the names of the tests we're given are all across the board,
which makes this code a bit of a mess. Our basic process is to:
1. Gather the basename of the test
2. Strip its extension
3. Replace all numeric characters (9) with literal counterparts (Nine)
4. Stripping split on any undesired character
5. Capitalize the fragments
6. Verify that the first fragment is not "Webkit"
7. Verify that the last fragment is not "Test"
8. Join them
I'm sure there are remaining issues here, but this should do for now.
"""
basename = os.path.basename(test)
# note that this is fragile, but we're being conservative here
name = basename.split('.')[0]
# build the numeral-number table
nums = {'0' : "Zero",
'1' : "One",
'2' : "Two",
'3' : "Three",
'4' : "Four",
'5' : "Five",
'6' : "Six",
'7' : "Seven",
'8' : "Eight",
'9' : "Nine"}
# do our replacement
for k, v in nums.items():
name = name.replace(k, v)
# do the stripping split to obtain our fragments
undesired_chars = '[' + string.whitespace + string.punctuation + ']'
fragments = re.split(undesired_chars, name)
# capitalize each fragment
fragments = [f.capitalize() for f in fragments]
# check the first and last fragments
if fragments[0] != 'Webkit':
fragments.insert(0, 'Webkit')
if fragments[-1] != 'Test':
fragments.append('Test')
# join the results
return ''.join(fragments)
def get_device_path(test):
"""Gets the path to the asset as it will be seen from the device"""
return DEVICE_ASSETS_PATH + os.path.basename(test)
def get_host_test_path(java_name):
"""Returns the path that the generated test should be stored at"""
return os.path.join(HOST_SOURCE_PATH, java_name + '.java')
def write_test(test_contents, new_test_host_path):
"""Writes the given contents at the given path"""
with open(new_test_host_path, 'w') as f:
f.write(test_contents)
if __name__ == "__main__":
# TODO: check our location
# check_sanity()
# get our aguments
directory = get_arguments()
# turn that into a list of test pathnames
test_paths = get_test_paths(directory)
# copy those paths over to the assets dir
copy_assets(test_paths)
# filter for the .html files
test_roots = get_test_roots(test_paths)
# read the base test in
base_test = read_base_test(BASE_FILE)
# the test roots are the entry points for the tests we care about
# let's iterate over them and build the accompanying test files.
for test in test_roots:
# get the values for substitution
asset_path = get_asset_path(test)
java_name = get_java_name(test)
# get the on-device path to the test
device_test_path = get_device_path(test)
# do the actual substitution
new_test = base_test % (java_name, java_name, device_test_path, java_name)
# get the destination to write to
new_test_host_path = get_host_test_path(java_name)
# write the test
write_test(new_test, new_test_host_path)
# and we're done!