• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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