pebble/tests/wscript
2025-01-27 11:38:16 -08:00

333 lines
14 KiB
Python

# 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