Flutter Engine
The Flutter Engine
Functions | Variables
Package test

Functions

def Main ()
 
def test_steps (api)
 
def RunSteps (api)
 
def GenTests (api)
 
def fail_tests (font_subset)
 
def run_cmd (cmd, codepoints, fail=False)
 
def test_zip (font_subset_zip, exe)
 
def platform_to_path (os, cpu)
 
def main ()
 

Variables

string PYTHON_VERSION_COMPATIBILITY = "PY3"
 
list DEPS
 
string DM_JSON = 'dm.json'
 
list TEST_BUILDERS
 
 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
 
 SRC_DIR = os.path.normpath(os.path.join(SCRIPT_DIR, '..', '..', '..'))
 
 MATERIAL_TTF = os.path.join(SCRIPT_DIR, 'fixtures', 'MaterialIcons-Regular.ttf')
 
 VARIABLE_MATERIAL_TTF = os.path.join(SCRIPT_DIR, 'fixtures', 'MaterialSymbols-Variable.ttf')
 
tuple COMPARE_TESTS
 

Function Documentation

◆ fail_tests()

def test.fail_tests (   font_subset)

Definition at line 66 of file test.py.

66def fail_tests(font_subset):
67 return [
68 ([font_subset, 'output.ttf', 'does-not-exist.ttf'], [
69 '1',
70 ]), # non-existent input font
71 ([font_subset, 'output.ttf', MATERIAL_TTF], [
72 '0xFFFFFFFF',
73 ]), # Value too big.
74 ([font_subset, 'output.ttf', MATERIAL_TTF], [
75 '-1',
76 ]), # invalid value
77 ([font_subset, 'output.ttf', MATERIAL_TTF], [
78 'foo',
79 ]), # no valid values
80 ([font_subset, 'output.ttf', MATERIAL_TTF], [
81 '0xE003',
82 '0x12',
83 '0xE004',
84 ]), # codepoint not in font
85 ([font_subset, 'non-existent-dir/output.ttf', MATERIAL_TTF], [
86 '0xE003',
87 ]), # dir doesn't exist
88 ([font_subset, 'output.ttf', MATERIAL_TTF], [
89 ' ',
90 ]), # empty input
91 ([font_subset, 'output.ttf', MATERIAL_TTF], []), # empty input
92 ([font_subset, 'output.ttf', MATERIAL_TTF], ['']), # empty input
93 # repeat tests with variable input font
94 ([font_subset, 'output.ttf', VARIABLE_MATERIAL_TTF], [
95 '0xFFFFFFFF',
96 ]), # Value too big.
97 ([font_subset, 'output.ttf', VARIABLE_MATERIAL_TTF], [
98 '-1',
99 ]), # invalid value
100 ([font_subset, 'output.ttf', VARIABLE_MATERIAL_TTF], [
101 'foo',
102 ]), # no valid values
103 ([font_subset, 'output.ttf', VARIABLE_MATERIAL_TTF], [
104 '0xE003',
105 '0x12',
106 '0xE004',
107 ]), # codepoint not in font
108 ([font_subset, 'non-existent-dir/output.ttf', VARIABLE_MATERIAL_TTF], [
109 '0xE003',
110 ]), # dir doesn't exist
111 ([font_subset, 'output.ttf', VARIABLE_MATERIAL_TTF], [
112 ' ',
113 ]), # empty input
114 ([font_subset, 'output.ttf', VARIABLE_MATERIAL_TTF], []), # empty input
115 ([font_subset, 'output.ttf', VARIABLE_MATERIAL_TTF], ['']), # empty input
116 ]
117
118
def fail_tests(font_subset)
Definition: test.py:66

◆ GenTests()

def test.GenTests (   api)

Definition at line 157 of file test.py.

