1# Copyright (c) 2017 Mark D. Hill and David A. Wood
2# All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are
6# met: redistributions of source code must retain the above copyright
7# notice, this list of conditions and the following disclaimer;
8# redistributions in binary form must reproduce the above copyright
9# notice, this list of conditions and the following disclaimer in the
10# documentation and/or other materials provided with the distribution;
11# neither the name of the copyright holders nor the names of its
12# contributors may be used to endorse or promote products derived from
13# this software without specific prior written permission.
14#
15# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26#
27# Authors: Sean Wilson
28
29import os
30import itertools
31
32import config
33
34class UID(object):
35    sep = ':'
36    type_idx, path_idx = range(2)
37
38    def __init__(self, path, *args):
39        self.path = self._shorten_path(path)
40        self.attributes = args
41
42    @staticmethod
43    def _shorten_path(path):
44        return os.path.relpath(path,
45                os.path.commonprefix((config.constants.testing_base,
46                                      path)))
47
48    @staticmethod
49    def _full_path(short_path):
50        return os.path.join(config.constants.testing_base, short_path)
51
52    @classmethod
53    def uid_to_path(cls, uid):
54        split_path = str(uid).split(cls.sep)[cls.path_idx]
55        return cls._full_path(split_path)
56
57    @classmethod
58    def uid_to_class(cls, uid):
59        return globals()[uid.split(cls.sep)[cls.type_idx]]
60
61    @classmethod
62    def from_suite(self, suite, filepath):
63        return SuiteUID(filepath, suite.name)
64
65    @classmethod
66    def from_test(self, test, filepath):
67        return TestUID(filepath, test.name, test.parent_suite.name)
68
69    @classmethod
70    def from_uid(cls, uid):
71        args = uid.split(cls.sep)
72        del args[cls.type_idx]
73        return cls.uid_to_class(uid)(*args)
74
75    def __str__(self):
76        common_opts = {
77            self.path_idx: self.path,
78            self.type_idx: self.__class__.__name__
79        }
80        return self.sep.join(itertools.chain(
81            [common_opts[0], common_opts[1]],
82            self.attributes))
83
84    def __hash__(self):
85        return hash(str(self))
86
87    def __eq__(self, other):
88        return type(self) == type(other) and str(self) == str(other)
89
90
91class TestUID(UID):
92    def __init__(self, filename, test_name, suite_name):
93        UID.__init__(self, filename, suite_name, test_name)
94
95    @property
96    def test(self):
97        return self.attributes[1]
98
99    @property
100    def suite(self):
101        return self.attributes[0]
102
103
104class SuiteUID(UID):
105    def __init__(self, filename, suite_name):
106        UID.__init__(self, filename, suite_name)
107
108    @property
109    def suite(self):
110        return self.attributes[0]
111