xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/unittest/util.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""Various utility functions."""
2*cda5da8dSAndroid Build Coastguard Worker
3*cda5da8dSAndroid Build Coastguard Workerfrom collections import namedtuple, Counter
4*cda5da8dSAndroid Build Coastguard Workerfrom os.path import commonprefix
5*cda5da8dSAndroid Build Coastguard Worker
6*cda5da8dSAndroid Build Coastguard Worker__unittest = True
7*cda5da8dSAndroid Build Coastguard Worker
8*cda5da8dSAndroid Build Coastguard Worker_MAX_LENGTH = 80
9*cda5da8dSAndroid Build Coastguard Worker_PLACEHOLDER_LEN = 12
10*cda5da8dSAndroid Build Coastguard Worker_MIN_BEGIN_LEN = 5
11*cda5da8dSAndroid Build Coastguard Worker_MIN_END_LEN = 5
12*cda5da8dSAndroid Build Coastguard Worker_MIN_COMMON_LEN = 5
13*cda5da8dSAndroid Build Coastguard Worker_MIN_DIFF_LEN = _MAX_LENGTH - \
14*cda5da8dSAndroid Build Coastguard Worker               (_MIN_BEGIN_LEN + _PLACEHOLDER_LEN + _MIN_COMMON_LEN +
15*cda5da8dSAndroid Build Coastguard Worker                _PLACEHOLDER_LEN + _MIN_END_LEN)
16*cda5da8dSAndroid Build Coastguard Workerassert _MIN_DIFF_LEN >= 0
17*cda5da8dSAndroid Build Coastguard Worker
18*cda5da8dSAndroid Build Coastguard Workerdef _shorten(s, prefixlen, suffixlen):
19*cda5da8dSAndroid Build Coastguard Worker    skip = len(s) - prefixlen - suffixlen
20*cda5da8dSAndroid Build Coastguard Worker    if skip > _PLACEHOLDER_LEN:
21*cda5da8dSAndroid Build Coastguard Worker        s = '%s[%d chars]%s' % (s[:prefixlen], skip, s[len(s) - suffixlen:])
22*cda5da8dSAndroid Build Coastguard Worker    return s
23*cda5da8dSAndroid Build Coastguard Worker
24*cda5da8dSAndroid Build Coastguard Workerdef _common_shorten_repr(*args):
25*cda5da8dSAndroid Build Coastguard Worker    args = tuple(map(safe_repr, args))
26*cda5da8dSAndroid Build Coastguard Worker    maxlen = max(map(len, args))
27*cda5da8dSAndroid Build Coastguard Worker    if maxlen <= _MAX_LENGTH:
28*cda5da8dSAndroid Build Coastguard Worker        return args
29*cda5da8dSAndroid Build Coastguard Worker
30*cda5da8dSAndroid Build Coastguard Worker    prefix = commonprefix(args)
31*cda5da8dSAndroid Build Coastguard Worker    prefixlen = len(prefix)
32*cda5da8dSAndroid Build Coastguard Worker
33*cda5da8dSAndroid Build Coastguard Worker    common_len = _MAX_LENGTH - \
34*cda5da8dSAndroid Build Coastguard Worker                 (maxlen - prefixlen + _MIN_BEGIN_LEN + _PLACEHOLDER_LEN)
35*cda5da8dSAndroid Build Coastguard Worker    if common_len > _MIN_COMMON_LEN:
36*cda5da8dSAndroid Build Coastguard Worker        assert _MIN_BEGIN_LEN + _PLACEHOLDER_LEN + _MIN_COMMON_LEN + \
37*cda5da8dSAndroid Build Coastguard Worker               (maxlen - prefixlen) < _MAX_LENGTH
38*cda5da8dSAndroid Build Coastguard Worker        prefix = _shorten(prefix, _MIN_BEGIN_LEN, common_len)
39*cda5da8dSAndroid Build Coastguard Worker        return tuple(prefix + s[prefixlen:] for s in args)
40*cda5da8dSAndroid Build Coastguard Worker
41*cda5da8dSAndroid Build Coastguard Worker    prefix = _shorten(prefix, _MIN_BEGIN_LEN, _MIN_COMMON_LEN)
42*cda5da8dSAndroid Build Coastguard Worker    return tuple(prefix + _shorten(s[prefixlen:], _MIN_DIFF_LEN, _MIN_END_LEN)
43*cda5da8dSAndroid Build Coastguard Worker                 for s in args)
44*cda5da8dSAndroid Build Coastguard Worker
45*cda5da8dSAndroid Build Coastguard Workerdef safe_repr(obj, short=False):
46*cda5da8dSAndroid Build Coastguard Worker    try:
47*cda5da8dSAndroid Build Coastguard Worker        result = repr(obj)
48*cda5da8dSAndroid Build Coastguard Worker    except Exception:
49*cda5da8dSAndroid Build Coastguard Worker        result = object.__repr__(obj)
50*cda5da8dSAndroid Build Coastguard Worker    if not short or len(result) < _MAX_LENGTH:
51*cda5da8dSAndroid Build Coastguard Worker        return result
52*cda5da8dSAndroid Build Coastguard Worker    return result[:_MAX_LENGTH] + ' [truncated]...'
53*cda5da8dSAndroid Build Coastguard Worker
54*cda5da8dSAndroid Build Coastguard Workerdef strclass(cls):
55*cda5da8dSAndroid Build Coastguard Worker    return "%s.%s" % (cls.__module__, cls.__qualname__)
56*cda5da8dSAndroid Build Coastguard Worker
57*cda5da8dSAndroid Build Coastguard Workerdef sorted_list_difference(expected, actual):
58*cda5da8dSAndroid Build Coastguard Worker    """Finds elements in only one or the other of two, sorted input lists.
59*cda5da8dSAndroid Build Coastguard Worker
60*cda5da8dSAndroid Build Coastguard Worker    Returns a two-element tuple of lists.    The first list contains those
61*cda5da8dSAndroid Build Coastguard Worker    elements in the "expected" list but not in the "actual" list, and the
62*cda5da8dSAndroid Build Coastguard Worker    second contains those elements in the "actual" list but not in the
63*cda5da8dSAndroid Build Coastguard Worker    "expected" list.    Duplicate elements in either input list are ignored.
64*cda5da8dSAndroid Build Coastguard Worker    """
65*cda5da8dSAndroid Build Coastguard Worker    i = j = 0
66*cda5da8dSAndroid Build Coastguard Worker    missing = []
67*cda5da8dSAndroid Build Coastguard Worker    unexpected = []
68*cda5da8dSAndroid Build Coastguard Worker    while True:
69*cda5da8dSAndroid Build Coastguard Worker        try:
70*cda5da8dSAndroid Build Coastguard Worker            e = expected[i]
71*cda5da8dSAndroid Build Coastguard Worker            a = actual[j]
72*cda5da8dSAndroid Build Coastguard Worker            if e < a:
73*cda5da8dSAndroid Build Coastguard Worker                missing.append(e)
74*cda5da8dSAndroid Build Coastguard Worker                i += 1
75*cda5da8dSAndroid Build Coastguard Worker                while expected[i] == e:
76*cda5da8dSAndroid Build Coastguard Worker                    i += 1
77*cda5da8dSAndroid Build Coastguard Worker            elif e > a:
78*cda5da8dSAndroid Build Coastguard Worker                unexpected.append(a)
79*cda5da8dSAndroid Build Coastguard Worker                j += 1
80*cda5da8dSAndroid Build Coastguard Worker                while actual[j] == a:
81*cda5da8dSAndroid Build Coastguard Worker                    j += 1
82*cda5da8dSAndroid Build Coastguard Worker            else:
83*cda5da8dSAndroid Build Coastguard Worker                i += 1
84*cda5da8dSAndroid Build Coastguard Worker                try:
85*cda5da8dSAndroid Build Coastguard Worker                    while expected[i] == e:
86*cda5da8dSAndroid Build Coastguard Worker                        i += 1
87*cda5da8dSAndroid Build Coastguard Worker                finally:
88*cda5da8dSAndroid Build Coastguard Worker                    j += 1
89*cda5da8dSAndroid Build Coastguard Worker                    while actual[j] == a:
90*cda5da8dSAndroid Build Coastguard Worker                        j += 1
91*cda5da8dSAndroid Build Coastguard Worker        except IndexError:
92*cda5da8dSAndroid Build Coastguard Worker            missing.extend(expected[i:])
93*cda5da8dSAndroid Build Coastguard Worker            unexpected.extend(actual[j:])
94*cda5da8dSAndroid Build Coastguard Worker            break
95*cda5da8dSAndroid Build Coastguard Worker    return missing, unexpected
96*cda5da8dSAndroid Build Coastguard Worker
97*cda5da8dSAndroid Build Coastguard Worker
98*cda5da8dSAndroid Build Coastguard Workerdef unorderable_list_difference(expected, actual):
99*cda5da8dSAndroid Build Coastguard Worker    """Same behavior as sorted_list_difference but
100*cda5da8dSAndroid Build Coastguard Worker    for lists of unorderable items (like dicts).
101*cda5da8dSAndroid Build Coastguard Worker
102*cda5da8dSAndroid Build Coastguard Worker    As it does a linear search per item (remove) it
103*cda5da8dSAndroid Build Coastguard Worker    has O(n*n) performance."""
104*cda5da8dSAndroid Build Coastguard Worker    missing = []
105*cda5da8dSAndroid Build Coastguard Worker    while expected:
106*cda5da8dSAndroid Build Coastguard Worker        item = expected.pop()
107*cda5da8dSAndroid Build Coastguard Worker        try:
108*cda5da8dSAndroid Build Coastguard Worker            actual.remove(item)
109*cda5da8dSAndroid Build Coastguard Worker        except ValueError:
110*cda5da8dSAndroid Build Coastguard Worker            missing.append(item)
111*cda5da8dSAndroid Build Coastguard Worker
112*cda5da8dSAndroid Build Coastguard Worker    # anything left in actual is unexpected
113*cda5da8dSAndroid Build Coastguard Worker    return missing, actual
114*cda5da8dSAndroid Build Coastguard Worker
115*cda5da8dSAndroid Build Coastguard Workerdef three_way_cmp(x, y):
116*cda5da8dSAndroid Build Coastguard Worker    """Return -1 if x < y, 0 if x == y and 1 if x > y"""
117*cda5da8dSAndroid Build Coastguard Worker    return (x > y) - (x < y)
118*cda5da8dSAndroid Build Coastguard Worker
119*cda5da8dSAndroid Build Coastguard Worker_Mismatch = namedtuple('Mismatch', 'actual expected value')
120*cda5da8dSAndroid Build Coastguard Worker
121*cda5da8dSAndroid Build Coastguard Workerdef _count_diff_all_purpose(actual, expected):
122*cda5da8dSAndroid Build Coastguard Worker    'Returns list of (cnt_act, cnt_exp, elem) triples where the counts differ'
123*cda5da8dSAndroid Build Coastguard Worker    # elements need not be hashable
124*cda5da8dSAndroid Build Coastguard Worker    s, t = list(actual), list(expected)
125*cda5da8dSAndroid Build Coastguard Worker    m, n = len(s), len(t)
126*cda5da8dSAndroid Build Coastguard Worker    NULL = object()
127*cda5da8dSAndroid Build Coastguard Worker    result = []
128*cda5da8dSAndroid Build Coastguard Worker    for i, elem in enumerate(s):
129*cda5da8dSAndroid Build Coastguard Worker        if elem is NULL:
130*cda5da8dSAndroid Build Coastguard Worker            continue
131*cda5da8dSAndroid Build Coastguard Worker        cnt_s = cnt_t = 0
132*cda5da8dSAndroid Build Coastguard Worker        for j in range(i, m):
133*cda5da8dSAndroid Build Coastguard Worker            if s[j] == elem:
134*cda5da8dSAndroid Build Coastguard Worker                cnt_s += 1
135*cda5da8dSAndroid Build Coastguard Worker                s[j] = NULL
136*cda5da8dSAndroid Build Coastguard Worker        for j, other_elem in enumerate(t):
137*cda5da8dSAndroid Build Coastguard Worker            if other_elem == elem:
138*cda5da8dSAndroid Build Coastguard Worker                cnt_t += 1
139*cda5da8dSAndroid Build Coastguard Worker                t[j] = NULL
140*cda5da8dSAndroid Build Coastguard Worker        if cnt_s != cnt_t:
141*cda5da8dSAndroid Build Coastguard Worker            diff = _Mismatch(cnt_s, cnt_t, elem)
142*cda5da8dSAndroid Build Coastguard Worker            result.append(diff)
143*cda5da8dSAndroid Build Coastguard Worker
144*cda5da8dSAndroid Build Coastguard Worker    for i, elem in enumerate(t):
145*cda5da8dSAndroid Build Coastguard Worker        if elem is NULL:
146*cda5da8dSAndroid Build Coastguard Worker            continue
147*cda5da8dSAndroid Build Coastguard Worker        cnt_t = 0
148*cda5da8dSAndroid Build Coastguard Worker        for j in range(i, n):
149*cda5da8dSAndroid Build Coastguard Worker            if t[j] == elem:
150*cda5da8dSAndroid Build Coastguard Worker                cnt_t += 1
151*cda5da8dSAndroid Build Coastguard Worker                t[j] = NULL
152*cda5da8dSAndroid Build Coastguard Worker        diff = _Mismatch(0, cnt_t, elem)
153*cda5da8dSAndroid Build Coastguard Worker        result.append(diff)
154*cda5da8dSAndroid Build Coastguard Worker    return result
155*cda5da8dSAndroid Build Coastguard Worker
156*cda5da8dSAndroid Build Coastguard Workerdef _count_diff_hashable(actual, expected):
157*cda5da8dSAndroid Build Coastguard Worker    'Returns list of (cnt_act, cnt_exp, elem) triples where the counts differ'
158*cda5da8dSAndroid Build Coastguard Worker    # elements must be hashable
159*cda5da8dSAndroid Build Coastguard Worker    s, t = Counter(actual), Counter(expected)
160*cda5da8dSAndroid Build Coastguard Worker    result = []
161*cda5da8dSAndroid Build Coastguard Worker    for elem, cnt_s in s.items():
162*cda5da8dSAndroid Build Coastguard Worker        cnt_t = t.get(elem, 0)
163*cda5da8dSAndroid Build Coastguard Worker        if cnt_s != cnt_t:
164*cda5da8dSAndroid Build Coastguard Worker            diff = _Mismatch(cnt_s, cnt_t, elem)
165*cda5da8dSAndroid Build Coastguard Worker            result.append(diff)
166*cda5da8dSAndroid Build Coastguard Worker    for elem, cnt_t in t.items():
167*cda5da8dSAndroid Build Coastguard Worker        if elem not in s:
168*cda5da8dSAndroid Build Coastguard Worker            diff = _Mismatch(0, cnt_t, elem)
169*cda5da8dSAndroid Build Coastguard Worker            result.append(diff)
170*cda5da8dSAndroid Build Coastguard Worker    return result
171