1#!/usr/bin/env python3.4
2#
3# Copyright 2016 - The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16"""This module is where all the test signal classes and related utilities live.
17"""
18
19import functools
20import json
21
22
23def generated_test(func):
24    """A decorator used to suppress result reporting for the test case that
25    kicks off a group of generated test cases.
26
27    Returns:
28        What the decorated function returns.
29    """
30
31    @functools.wraps(func)
32    def wrapper(*args, **kwargs):
33        func(*args, **kwargs)
34        raise TestSilent("Result reporting for %s is suppressed" %
35                         func.__name__)
36
37    return wrapper
38
39
40class TestSignalError(Exception):
41    """Raised when an error occurs inside a test signal."""
42
43
44class TestSignal(Exception):
45    """Base class for all test result control signals. This is used to signal
46    the result of a test.
47
48    Attribute:
49        details: A string that describes the reason for raising this signal.
50        extras: A json-serializable data type to convey extra information about
51                a test result.
52    """
53
54    def __init__(self, details, extras=None):
55        super(TestSignal, self).__init__(details)
56        self.details = str(details)
57        try:
58            json.dumps(extras)
59            self.extras = extras
60        except TypeError:
61            raise TestSignalError(("Extras must be json serializable. %s "
62                                   "is not.") % extras)
63
64    def __str__(self):
65        return "Details=%s, Extras=%s" % (self.details, self.extras)
66
67
68class TestFailure(TestSignal):
69    """Raised when a test has failed."""
70
71
72class TestPass(TestSignal):
73    """Raised when a test has passed."""
74
75
76class TestSkip(TestSignal):
77    """Raised when a test has been skipped."""
78
79
80class TestBlocked(TestSignal):
81    """Raised when a test has been blocked from running."""
82
83
84class TestSkipClass(TestSignal):
85    """Raised in setup_class when a whole test class should be skipped."""
86
87
88class TestSilent(TestSignal):
89    """Raised when a test should not be reported. This should only be used for
90    generated test cases.
91    """
92
93
94class TestAbortClass(TestSignal):
95    """Raised when all subsequent test cases within the same test class should
96    be aborted.
97    """
98
99
100class TestAbortAll(TestSignal):
101    """Raised when all subsequent test cases should be aborted."""
102
103
104class ControllerError(Exception):
105    """Raised when an error occured in controller classes."""
106