mirror of
https://github.com/google/pebble.git
synced 2025-03-15 16:51:21 +00:00
334 lines
14 KiB
Text
334 lines
14 KiB
Text
|
# FIXME: PBL-17362 Script should be build type (FW or SDK) agnostic (waf & PEP8 compliant)
|
||
|
import bitmapgen
|
||
|
import png2pblpng
|
||
|
import os
|
||
|
import re
|
||
|
import sh
|
||
|
import sys
|
||
|
import waflib
|
||
|
from waftools.pebble_test import clar
|
||
|
|
||
|
def remove_old_coverage_files(bld):
|
||
|
# Remove old .gcda files:
|
||
|
old_coverage_files = bld.path.get_bld().ant_glob('**/*.gcda lcov.info', remove=False)
|
||
|
for old_file in old_coverage_files:
|
||
|
os.remove(old_file.abspath())
|
||
|
|
||
|
def update_lcov(bld):
|
||
|
""" Update lcov-related files based on the results of `./waf test`"""
|
||
|
print "Generating code coverage information using lcov..."
|
||
|
lcov_version_cmd = ['lcov', '--version']
|
||
|
# Send stdout of checking for lcov to /dev/null to hide it; stderr will still be visible
|
||
|
with open(os.devnull, 'w') as devnull_fp:
|
||
|
ret = bld.exec_command(lcov_version_cmd, stdout=devnull_fp)
|
||
|
if ret != 0:
|
||
|
bld.fatal("Error running `lcov`. Is it installed?")
|
||
|
tests_path = bld.path.get_bld().abspath()
|
||
|
lcov_info_out_file = os.path.join(tests_path, 'lcov.info')
|
||
|
try:
|
||
|
platform_specific_lcov_args = []
|
||
|
if sys.platform.startswith('linux'):
|
||
|
platform_specific_lcov_args.extend(['--gcov-tool', 'llvm-cov'])
|
||
|
cmd = ['lcov', '--capture', '--directory', tests_path, '--output-file', lcov_info_out_file]
|
||
|
cmd += platform_specific_lcov_args
|
||
|
bld.cmd_and_log(cmd, quiet=waflib.Context.BOTH)
|
||
|
# remove unit-tests directory itself from lcov report
|
||
|
cmd = ['lcov', '--remove', lcov_info_out_file, 'tests/**', '-o', lcov_info_out_file]
|
||
|
cmd += platform_specific_lcov_args
|
||
|
bld.cmd_and_log(cmd, quiet=waflib.Context.BOTH)
|
||
|
except waflib.Errors.WafError as e:
|
||
|
print e.stdout, '\n', e.stderr
|
||
|
bld.fatal("Error running `lcov`")
|
||
|
if bld.options.coverage:
|
||
|
lcov_html_directory = os.path.join(tests_path, 'lcov-html')
|
||
|
genhtml_cmd = ['genhtml', lcov_info_out_file, '--output-directory', lcov_html_directory]
|
||
|
try:
|
||
|
bld.cmd_and_log(genhtml_cmd, quiet=waflib.Context.BOTH)
|
||
|
except waflib.Errors.WafError as e:
|
||
|
print e.stdout, '\n', e.stderr
|
||
|
bld.fatal("Error running `genhtml`")
|
||
|
index_html = os.path.join(lcov_html_directory, 'index.html')
|
||
|
print "Updated coverage report at %s" % index_html
|
||
|
|
||
|
def convert_png_to_pbi(task):
|
||
|
src_png = task.inputs[0].srcpath()
|
||
|
dest_pbi = task.outputs[0].srcpath()
|
||
|
bitdepth = None
|
||
|
|
||
|
if any(word in dest_pbi for word in ['.8bit.', '~snowy', '~spalding', '~cutts', '~robert']):
|
||
|
img_fmt = 'color_raw'
|
||
|
elif any(word in dest_pbi for word in ['.1bit.', '~tintin']):
|
||
|
img_fmt = 'bw'
|
||
|
else:
|
||
|
img_fmt = 'color' # raw and palettized color images
|
||
|
bit_suffix = re.search('(\d)bitpalette\.png', dest_pbi)
|
||
|
if bit_suffix:
|
||
|
bitdepth = int(bit_suffix.group(1))
|
||
|
|
||
|
pb = bitmapgen.PebbleBitmap(src_png, bitmap_format=img_fmt, crop=False, bitdepth=bitdepth)
|
||
|
pb.convert_to_pbi_file(dest_pbi)
|
||
|
|
||
|
def convert_png_to_pblpng(task):
|
||
|
src_png = task.inputs[0].srcpath()
|
||
|
dest_png = task.outputs[0].srcpath()
|
||
|
|
||
|
# we need to be able to skip the png generator for specific test pngs flagged 'raw'
|
||
|
# and copy over the original file
|
||
|
if dest_png.endswith('.raw.png'):
|
||
|
task.exec_command('cp -f {0} {1}'.format(task.inputs[0].abspath(), task.outputs[0].abspath()))
|
||
|
else:
|
||
|
palette_name = 'pebble64'
|
||
|
bitdepth = None
|
||
|
bit_suffix = re.search('(\d)bit(palette)?\.png', dest_png)
|
||
|
|
||
|
if bit_suffix:
|
||
|
bitdepth = int(bit_suffix.group(1))
|
||
|
elif any(word in dest_png for word in ['~snowy', '~spalding', '~cutts', '~robert']):
|
||
|
bitdepth = 8
|
||
|
elif any(word in dest_png for word in ['~tintin']):
|
||
|
bitdepth = 1
|
||
|
palette_name = 'pebble2'
|
||
|
|
||
|
png2pblpng.convert_png_to_pebble_png(src_png, dest_png,
|
||
|
palette_name=palette_name, bitdepth=bitdepth)
|
||
|
|
||
|
# Creates a job for each PNG in the test_images directory.
|
||
|
# Each of these PNGs will be converted into a PBI in the build directory.
|
||
|
# Also exports TEST_IMAGES_PATH to point to the location of the PBIs.
|
||
|
def generate_test_pbis(ctx):
|
||
|
|
||
|
test_image_pbis = []
|
||
|
|
||
|
bitmapgen_path = ctx.path.find_node('../tools/bitmapgen.py').abspath()
|
||
|
|
||
|
for png_file in ctx.path.find_node('test_images').ant_glob("*.png"):
|
||
|
dest_pbi = png_file.get_bld().change_ext('.pbi')
|
||
|
|
||
|
# if the image contains Xbit in the name, then generate both 1bit and 8bit PBI images
|
||
|
if ".Xbit." in str(dest_pbi):
|
||
|
dest_pbi = png_file.get_bld().change_ext('.1bit.pbi', '.Xbit.png')
|
||
|
ctx(name='png_to_pbi', rule=convert_png_to_pbi, source=png_file, target=dest_pbi,
|
||
|
bmp_script=bitmapgen_path)
|
||
|
test_image_pbis.append(dest_pbi)
|
||
|
|
||
|
dest_pbi = png_file.get_bld().change_ext('.8bit.pbi', '.Xbit.png')
|
||
|
ctx(name='png_to_pbi', rule=convert_png_to_pbi, source=png_file, target=dest_pbi,
|
||
|
bmp_script=bitmapgen_path)
|
||
|
test_image_pbis.append(dest_pbi)
|
||
|
else:
|
||
|
ctx(name='png_to_pbi', rule=convert_png_to_pbi, source=png_file, target=dest_pbi,
|
||
|
bmp_script=bitmapgen_path)
|
||
|
test_image_pbis.append(dest_pbi)
|
||
|
|
||
|
return test_image_pbis
|
||
|
|
||
|
# Creates a job for select PNG in the test_images directory.
|
||
|
# Each of these PNGs will be converted into a Pebble PNG8 in the build directory.
|
||
|
def generate_test_pngs(ctx):
|
||
|
|
||
|
test_image_pngs = []
|
||
|
|
||
|
pblpng_resources_list = []
|
||
|
pblpng_resources_list.extend(
|
||
|
ctx.path.find_node('test_images').ant_glob("test_png__*.png"))
|
||
|
|
||
|
for png_file in pblpng_resources_list:
|
||
|
dest_png = png_file.get_bld()
|
||
|
|
||
|
ctx(name='png_to_pblpng', rule=convert_png_to_pblpng, source=png_file, target=dest_png)
|
||
|
test_image_pngs.append(dest_png)
|
||
|
|
||
|
return test_image_pngs
|
||
|
|
||
|
def copy_test_pngs_to_build_dir(ctx):
|
||
|
test_image_pngs = []
|
||
|
|
||
|
# copy over test specific files such as png, apng
|
||
|
copy_resources_list = []
|
||
|
copy_resources_list.extend(
|
||
|
ctx.path.find_node('test_images').ant_glob("test_bitblt_circular__*.png"))
|
||
|
copy_resources_list.extend(
|
||
|
ctx.path.find_node('test_images').ant_glob("test_gbitmap_sequence__*.apng"))
|
||
|
copy_resources_list.extend(
|
||
|
ctx.path.find_node('test_images').ant_glob("test_kino_reel__*.apng"))
|
||
|
copy_resources_list.extend(
|
||
|
ctx.path.find_node('test_images').ant_glob("test_graphics_draw_text_flow__*.png"))
|
||
|
for copy_file in copy_resources_list:
|
||
|
dest_file = copy_file.get_bld()
|
||
|
ctx(name='copy_png', rule='cp -f ${SRC} ${TGT}', source=copy_file, target=dest_file)
|
||
|
test_image_pngs.append(dest_file)
|
||
|
|
||
|
return test_image_pngs
|
||
|
|
||
|
|
||
|
def copy_pdc_files_to_build_dir(ctx):
|
||
|
test_image_pdc_files = []
|
||
|
copy_resources_list = ctx.path.find_node('test_images').ant_glob("*.pdc")
|
||
|
for copy_file in copy_resources_list:
|
||
|
dest_file = copy_file.get_bld()
|
||
|
ctx(name='copy_pdc', rule='cp -f ${SRC} ${TGT}', source=copy_file, target=dest_file)
|
||
|
test_image_pdc_files.append(dest_file)
|
||
|
|
||
|
return test_image_pdc_files
|
||
|
|
||
|
|
||
|
def copy_pfo_files_to_build_dir(ctx):
|
||
|
test_image_pfo_files = []
|
||
|
copy_resources_list = ctx.path.find_node('test_images').ant_glob("*.pfo")
|
||
|
for copy_file in copy_resources_list:
|
||
|
dest_file = copy_file.get_bld()
|
||
|
ctx(name='copy_pfo', rule='cp -f ${SRC} ${TGT}', source=copy_file, target=dest_file)
|
||
|
test_image_pfo_files.append(dest_file)
|
||
|
|
||
|
return test_image_pfo_files
|
||
|
|
||
|
|
||
|
def convert_test_pdcs(ctx):
|
||
|
test_image_pdc_files = []
|
||
|
|
||
|
resources_list = ctx.path.find_node('test_images').ant_glob("*.svg")
|
||
|
resources_list.extend(ctx.path.find_node('test_images').ant_glob("*", src=False, dir=True))
|
||
|
import sys
|
||
|
sys.path.insert(0, ctx.path.parent.abspath())
|
||
|
|
||
|
from tools.generate_pdcs import pdc_gen
|
||
|
def convert_svg_image(task):
|
||
|
pdc_gen.create_pdc_from_path(
|
||
|
task.inputs[0].abspath(),
|
||
|
task.outputs[0].abspath(),
|
||
|
viewbox_size=(0, 0),
|
||
|
verbose=False,
|
||
|
duration=0,
|
||
|
play_count=0)
|
||
|
|
||
|
def convert_svg_sequence(task):
|
||
|
dir_name = os.path.dirname(task.inputs[0].abspath())
|
||
|
pdc_gen.create_pdc_from_path(
|
||
|
dir_name,
|
||
|
task.outputs[0].abspath(),
|
||
|
viewbox_size=(0, 0),
|
||
|
verbose=False,
|
||
|
duration=33,
|
||
|
play_count=1)
|
||
|
|
||
|
for input_node in resources_list:
|
||
|
output_pdc = input_node.get_bld().change_ext('.pdc')
|
||
|
|
||
|
test_image_pdc_files.append(output_pdc)
|
||
|
if os.path.isdir(input_node.abspath()):
|
||
|
conversion_rule = convert_svg_sequence
|
||
|
source_files = input_node.ant_glob("*.svg")
|
||
|
else:
|
||
|
conversion_rule = convert_svg_image
|
||
|
source_files = [input_node]
|
||
|
|
||
|
ctx(rule=conversion_rule,
|
||
|
source=source_files,
|
||
|
target=output_pdc)
|
||
|
|
||
|
return test_image_pdc_files
|
||
|
|
||
|
|
||
|
def convert_pdc_to_pbi(ctx):
|
||
|
bitmapgen_path = ctx.path.find_node('../tools/bitmapgen.py').abspath()
|
||
|
|
||
|
test_pdc_pbis = []
|
||
|
|
||
|
pdc_files = ctx.path.find_node('test_images').ant_glob("test_pdc__*.pdc")
|
||
|
pdc2png = ctx.path.get_bld().parent.make_node('pdc2png')
|
||
|
|
||
|
for pdc in pdc_files:
|
||
|
dest_pdc = pdc.get_bld().change_ext('.pdc.pdc')
|
||
|
src_png = dest_pdc.change_ext('.png')
|
||
|
dest_pbi = dest_pdc.change_ext('.pbi')
|
||
|
ctx(rule='cp ${SRC} ${TGT}', source=pdc, target=dest_pdc)
|
||
|
ctx(rule='${SRC[0].abspath()} ${SRC[1].abspath()}', source=[pdc2png, dest_pdc], target=src_png)
|
||
|
ctx(rule=convert_png_to_pbi, source=src_png, target=dest_pbi, bmp_script=bitmapgen_path)
|
||
|
test_pdc_pbis.append(dest_pbi)
|
||
|
|
||
|
return test_pdc_pbis
|
||
|
|
||
|
def options(opt):
|
||
|
gr = opt.add_option_group('test options')
|
||
|
gr.add_option('-D', '--debug_test', action='store_true',
|
||
|
help='Execute tests within GDB. Use alongside -M.')
|
||
|
gr.add_option('-M', '--match', dest='regex', default=None, action='store',
|
||
|
help='Run regex match tests. Example: ./waf test -M "test.*resource.*"')
|
||
|
gr.add_option('-L', '--list_tests', dest='list_tests', action='store_true',
|
||
|
help='List all test names. Usually used in conjunction with -M. Example: '
|
||
|
'./waf test -M test_animation -L')
|
||
|
gr.add_option('-T', '--test_name', dest='test_name', default=None, action='store',
|
||
|
help='Run only the given test name. Usually used in conjunction with -M. Example: '
|
||
|
'./waf test -M test_animation -T unschedule')
|
||
|
gr.add_option('-C', '--coverage', dest='coverage', action='store_true', help='Generate gcov test coverage data and use lcov to generate HTML report')
|
||
|
gr.add_option('--show_output', action='store_true', help='show test output')
|
||
|
gr.add_option('--no_run', action='store_true', help='Do not run the tests, just build them')
|
||
|
gr.add_option('--no_images', action='store_true', help='skip generation of test images, '
|
||
|
'which are only required for some tests and can slow down build times')
|
||
|
|
||
|
def build(bld):
|
||
|
if bld.options.debug_test:
|
||
|
if not bld.options.regex:
|
||
|
bld.fatal('When using --debug_test, you must also use --match to'
|
||
|
' specify the test file to debug')
|
||
|
bld.env.append_value('DEFINES', 'UNITTEST_DEBUG')
|
||
|
|
||
|
bld.env.CFLAGS.append('-I' + bld.path.abspath() + '/../src/fw/util/time')
|
||
|
bld.env.CFLAGS.append('-I' + bld.path.abspath() + '/../src/include')
|
||
|
|
||
|
# clang on Linux errors on true == true or false == false compile-time assertions
|
||
|
bld.env.CFLAGS.append('-Wno-tautological-compare')
|
||
|
|
||
|
# time_t is defined in sys/types in newlib, and time.h on recent Linux
|
||
|
# so just force the defined type for testing time
|
||
|
bld.env.CFLAGS.append('-Dtime_t=__SYSCALL_SLONG_TYPE')
|
||
|
|
||
|
# Many tests operate on a set of test images and require tools to process these
|
||
|
# images and therefore need extra defines. Set up our environment first before running any
|
||
|
# tests.
|
||
|
test_images_dest_dir = bld.path.find_node('test_images').get_bld()
|
||
|
|
||
|
# Set up the fail directory, and make it. This is used to output data from the tests for
|
||
|
# comparison with the expected results.
|
||
|
fail_dir = test_images_dest_dir.parent.make_node('failed')
|
||
|
fail_path = fail_dir.abspath().strip()
|
||
|
sh.rm('-rf', fail_path)
|
||
|
fail_dir.mkdir()
|
||
|
|
||
|
def convert_to_emscripten_fs_path_if_needed(node):
|
||
|
real_fs_abspath = node.abspath()
|
||
|
if bld.variant != 'test_rocky_emx':
|
||
|
return real_fs_abspath
|
||
|
# When transpiling unittests with Emscripten, the host machine's
|
||
|
# filesystem is mounted at /node_fs, so we need to translate paths.
|
||
|
return '/node_fs' + real_fs_abspath
|
||
|
|
||
|
bld.env.test_image_defines = [
|
||
|
'TEST_IMAGES_PATH="%s"' % convert_to_emscripten_fs_path_if_needed(test_images_dest_dir),
|
||
|
'TEST_OUTPUT_PATH="%s"' % convert_to_emscripten_fs_path_if_needed(fail_dir),
|
||
|
'PBI2PNG_EXE="%s"' % bld.path.find_node('../tools/pbi2png.py').abspath()]
|
||
|
|
||
|
# Add test_pbis or test_pngs to runtime_deps for tests that require them
|
||
|
if not bld.options.no_images:
|
||
|
bld.env.test_pbis = generate_test_pbis(bld)
|
||
|
bld.env.test_pngs = copy_test_pngs_to_build_dir(bld)
|
||
|
bld.env.test_pngs.extend(generate_test_pngs(bld))
|
||
|
bld.env.test_pfos = copy_pfo_files_to_build_dir(bld)
|
||
|
# Includes reference pdc and pbi generated from ref png
|
||
|
bld.env.test_pdcs = bld.env.test_pbis + convert_test_pdcs(bld) + copy_pdc_files_to_build_dir(bld)
|
||
|
bld.env.pdcs2png_test_files = bld.env.test_pbis + convert_pdc_to_pbi(bld)
|
||
|
|
||
|
if bld.options.coverage:
|
||
|
bld.env.append_value('CFLAGS', '-fprofile-arcs')
|
||
|
bld.env.append_value('CFLAGS', '-ftest-coverage')
|
||
|
bld.env.append_value('LINKFLAGS', '--coverage')
|
||
|
test_wscript_dirs = [os.path.dirname(f.abspath()) for f in bld.path.ant_glob('**/wscript')]
|
||
|
for dir in test_wscript_dirs:
|
||
|
bld.recurse(dir)
|
||
|
if bld.options.coverage:
|
||
|
bld.add_pre_fun(remove_old_coverage_files)
|
||
|
bld.add_post_fun(update_lcov)
|
||
|
|
||
|
|
||
|
# vim:filetype=python
|