1# Copyright 2018, The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15""" 16Classes for test mapping related objects 17""" 18 19 20import copy 21import os 22 23import constants 24 25 26class TestDetail(object): 27 """Stores the test details set in a TEST_MAPPING file.""" 28 29 def __init__(self, details): 30 """TestDetail constructor 31 32 Parse test detail from a dictionary, e.g., 33 { 34 "name": "SettingsUnitTests", 35 "host": true, 36 "options": [ 37 { 38 "instrumentation-arg": 39 "annotation=android.platform.test.annotations.Presubmit" 40 } 41 ] 42 } 43 44 Args: 45 details: A dictionary of test detail. 46 """ 47 self.name = details['name'] 48 self.options = [] 49 # True if the test should run on host and require no device. 50 self.host = details.get('host', False) 51 assert isinstance(self.host, bool), 'host can only have boolean value.' 52 options = details.get('options', []) 53 for option in options: 54 assert len(option) == 1, 'Each option can only have one key.' 55 self.options.append(copy.deepcopy(option).popitem()) 56 self.options.sort(key=lambda o: o[0]) 57 58 def __str__(self): 59 """String value of the TestDetail object.""" 60 host_info = (', runs on host without device required.' if self.host 61 else '') 62 if not self.options: 63 return self.name + host_info 64 options = '' 65 for option in self.options: 66 options += '%s: %s, ' % option 67 68 return '%s (%s)%s' % (self.name, options.strip(', '), host_info) 69 70 def __hash__(self): 71 """Get the hash of TestDetail based on the details""" 72 return hash(str(self)) 73 74 def __eq__(self, other): 75 return str(self) == str(other) 76 77 78class Import(object): 79 """Store test mapping import details.""" 80 81 def __init__(self, test_mapping_file, details): 82 """Import constructor 83 84 Parse import details from a dictionary, e.g., 85 { 86 "path": "..\folder1" 87 } 88 in which, project is the name of the project, by default it's the 89 current project of the containing TEST_MAPPING file. 90 91 Args: 92 test_mapping_file: Path to the TEST_MAPPING file that contains the 93 import. 94 details: A dictionary of details about importing another 95 TEST_MAPPING file. 96 """ 97 self.test_mapping_file = test_mapping_file 98 self.path = details['path'] 99 100 def __str__(self): 101 """String value of the Import object.""" 102 return 'Source: %s, path: %s' % (self.test_mapping_file, self.path) 103 104 def get_path(self): 105 """Get the path to TEST_MAPPING import directory.""" 106 path = os.path.realpath(os.path.join( 107 os.path.dirname(self.test_mapping_file), self.path)) 108 if os.path.exists(path): 109 return path 110 root_dir = os.environ.get(constants.ANDROID_BUILD_TOP, os.sep) 111 path = os.path.realpath(os.path.join(root_dir, self.path)) 112 if os.path.exists(path): 113 return path 114 # The import path can't be located. 115 return None 116