157def GenTests(api):
158 for builder in TEST_BUILDERS:
159 props = dict(
160 buildername=builder,
161 buildbucket_build_id='123454321',
162 dm_flags='["dm","--example","--flags"]',
163 dm_properties=('{"key1":"value1","key2":"",'
164 '"bot":"${SWARMING_BOT_ID}",'
165 '"task":"${SWARMING_TASK_ID}"}'),
166 revision='abc123',
167 gs_bucket='skia-infra-gm',
168 patch_ref='89/456789/12',
169 patch_set=7,
170 patch_issue=1234,
171 path_config='kitchen',
172 gold_hashes_url='https://example.com/hashes.txt',
173 swarm_out_dir='[SWARM_OUT_DIR]',
174 task_id='task_12345',
175 resources='true',
176 )
177 if 'ASAN' not in builder:
178 props['do_upload'] = 'true'
179 if 'Lottie' in builder:
180 props['lotties'] = 'true'
181 else:
182 props['images'] = 'true'
183 props['skps'] = 'true'
184 props['svgs'] = 'true'
185 test = (
186 api.test(builder) +
187 api.properties(**props) +
188 api.path.exists(
189 api.path.start_dir.join('skia'),
190 api.path.start_dir.join('skia', 'infra', 'bots', 'assets',
191 'skimage', 'VERSION'),
192 api.path.start_dir.join('skia', 'infra', 'bots', 'assets',
193 'skp', 'VERSION'),
194 api.path.start_dir.join('skia', 'infra', 'bots', 'assets',
195 'svg', 'VERSION'),
196 api.path.start_dir.join('tmp', 'uninteresting_hashes.txt')
197 ) +
198 api.step_data('get swarming bot id',
199 stdout=api.raw_io.output('skia-bot-123')) +
200 api.step_data('get swarming task id',
201 stdout=api.raw_io.output('123456'))
202 )
203 if 'Win' in builder:
204 test += api.platform('win', 64)
205
206 yield test
def GenTests(api)
Definition: test.py:157

◆ Main()

def test.Main ( )

Definition at line 15 of file test.py.

15def Main():
16 args = sys.argv[1:]
17
18 cleanup_dart = False
19 if '--cleanup-dart-processes' in args:
20 args.remove('--cleanup-dart-processes')
21 cleanup_dart = True
22
23 tools_dir = os.path.dirname(os.path.realpath(__file__))
24 repo_dir = os.path.dirname(tools_dir)
25 dart_test_script = os.path.join(repo_dir, 'pkg', 'test_runner', 'bin',
26 'test_runner.dart')
27 command = [utils.CheckedInSdkExecutable(), dart_test_script] + args
28
29 # The testing script potentially needs the android platform tools in PATH so
30 # we do that in ./tools/test.py (a similar logic exists in ./tools/build.py).
31 android_platform_tools = os.path.normpath(
32 os.path.join(tools_dir,
33 '../third_party/android_tools/sdk/platform-tools'))
34 if os.path.isdir(android_platform_tools):
35 os.environ['PATH'] = '%s%s%s' % (os.environ['PATH'], os.pathsep,
36 android_platform_tools)
37
39 with ExitStack() as stack:
40 for ctx in utils.CoreDumpArchiver(args):
41 stack.enter_context(ctx)
42 exit_code = subprocess.call(command)
43
44 if cleanup_dart:
45 cleanup_command = [
46 sys.executable,
47 os.path.join(tools_dir, 'task_kill.py'), '--kill_dart=True',
48 '--kill_vc=False'
49 ]
50 subprocess.call(cleanup_command)
51
52 utils.DiagnoseExitCode(exit_code, command)
53 return exit_code
54
55
def Main()
Definition: test.py:15
def CoreDumpArchiver(args)
Definition: utils.py:973
def DiagnoseExitCode(exit_code, command)
Definition: utils.py:492
def FileDescriptorLimitIncreaser()
Definition: utils.py:995
def CheckedInSdkExecutable()
Definition: utils.py:504

◆ main()

def test.main ( )

Definition at line 167 of file test.py.

