WebKit Bugzilla
Attachment 356960 Details for
Bug 192162
: webkitpy: Implement device type specific expected results
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-192162-20181210082724.patch (text/plain), 27.48 KB, created by
Jonathan Bedard
on 2018-12-10 08:27:25 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Jonathan Bedard
Created:
2018-12-10 08:27:25 PST
Size:
27.48 KB
patch
obsolete
>Index: Tools/ChangeLog >=================================================================== >--- Tools/ChangeLog (revision 239029) >+++ Tools/ChangeLog (working copy) >@@ -1,3 +1,56 @@ >+2018-12-10 Jonathan Bedard <jbedard@apple.com> >+ >+ https://bugs.webkit.org/show_bug.cgi?id=192162 >+ <https://bugs.webkit.org/show_bug.cgi?id=192162> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ UNFINISHED PATCH >+ >+ * Scripts/webkitpy/layout_tests/controllers/manager.py: >+ (Manager._custom_devices_for_test): >+ (Manager.run): >+ (Manager.print_expectations): >+ (Manager._custom_device_for_test): Deleted. >+ * Scripts/webkitpy/layout_tests/controllers/manager_unittest.py: >+ (ManagerTest.test_uses_custom_device.MockCustomDevicePort): >+ (ManagerTest.test_uses_custom_device.get_manager): >+ (ManagerTest): >+ (ManagerTest.test_uses_custom_device): >+ * Scripts/webkitpy/layout_tests/controllers/single_test_runner.py: >+ (SingleTestRunner._expected_driver_output): >+ * Scripts/webkitpy/port/base.py: >+ (Port.expected_baselines): >+ (Port.expected_baselines.expectation_suffix_for_device_type): >+ (Port.expected_filename): >+ (Port.expected_checksum): >+ (Port.expected_image): >+ (Port.expected_audio): >+ (Port.expected_text): >+ (Port.potential_test_names_from_expected_file): >+ (Port): >+ * Scripts/webkitpy/port/device_port.py: >+ (DevicePort.setup_test_run): >+ * Scripts/webkitpy/port/driver.py: >+ (Driver): >+ (Driver.device_type): >+ (DriverProxy): >+ (DriverProxy.device_type): >+ * Scripts/webkitpy/test/main.py: >+ (Tester._run_tests): >+ * Scripts/webkitpy/xcode/device_type.py: >+ (DeviceType): >+ (DeviceType.types_for_layout_test): >+ (DeviceType.__hash__): >+ (DeviceType.__cmp__): >+ (DeviceType.__cmp__.compute_priority): >+ (DeviceType.__ne__): >+ * Scripts/webkitpy/xcode/device_type_unittest.py: >+ (DeviceTypeTest.test_comparison_lower_case): >+ (DeviceTypeTest): >+ (DeviceTypeTest.test_order): >+ (DeviceTypeTest.test_from_layout_test): >+ > 2018-12-10 Michael Catanzaro <mcatanzaro@igalia.com> > > [WPE][GTK] run-minibrowser improperly creates webkit-flatpak environment >Index: Tools/Scripts/webkitpy/layout_tests/controllers/manager.py >=================================================================== >--- Tools/Scripts/webkitpy/layout_tests/controllers/manager.py (revision 238966) >+++ Tools/Scripts/webkitpy/layout_tests/controllers/manager.py (working copy) >@@ -1,5 +1,6 @@ > # Copyright (C) 2010 Google Inc. All rights reserved. > # Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged >+# Copyright (C) 2018 Apple Inc. All rights reserved. > # > # Redistribution and use in source and binary forms, with or without > # modification, are permitted provided that the following conditions are >@@ -103,15 +104,14 @@ class Manager(object): > def _needs_web_platform_test(self, test): > return self.web_platform_test_subdir in test or self.webkit_specific_web_platform_test_subdir in test > >- def _custom_device_for_test(self, test): >- # FIXME: This is a terrible way to do device-specific expected results https://bugs.webkit.org/show_bug.cgi?id=192162 >- for device_type in self._port.CUSTOM_DEVICE_TYPES: >- if device_type.hardware_family and device_type.hardware_family.lower() + self._port.TEST_PATH_SEPARATOR in test: >- return device_type >- if device_type.hardware_family and device_type.hardware_type and \ >- (device_type.hardware_family + device_type.hardware_type).lower().replace(' ', '') + self._port.TEST_PATH_SEPARATOR in test: >- return device_type >- return None >+ def _custom_devices_for_test(self, test): >+ if not self._filesystem.exists(test): >+ test = self._filesystem.join(self._port.layout_tests_dir(), test) >+ >+ types_for_test = [typ for typ in DeviceType.types_for_layout_test(test, filesystem=self._filesystem)] >+ if len(filter(lambda typ: self._port.max_child_processes(device_type=typ), types_for_test)) != 1: >+ return [typ for typ in types_for_test if typ] >+ return [typ or self._port.DEFAULT_DEVICE_TYPE for typ in types_for_test] > > def _http_tests(self, test_names): > return set(test for test in test_names if self._is_http_test(test)) >@@ -208,21 +208,9 @@ class Manager(object): > # Look for tests with custom device requirements. > test_device_mapping = defaultdict(list) > for test_file in tests_to_run: >- test_device_mapping[self._custom_device_for_test(test_file) or self._port.DEFAULT_DEVICE_TYPE].append(test_file) >- >- # Order device types from most specific to least specific in the hopes that some of the more specific device >- # types will match the less specific device types. >- device_type_order = [] >- types_with_family = [] >- remaining_types = [] >- for device_type in test_device_mapping.iterkeys(): >- if device_type and device_type.hardware_family and device_type.hardware_type: >- device_type_order.append(device_type) >- elif device_type and device_type.hardware_family: >- types_with_family.append(device_type) >- else: >- remaining_types.append(device_type) >- device_type_order.extend(types_with_family + remaining_types) >+ for device_type in self._custom_devices_for_test(test_file): >+ test_device_mapping[device_type].append(test_file) >+ device_type_order = [typ or self._port.DEFAULT_DEVICE_TYPE for typ in sorted(test_device_mapping.iterkeys())] > > needs_http = any((self._is_http_test(test) and not self._needs_web_platform_test(test)) for test in tests_to_run) > needs_web_platform_test_server = any(self._needs_web_platform_test(test) for test in tests_to_run) >@@ -265,7 +253,7 @@ class Manager(object): > > # This loop looks for any less-specific device types which match the current device type > index = 0 >- while index < len(device_type_order): >+ while index < len(device_type_order) and device_type: > if device_type_order[index] == device_type: > tests.extend(test_device_mapping[device_type_order[index]]) > >@@ -605,18 +593,13 @@ class Manager(object): > # Look for tests with custom device requirements. > custom_device_tests = defaultdict(list) > for test_file in tests_to_run: >- custom_device = self._custom_device_for_test(test_file) >- if custom_device: >- custom_device_tests[custom_device].append(test_file) >- else: >- default_device_tests.append(test_file) >+ for device_type in self._custom_devices_for_test(test_file): >+ custom_device_tests[device_type].append(test_file) > >- if custom_device_tests: >- for device_type, tests in custom_device_tests.iteritems(): >+ for device_type, tests in custom_device_tests.iteritems(): >+ if device_type: > _log.debug('{} tests use device {}'.format(len(tests), device_type)) > >- self._print_expectations_for_subset(None, test_col_width, tests_to_run, tests_to_skip) >- > for device_type, tests in custom_device_tests.iteritems(): > self._print_expectations_for_subset(device_type, test_col_width, tests) > >Index: Tools/Scripts/webkitpy/layout_tests/controllers/manager_unittest.py >=================================================================== >--- Tools/Scripts/webkitpy/layout_tests/controllers/manager_unittest.py (revision 238966) >+++ Tools/Scripts/webkitpy/layout_tests/controllers/manager_unittest.py (working copy) >@@ -34,6 +34,7 @@ import time > import unittest > > from webkitpy.common.host_mock import MockHost >+from webkitpy.common.system.filesystem_mock import MockFileSystem > from webkitpy.layout_tests.controllers.manager import Manager > from webkitpy.layout_tests.models import test_expectations > from webkitpy.layout_tests.models.test_run_results import TestRunResults >@@ -108,16 +109,22 @@ class ManagerTest(unittest.TestCase): > > def test_uses_custom_device(self): > class MockCustomDevicePort(TestPort): >- CUSTOM_DEVICE_TYPES = [DeviceType(hardware_family='iPad')] > > def __init__(self, host): > super(MockCustomDevicePort, self).__init__(host) > > def get_manager(): > host = MockHost() >+ host.filesystem = MockFileSystem(files={ >+ '/test.checkout/LayoutTests/fast/lasers.html': 'blah', >+ '/test.checkout/LayoutTests/fast/lasers-expected/ipad.txt': 'blah', >+ '/test.checkout/LayoutTests/fast/phasers.html': 'blah', >+ '/test.checkout/LayoutTests/fast/phasers-expected.txt': 'blah', >+ }) > port = MockCustomDevicePort(host) >- manager = Manager(port, options=MockOptions(test_list=['fast/ipad/lasers.html'], http=True), printer=Mock()) >+ manager = Manager(port, options=MockOptions(test_list=['fast/lasers.html', 'fast/phasers.html'], http=True), printer=Mock()) > return manager > > manager = get_manager() >- self.assertTrue(manager._custom_device_for_test('fast/ipad/lasers.html') == DeviceType(hardware_family='iPad')) >+ self.assertEqual(manager._custom_devices_for_test('fast/phasers.html'), [None]) >+ self.assertEqual(manager._custom_devices_for_test('fast/lasers.html'), [DeviceType.from_string('iPad')]) >Index: Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py >=================================================================== >--- Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py (revision 238966) >+++ Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py (working copy) >@@ -1,4 +1,5 @@ > # Copyright (C) 2011 Google Inc. All rights reserved. >+# Copyright (C) 2018 Apple Inc. All rights reserved. > # > # Redistribution and use in source and binary forms, with or without > # modification, are permitted provided that the following conditions are >@@ -74,10 +75,10 @@ class SingleTestRunner(object): > _log.error('%s is a reftest, but has an unused expectation file. Please remove %s.', self._test_name, expected_filename) > > def _expected_driver_output(self): >- return DriverOutput(self._port.expected_text(self._test_name), >- self._port.expected_image(self._test_name), >- self._port.expected_checksum(self._test_name), >- self._port.expected_audio(self._test_name)) >+ return DriverOutput(self._port.expected_text(self._test_name, device_type=self._driver.device_type), >+ self._port.expected_image(self._test_name, device_type=self._driver.device_type), >+ self._port.expected_checksum(self._test_name, device_type=self._driver.device_type), >+ self._port.expected_audio(self._test_name, device_type=self._driver.device_type)) > > def _should_fetch_expected_checksum(self): > return self._should_run_pixel_test and not (self._options.new_baseline or self._options.reset_results) >Index: Tools/Scripts/webkitpy/port/base.py >=================================================================== >--- Tools/Scripts/webkitpy/port/base.py (revision 238966) >+++ Tools/Scripts/webkitpy/port/base.py (working copy) >@@ -1,5 +1,5 @@ > # Copyright (C) 2010 Google Inc. All rights reserved. >-# Copyright (C) 2013 Apple Inc. All rights reserved. >+# Copyright (C) 2013-2018 Apple Inc. All rights reserved. > # > # Redistribution and use in source and binary forms, with or without > # modification, are permitted provided that the following conditions are >@@ -61,6 +61,7 @@ from webkitpy.port.factory import PortFa > from webkitpy.layout_tests.servers import apache_http_server, http_server, http_server_base > from webkitpy.layout_tests.servers import web_platform_test_server > from webkitpy.layout_tests.servers import websocket_server >+from webkitpy.xcode.device_type import DeviceType > > _log = logging.getLogger(__name__) > >@@ -408,7 +409,7 @@ class Port(object): > """Returns a tuple of all of the non-reftest baseline extensions we use. The extensions include the leading '.'.""" > return ('.wav', '.webarchive', '.txt', '.png') > >- def expected_baselines(self, test_name, suffix, all_baselines=False): >+ def expected_baselines(self, test_name, suffix, all_baselines=False, device_type=None): > """Given a test name, finds where the baseline results are located. > > Args: >@@ -435,29 +436,32 @@ class Port(object): > conjunction with the other baseline and filename routines that are > platform specific. > """ >- baseline_filename = self._filesystem.splitext(test_name)[0] + '-expected' + suffix >- baseline_search_path = self.baseline_search_path() >+ >+ def expectation_suffix_for_device_type(device_type): >+ if not device_type: >+ return '-expected' >+ return '-expected/{}{}'.format(device_type.hardware_family, (' ' + device_type.hardware_type) if device_type.hardware_type else '').replace(' ', '-') > > baselines = [] >- for platform_dir in baseline_search_path: >- if self._filesystem.exists(self._filesystem.join(platform_dir, baseline_filename)): >- baselines.append((platform_dir, baseline_filename)) >+ baseline_filename = self._filesystem.splitext(test_name)[0] >+ baseline_search_path = self.baseline_search_path() >+ for platform_dir in baseline_search_path + [self.layout_tests_dir()]: >+ types = DeviceType.types_for_layout_test(self._filesystem.join(platform_dir, test_name), filesystem=self._filesystem) >+ valid_types = [typ for typ in types if not device_type or (typ and device_type in typ)] >+ if not valid_types: >+ continue >+ baseline_filename_for_type = baseline_filename + expectation_suffix_for_device_type(valid_types[0]) + suffix >+ if self._filesystem.exists(self._filesystem.join(platform_dir, baseline_filename_for_type)): >+ baselines.append((platform_dir, baseline_filename_for_type)) > > if not all_baselines and baselines: > return baselines > >- # If it wasn't found in a platform directory, return the expected >- # result in the test directory, even if no such file actually exists. >- platform_dir = self.layout_tests_dir() >- if self._filesystem.exists(self._filesystem.join(platform_dir, baseline_filename)): >- baselines.append((platform_dir, baseline_filename)) >- > if baselines: > return baselines >+ return [(None, baseline_filename + expectation_suffix_for_device_type(None) + suffix)] > >- return [(None, baseline_filename)] >- >- def expected_filename(self, test_name, suffix, return_default=True): >+ def expected_filename(self, test_name, suffix, return_default=True, device_type=None): > """Given a test name, returns an absolute path to its expected results. > > If no expected results are found in any of the searched directories, >@@ -478,7 +482,7 @@ class Port(object): > the other baseline and filename manipulation routines. > """ > # FIXME: The [0] here is very mysterious, as is the destructured return. >- platform_dir, baseline_filename = self.expected_baselines(test_name, suffix)[0] >+ platform_dir, baseline_filename = self.expected_baselines(test_name, suffix, device_type=device_type)[0] > if platform_dir: > return self._filesystem.join(platform_dir, baseline_filename) > >@@ -486,9 +490,9 @@ class Port(object): > return self._filesystem.join(self.layout_tests_dir(), baseline_filename) > return None > >- def expected_checksum(self, test_name): >+ def expected_checksum(self, test_name, device_type=None): > """Returns the checksum of the image we expect the test to produce, or None if it is a text-only test.""" >- png_path = self.expected_filename(test_name, '.png') >+ png_path = self.expected_filename(test_name, '.png', device_type=device_type) > > if self._filesystem.exists(png_path): > with self._filesystem.open_binary_file_for_reading(png_path) as filehandle: >@@ -496,29 +500,29 @@ class Port(object): > > return None > >- def expected_image(self, test_name): >+ def expected_image(self, test_name, device_type=None): > """Returns the image we expect the test to produce.""" >- baseline_path = self.expected_filename(test_name, '.png') >+ baseline_path = self.expected_filename(test_name, '.png', device_type=device_type) > if not self._filesystem.exists(baseline_path): > return None > return self._filesystem.read_binary_file(baseline_path) > >- def expected_audio(self, test_name): >- baseline_path = self.expected_filename(test_name, '.wav') >+ def expected_audio(self, test_name, device_type=None): >+ baseline_path = self.expected_filename(test_name, '.wav', device_type=device_type) > if not self._filesystem.exists(baseline_path): > return None > return self._filesystem.read_binary_file(baseline_path) > >- def expected_text(self, test_name): >+ def expected_text(self, test_name, device_type=None): > """Returns the text output we expect the test to produce, or None > if we don't expect there to be any text output. > End-of-line characters are normalized to '\n'.""" > # FIXME: DRT output is actually utf-8, but since we don't decode the > # output from DRT (instead treating it as a binary string), we read the > # baselines as a binary string, too. >- baseline_path = self.expected_filename(test_name, '.txt') >+ baseline_path = self.expected_filename(test_name, '.txt', device_type=device_type) > if not self._filesystem.exists(baseline_path): >- baseline_path = self.expected_filename(test_name, '.webarchive') >+ baseline_path = self.expected_filename(test_name, '.webarchive', device_type=device_type) > if not self._filesystem.exists(baseline_path): > return None > text = self._filesystem.read_binary_file(baseline_path) >@@ -568,7 +572,7 @@ class Port(object): > def potential_test_names_from_expected_file(self, path): > """Return potential test names if any from a potential expected file path, relative to LayoutTests directory.""" > >- if not '-expected.' in path: >+ if not any(element in path for element in ['-expected/', '-expected.', '-expected-']): > return None > > if path.startswith('platform' + self._filesystem.sep): >@@ -625,7 +629,6 @@ class Port(object): > return False > > @staticmethod >- # If any changes are made here be sure to update the isUsedInReftest method in old-run-webkit-tests as well. > def is_reference_html_file(filesystem, dirname, filename): > if filename.startswith('ref-') or filename.startswith('notref-'): > return True >Index: Tools/Scripts/webkitpy/port/device_port.py >=================================================================== >--- Tools/Scripts/webkitpy/port/device_port.py (revision 238966) >+++ Tools/Scripts/webkitpy/port/device_port.py (working copy) >@@ -146,7 +146,7 @@ class DevicePort(DarwinPort): > device_type, > use_booted_simulator=not self.get_option('dedicated_simulators', False), > use_existing_simulator=False, >- allow_incomplete_match=True, >+ allow_incomplete_match=False, > ) > self.DEVICE_MANAGER.initialize_devices( > [request] * self.child_processes(), >Index: Tools/Scripts/webkitpy/port/driver.py >=================================================================== >--- Tools/Scripts/webkitpy/port/driver.py (revision 238966) >+++ Tools/Scripts/webkitpy/port/driver.py (working copy) >@@ -1,5 +1,5 @@ > # Copyright (C) 2011 Google Inc. All rights reserved. >-# Copyright (c) 2015, 2016 Apple Inc. All rights reserved. >+# Copyright (c) 2015-2018 Apple Inc. All rights reserved. > # > # Redistribution and use in source and binary forms, with or without > # modification, are permitted provided that the following conditions are >@@ -182,6 +182,10 @@ class Driver(object): > def __del__(self): > self.stop() > >+ @property >+ def device_type(self): >+ return getattr(getattr(self._target_host, 'platform_device', None), 'device_type', None) >+ > def run_test(self, driver_input, stop_when_done): > """Run a single test and return the results. > >@@ -719,6 +723,10 @@ class DriverProxy(object): > def _make_driver(self, pixel_tests): > return self._driver_instance_constructor(self._port, self._worker_number, pixel_tests, self._no_timeout) > >+ @property >+ def device_type(self): >+ return self._driver.device_type >+ > # FIXME: this should be a @classmethod (or implemented on Port instead). > def is_http_test(self, test_name): > return self._driver.is_http_test(test_name) >Index: Tools/Scripts/webkitpy/test/main.py >=================================================================== >--- Tools/Scripts/webkitpy/test/main.py (revision 238966) >+++ Tools/Scripts/webkitpy/test/main.py (working copy) >@@ -178,8 +178,8 @@ class Tester(object): > # We autoinstall everything up so that we can run tests concurrently > # and not have to worry about autoinstalling packages concurrently. > self.printer.write_update("Checking autoinstalled packages ...") >- from webkitpy.thirdparty import autoinstall_everything >- autoinstall_everything() >+ #from webkitpy.thirdparty import autoinstall_everything >+ #autoinstall_everything() > > if will_run_lldb_webkit_tests: > self.printer.write_update('Building lldbWebKitTester ...') >Index: Tools/Scripts/webkitpy/xcode/device_type.py >=================================================================== >--- Tools/Scripts/webkitpy/xcode/device_type.py (revision 238966) >+++ Tools/Scripts/webkitpy/xcode/device_type.py (working copy) >@@ -1,4 +1,4 @@ >-# Copyright (C) 2017 Apple Inc. All rights reserved. >+# Copyright (C) 2017-2018 Apple Inc. All rights reserved. > # > # Redistribution and use in source and binary forms, with or without > # modification, are permitted provided that the following conditions >@@ -21,6 +21,7 @@ > # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. > > from webkitpy.common.version_name_map import VersionNameMap >+from webkitpy.common.system.filesystem import FileSystem > > > # This class is designed to match device types. Because it is used for matching, 'None' is treated as a wild-card. >@@ -56,6 +57,47 @@ class DeviceType(object): > hardware_type=' '.join(split_str[family_index + 1:]) if len(split_str) > family_index + 1 else None, > software_version=version) > >+ @classmethod >+ def types_for_layout_test(cls, filename, filesystem=None): >+ filesystem = filesystem or FileSystem() >+ stripped_filename = filesystem.splitext(filename)[0] >+ >+ if filesystem.isdir(stripped_filename + '-expected'): >+ result = [] >+ processed_expectations = [] >+ has_default = filesystem.glob(stripped_filename + '-expected.*') >+ for expectation in filesystem.listdir(stripped_filename + '-expected'): >+ stripped_expectation = filesystem.splitext(expectation)[0] >+ if not stripped_expectation or stripped_expectation[0] == '.' or expectation in processed_expectations: >+ continue >+ processed_expectations.append(expectation) >+ >+ # Support for -mismatch >+ if stripped_expectation.endswith('-mismatch'): >+ stripped_expectation = stripped_expectation[:-(len('-mismatch'))] >+ >+ if stripped_expectation == 'default': >+ has_default = True >+ continue >+ >+ device_string = '' >+ dash_state = False >+ for character in stripped_expectation: >+ if character == '-' and not dash_state: >+ device_string += ' ' >+ dash_state = True >+ else: >+ device_string += character >+ dash_state = False >+ result.append(cls.from_string(device_string)) >+ >+ result = sorted(result) >+ if has_default: >+ result.append(None) >+ return result >+ else: >+ return [None] >+ > def _define_software_variant_from_hardware_family(self): > if self.hardware_family is None: > return >@@ -114,6 +156,27 @@ class DeviceType(object): > version=VersionNameMap.map().to_name(self.software_version, platform=self.software_variant.lower()) if self.software_version else self.software_variant, > ) > >+ def __hash__(self): >+ result = 0 >+ for element in [self.hardware_family, self.hardware_type, self.software_version, self.software_variant]: >+ result ^= hash(element) >+ return result >+ >+ def __cmp__(self, other): >+ >+ # Order device types from most specific to least specific in the hopes that some of the more specific device >+ # types will match the less specific device types. >+ def compute_priority(obj): >+ if not obj: >+ return 3 >+ if self.hardware_family and self.hardware_type: >+ return 2 >+ if self.hardware_family: >+ return 1 >+ return 0 >+ >+ return compute_priority(other) - compute_priority(self) >+ > # This technique of matching treats 'None' a wild-card. > def __eq__(self, other): > assert isinstance(other, DeviceType) >@@ -127,6 +190,9 @@ class DeviceType(object): > return False > return True > >+ def __ne__(self, other): >+ return not (self == other) >+ > def __contains__(self, other): > assert isinstance(other, DeviceType) > if self.hardware_family is not None and (not other.hardware_family or self.hardware_family.lower() != other.hardware_family.lower()): >Index: Tools/Scripts/webkitpy/xcode/device_type_unittest.py >=================================================================== >--- Tools/Scripts/webkitpy/xcode/device_type_unittest.py (revision 238966) >+++ Tools/Scripts/webkitpy/xcode/device_type_unittest.py (working copy) >@@ -1,4 +1,4 @@ >-# Copyright (C) 2017 Apple Inc. All rights reserved. >+# Copyright (C) 2017-2018 Apple Inc. All rights reserved. > # > # Redistribution and use in source and binary forms, with or without > # modification, are permitted provided that the following conditions >@@ -155,3 +155,12 @@ class DeviceTypeTest(unittest.TestCase): > self.assertTrue(DeviceType.from_string('iphone 6s') in DeviceType.from_string('iPhone')) > self.assertTrue(DeviceType.from_string('iPhone 6s') in DeviceType.from_string('iphone')) > self.assertTrue(DeviceType.from_string('iphone 6s') in DeviceType.from_string('iphone')) >+ >+ def test_order(self): >+ self.assertEqual( >+ sorted([DeviceType.from_string('iPhone X'), None, DeviceType(software_variant='iOS'), DeviceType.from_string('iPhone')]), >+ [None, DeviceType.from_string('iPhone X'), DeviceType.from_string('iPhone'), DeviceType(software_variant='iOS')], >+ ) >+ >+ def test_from_layout_test(self): >+ pass
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 192162
:
356960
|
356967
|
357055
|
357148
|
357149
|
357154
|
357170
|
357194
|
357205
|
357231
|
357275
|
359090
|
359383
|
359398
|
359433
|
359444
|
359448