web_feature_map.py (5358B)
1 import itertools 2 3 from collections import OrderedDict 4 from os.path import basename 5 from typing import Dict, List, Optional, Sequence, Set 6 7 from ..manifest.item import ManifestItem, URLManifestItem 8 from ..manifest.sourcefile import SourceFile 9 from ..metadata.webfeatures.schema import FeatureEntry, FeatureFile, FileMatchingMode, WebFeaturesFile 10 11 12 class WebFeaturesMap: 13 """ 14 Stores a mapping of web-features to their associated test paths. 15 """ 16 17 def __init__(self) -> None: 18 """ 19 Initializes the WebFeaturesMap with an OrderedDict to maintain feature order. 20 """ 21 self._feature_tests_map_: OrderedDict[str, Set[str]] = OrderedDict() 22 23 24 def add(self, feature: str, manifest_items: List[ManifestItem]) -> None: 25 """ 26 Adds a web feature and its associated test paths to the map. 27 28 Args: 29 feature: The web-features identifier. 30 manifest_items: The ManifestItem objects representing the test paths. 31 """ 32 tests = self._feature_tests_map_.get(feature, set()) 33 self._feature_tests_map_[feature] = tests.union([ 34 manifest_item.url for manifest_item in manifest_items if isinstance(manifest_item, URLManifestItem)]) 35 36 37 def to_dict(self) -> Dict[str, List[str]]: 38 """ 39 Returns: 40 The plain dictionary representation of the map. 41 """ 42 rv: Dict[str, List[str]] = {} 43 for feature, manifest_items in self._feature_tests_map_.items(): 44 # Sort the list to keep output stable 45 rv[feature] = sorted(manifest_items) 46 return rv 47 48 49 class WebFeatureToTestsDirMapper: 50 """ 51 Maps web-features to tests within a specified directory. 52 """ 53 54 def __init__( 55 self, 56 all_test_files_in_dir: List[SourceFile], 57 web_feature_file: Optional[WebFeaturesFile]): 58 """ 59 Initializes the mapper with test paths and web feature information. 60 """ 61 62 self.all_test_files_in_dir = all_test_files_in_dir 63 self.test_path_to_manifest_items_map = dict([(basename(f.path), f.manifest_items()[1]) for f in self.all_test_files_in_dir]) 64 # Used to check if the current directory has a WEB_FEATURE_FILENAME 65 self.web_feature_file = web_feature_file 66 # Gets the manifest items for each test path and returns them into a single list. 67 self. get_all_manifest_items_for_dir = list(itertools.chain.from_iterable([ 68 items for _, items in self.test_path_to_manifest_items_map.items()])) 69 70 71 def _process_inherited_features( 72 self, 73 inherited_features: List[str], 74 result: WebFeaturesMap) -> None: 75 # No WEB_FEATURE.yml in this directory. Simply add the current features to the inherited features 76 for inherited_feature in inherited_features: 77 result.add(inherited_feature, self.get_all_manifest_items_for_dir) 78 79 def _process_recursive_feature( 80 self, 81 inherited_features: List[str], 82 feature: FeatureEntry, 83 result: WebFeaturesMap) -> None: 84 inherited_features.append(feature.name) 85 result.add(feature.name, self.get_all_manifest_items_for_dir) 86 87 def _process_non_recursive_feature( 88 self, 89 feature_name: str, 90 files: Sequence[FeatureFile], 91 result: WebFeaturesMap) -> None: 92 # If the feature does not apply recursively, look at the individual 93 # files and match them against all_test_files_in_dir. 94 final_test_file_paths: List[ManifestItem] = [] 95 test_file_paths: Set[str] = set() 96 excluded_test_file_paths: Set[str] = set() 97 base_test_file_names = [basename(f.path) for f in self.all_test_files_in_dir] 98 for test_file in files: 99 matched_base_file_names = test_file.match_files(base_test_file_names) 100 if test_file.matching_mode == FileMatchingMode.INCLUDE: 101 test_file_paths.update(matched_base_file_names) 102 elif test_file.matching_mode == FileMatchingMode.EXCLUDE: 103 excluded_test_file_paths.update(matched_base_file_names) 104 final_test_file_paths_set = test_file_paths - excluded_test_file_paths 105 final_test_file_paths.extend(itertools.chain.from_iterable([ 106 self.test_path_to_manifest_items_map[f] for f in final_test_file_paths_set])) 107 108 result.add(feature_name, final_test_file_paths) 109 110 def run(self, result: WebFeaturesMap, inherited_features: List[str]) -> None: 111 if self.web_feature_file: 112 # Do not copy the inherited features because the presence of a 113 # WEB_FEATURES.yml file indicates new instructions. 114 inherited_features.clear() 115 116 # Iterate over all the features in this new file 117 for feature in self.web_feature_file.features: 118 # Handle the "**" case 119 if feature.does_feature_apply_recursively(): 120 self._process_recursive_feature(inherited_features, feature, result) 121 122 # Handle the non recursive case. 123 elif isinstance(feature.files, List) and feature.files: 124 self._process_non_recursive_feature(feature.name, feature.files, result) 125 else: 126 self._process_inherited_features(inherited_features, result)