167def main():
168 parser = argparse.ArgumentParser(description='Runs font-subset tests.')
169 parser.add_argument('--variant', type=str, required=True)
170 parser.add_argument('--target-cpu', type=str, default='x64')
171 args = parser.parse_args()
172 variant = args.variant
173
174 is_windows = sys.platform.startswith(('cygwin', 'win'))
175 exe = '.exe' if is_windows else ''
176 font_subset = os.path.join(SRC_DIR, 'out', variant, 'font-subset' + exe)
177 font_subset_zip = os.path.join(
178 SRC_DIR, 'out', variant, 'zip_archives', platform_to_path(sys.platform, args.target_cpu),
179 'font-subset.zip'
180 )
181 if not os.path.isfile(font_subset):
182 raise Exception(
183 'Could not locate font-subset%s in %s - build before running this script.' % (exe, variant)
184 )
185
186 print('Using font subset binary at %s (%s)' % (font_subset, font_subset_zip))
187 failures = 0
188
189 failures += test_zip(font_subset_zip, exe)
190
191 for should_pass, golden_font, input_font, codepoints in COMPARE_TESTS:
192 gen_ttf = os.path.join(SCRIPT_DIR, 'gen', golden_font)
193 golden_ttf = os.path.join(SCRIPT_DIR, 'fixtures', golden_font)
194 cmd = [font_subset, gen_ttf, input_font]
195 run_cmd(cmd, codepoints)
196 cmp = filecmp.cmp(gen_ttf, golden_ttf, shallow=False)
197 if (should_pass and not cmp) or (not should_pass and cmp):
198 print('Test case %s failed.' % cmd)
199 failures += 1
200
201 with open(os.devnull, 'w') as devnull:
202 for cmd, codepoints in fail_tests(font_subset):
203 if run_cmd(cmd, codepoints, fail=True) == 0:
204 failures += 1
205
206 if failures > 0:
207 print('%s test(s) failed.' % failures)
208 return 1
209
210 print('All tests passed')
211 return 0
212
213
def print(*args, **kwargs)
Definition: run_tests.py:49
def test_zip(font_subset_zip, exe)
Definition: test.py:145
def platform_to_path(os, cpu)
Definition: test.py:155
def main()
Definition: test.py:167
def run_cmd(cmd, codepoints, fail=False)
Definition: test.py:119

◆ platform_to_path()

def test.platform_to_path (   os,
  cpu 
)

Definition at line 155 of file test.py.

155def platform_to_path(os, cpu):
156 d = {
157 'darwin': 'darwin-',
158 'linux': 'linux-',
159 'linux2': 'linux-',
160 'cygwin': 'windows-',
161 'win': 'windows-',
162 'win32': 'windows-',
163 }
164 return d[os] + cpu
165
166

◆ run_cmd()

def test.run_cmd (   cmd,
  codepoints,
  fail = False 
)

Definition at line 119 of file test.py.

119def run_cmd(cmd, codepoints, fail=False):
120 print('Running command:')
121 print(' %s' % ' '.join(cmd))
122 print('STDIN: "%s"' % ' '.join(codepoints))
123 p = subprocess.Popen(
124 cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, cwd=SRC_DIR
125 )
126 stdout_data, stderr_data = p.communicate(input=' '.join(codepoints).encode())
127 if p.returncode != 0 and fail == False:
128 print('FAILURE: %s' % p.returncode)
129 print('STDOUT:')
130 print(stdout_data)
131 print('STDERR:')
132 print(stderr_data)
133 elif p.returncode == 0 and fail == True:
134 print('FAILURE - test passed but should have failed.')
135 print('STDOUT:')
136 print(stdout_data)
137 print('STDERR:')
138 print(stderr_data)
139 else:
140 print('Success.')
141
142 return p.returncode
143
144
static void encode(uint8_t output[16], const uint32_t input[4])
Definition: SkMD5.cpp:240
static SkString join(const CommandLineFlags::StringArray &)
Definition: skpbench.cpp:741

◆ RunSteps()

