blob: 22b5bc2dbe94247c77abb8afc8565f14c5e78212 [file]
# Copyright (C) 2024-2026 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 met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import logging
from webkitexpectationspy import (
ExpectationsManager, ResultStatus,
)
from webkitexpectationspy.suites.api_tests import APITestSuite
_log = logging.getLogger(__name__)
PASS = ResultStatus.PASS
FAIL = ResultStatus.FAIL
CRASH = ResultStatus.CRASH
TIMEOUT = ResultStatus.TIMEOUT
_RUNNER_STATUS_MAP = {
0: PASS,
1: FAIL,
2: CRASH,
3: TIMEOUT,
}
def runner_status_to_expectation(runner_status):
return _RUNNER_STATUS_MAP.get(runner_status)
class APITestExpectations:
def __init__(self, port, tests=None):
self._port = port
self._tests = tests
self._suite = APITestSuite()
self._manager = ExpectationsManager(suite=self._suite)
def parse_all_expectations(self):
for filepath in self._port.api_test_expectations_files():
if self._port.host.filesystem.exists(filepath):
_log.debug('Loading expectations from {}'.format(filepath))
content = self._port.host.filesystem.read_text_file(filepath)
warnings = self._manager.load_content(filepath, content)
for w in warnings:
_log.warning(str(w))
else:
_log.debug('Expectations file not found (skipping): {}'.format(filepath))
def parse_additional_file(self, filepath):
if self._port.host.filesystem.exists(filepath):
content = self._port.host.filesystem.read_text_file(filepath)
return self._manager.load_content(filepath, content)
_log.warning('Additional expectations file not found: {}'.format(filepath))
return []
def model(self):
return self._manager
def get_current_configuration(self):
config = set()
port_config = self._port.api_test_current_configuration()
for key in ('platform', 'version', 'style', 'architecture', 'hardware', 'hardware_type', 'flavor'):
value = port_config.get(key)
if value:
config.add(value.lower())
return config
def get_expectation(self, test_name, config=None):
if config is None:
config = self.get_current_configuration()
version_order = self._port.api_test_version_order() if hasattr(self._port, 'api_test_version_order') else []
current_version = None
port_config = self._port.api_test_current_configuration()
if port_config.get('version'):
current_version = port_config['version'].lower()
return self._manager.get_expectation(
test_name,
current_config=config,
current_version=current_version,
version_order=version_order,
)
def lint(self, all_tests=None):
return self._manager.lint(all_tests=all_tests)
def fix(self):
"""Rewrite loaded expectations files in place with reordered/normalized content.
Returns the sorted list of filenames that changed.
"""
filesystem = self._port.host.filesystem
changed = []
for filepath, fixed_content in self._manager.fix().items():
if fixed_content and not fixed_content.endswith('\n'):
fixed_content += '\n'
current = filesystem.read_text_file(filepath) if filesystem.exists(filepath) else None
if current != fixed_content:
filesystem.write_text_file(filepath, fixed_content)
changed.append(filepath)
return sorted(changed)