def test.RunSteps (   api)

Definition at line 136 of file test.py.

136def RunSteps(api):
137 api.vars.setup()
138 api.file.ensure_directory('makedirs tmp_dir', api.vars.tmp_dir)
139 api.flavor.setup('dm')
140
141 try:
142 test_steps(api)
143 finally:
144 api.flavor.cleanup_steps()
145 api.run.check_failure()
146
147
def RunSteps(api)
Definition: test.py:136
def test_steps(api)
Definition: test.py:30

◆ test_steps()

def test.test_steps (   api)
Run the DM test.

Definition at line 30 of file test.py.

30def test_steps(api):
31 """Run the DM test."""
32 do_upload = api.properties.get('do_upload') == 'true'
33 images = api.properties.get('images') == 'true'
34 lotties = api.properties.get('lotties') == 'true'
35 resources = api.properties.get('resources') == 'true'
36 skps = api.properties.get('skps') == 'true'
37 svgs = api.properties.get('svgs') == 'true'
38
39 api.flavor.install(
40 images=images,
41 lotties=lotties,
42 resources=resources,
43 skps=skps,
44 svgs=svgs,
45 )
46
47 use_hash_file = False
48 if do_upload:
49 host_dm_dir = str(api.flavor.host_dirs.dm_dir)
50 api.flavor.create_clean_host_dir(api.path.start_dir.join('test'))
51 device_dm_dir = str(api.flavor.device_dirs.dm_dir)
52 if host_dm_dir != device_dm_dir:
53 api.flavor.create_clean_device_dir(device_dm_dir)
54
55 # Obtain the list of already-generated hashes.
56 hash_filename = 'uninteresting_hashes.txt'
57
58 host_hashes_file = api.vars.tmp_dir.join(hash_filename)
59 hashes_file = api.flavor.device_path_join(
60 api.flavor.device_dirs.tmp_dir, hash_filename)
61 script = api.gold_upload.resource('get_uninteresting_hashes.py')
62 api.run(
63 api.step,
64 'get uninteresting hashes',
65 cmd=['python3', script, api.properties['gold_hashes_url'],
66 host_hashes_file],
67 # If this fails, we want to know about it because it means Gold is down
68 # and proceeding onwards would take a very long time, but be hard to notice.
69 abort_on_failure=True,
70 fail_build_on_failure=True,
71 infra_step=True)
72
73 if api.path.exists(host_hashes_file):
74 api.flavor.copy_file_to_device(host_hashes_file, hashes_file)
75 use_hash_file = True
76
77 # Find DM flags.
78 args = json.loads(api.properties['dm_flags'])
79 props = json.loads(api.properties['dm_properties'])
80 args.append('--properties')
81 # Map iteration order is arbitrary; in order to maintain a consistent step
82 # ordering, sort by key.
83 for k in sorted(props.keys()):
84 v = props[k]
85 if v == '${SWARMING_BOT_ID}':
86 v = api.vars.swarming_bot_id
87 elif v == '${SWARMING_TASK_ID}':
88 v = api.vars.swarming_task_id
89 if v != '':
90 args.extend([k, v])
91
92 # Paths to required resources.
93 if resources:
94 args.extend(['--resourcePath', api.flavor.device_dirs.resource_dir])
95 if skps:
96 args.extend(['--skps', api.flavor.device_dirs.skp_dir])
97 if images:
98 args.extend([
99 '--images', api.flavor.device_path_join(
100 api.flavor.device_dirs.images_dir, 'dm'),
101 '--colorImages', api.flavor.device_path_join(
102 api.flavor.device_dirs.images_dir, 'colorspace'),
103 ])
104 if svgs:
105 # svg_dir is the root of the SVG corpus. Within that directory,
106 # the *.svg inputs are in the 'svg' subdirectory. See skbug.com/11229
107 args.extend(['--svgs', api.flavor.device_path_join(
108 api.flavor.device_dirs.svg_dir, "svg")])
109 if lotties:
110 args.extend([
111 '--lotties',
112 api.flavor.device_path_join(
113 api.flavor.device_dirs.resource_dir, 'skottie'),
114 api.flavor.device_dirs.lotties_dir,
115 ])
116 if 'Fontations' in api.vars.builder_cfg.get('extra_config', []):
117 args.extend(['--fontTestDataPath', api.flavor.device_dirs.fonts_dir])
118
119 if use_hash_file:
120 args.extend(['--uninterestingHashesFile', hashes_file])
121 if do_upload:
122 args.extend(['--writePath', api.flavor.device_dirs.dm_dir])
123
124 # Run DM.
125 api.run(api.flavor.step, 'dm', cmd=args, abort_on_failure=False)
126
127 if do_upload:
128 # Copy images and JSON to host machine if needed.
129 api.flavor.copy_directory_contents_to_host(
130 api.flavor.device_dirs.dm_dir, api.flavor.host_dirs.dm_dir)
131 # https://bugs.chromium.org/p/chromium/issues/detail?id=1192611
132 if 'Win' not in api.vars.builder_cfg.get('os', ''):
133 api.gold_upload.upload()
134
135

◆ test_zip()

def test.test_zip (   font_subset_zip,
  exe 
)

Definition at line 145 of file test.py.

145def test_zip(font_subset_zip, exe):
146 with ZipFile(font_subset_zip, 'r') as zip:
147 files = zip.namelist()
148 if 'font-subset%s' % exe not in files:
149 print('expected %s to contain font-subset%s' % (files, exe))
150 return 1
151 return 0
152
153
154# Maps the platform name to the output directory of the font artifacts.

Variable Documentation

◆ COMPARE_TESTS

tuple test.COMPARE_TESTS

Definition at line 23 of file test.py.

◆ DEPS

list test.DEPS
Initial value:
1= [
2 'env',
3 'flavor',
4 'recipe_engine/context',
5 'recipe_engine/file',
6 'recipe_engine/path',
7 'recipe_engine/platform',
8 'recipe_engine/properties',
9 'recipe_engine/raw_io',
10 'recipe_engine/step',
11 'gold_upload',
12 'run',
13 'vars',
14]

Definition at line 13 of file test.py.

◆ DM_JSON

string test.DM_JSON = 'dm.json'

Definition at line 28 of file test.py.

◆ MATERIAL_TTF

test.MATERIAL_TTF = os.path.join(SCRIPT_DIR, 'fixtures', 'MaterialIcons-Regular.ttf')

Definition at line 20 of file test.py.

◆ PYTHON_VERSION_COMPATIBILITY

string test.PYTHON_VERSION_COMPATIBILITY = "PY3"

Definition at line 11 of file test.py.

◆ SCRIPT_DIR

test.SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))

Definition at line 18 of file test.py.

◆ SRC_DIR

test.SRC_DIR = os.path.normpath(os.path.join(SCRIPT_DIR, '..', '..', '..'))

Definition at line 19 of file test.py.

◆ TEST_BUILDERS

list test.TEST_BUILDERS
Initial value:
1= [
2 'Test-Android-Clang-Pixel2XL-GPU-Adreno540-arm-Debug-All-Android_ASAN',
3 'Test-Android-Clang-Pixel2XL-GPU-Adreno540-arm64-Debug-All-Android',
4 'Test-Debian10-Clang-GCE-CPU-AVX2-x86_64-Release-All-Lottie',
5 'Test-Win10-Clang-ShuttleC-GPU-GTX960-x86_64-Debug-All-ANGLE',
6 'Test-Debian10-Clang-GCE-CPU-AVX2-x86_64-Debug-All-Fontations',
7]

Definition at line 148 of file test.py.

◆ VARIABLE_MATERIAL_TTF

test.VARIABLE_MATERIAL_TTF = os.path.join(SCRIPT_DIR, 'fixtures', 'MaterialSymbols-Variable.ttf')

Definition at line 21 of file test.py.