1# Copyright (C) 2014 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
15import collections
16import enum
17import sys
18
19
20class Logger:
21  class Level(enum.IntEnum):
22    NO_OUTPUT, ERROR, INFO = range(3)
23
24  class Color(enum.Enum):
25    DEFAULT, BLUE, GRAY, PURPLE, RED, GREEN = range(6)
26
27    @staticmethod
28    def terminal_code(color, out=sys.stdout):
29      if not out.isatty():
30        return ""
31      elif color == Logger.Color.BLUE:
32        return "\033[94m"
33      elif color == Logger.Color.GRAY:
34        return "\033[37m"
35      elif color == Logger.Color.PURPLE:
36        return "\033[95m"
37      elif color == Logger.Color.RED:
38        return "\033[91m"
39      elif color == Logger.Color.GREEN:
40        return "\033[32m"
41      else:
42        return "\033[0m"
43
44  Verbosity = Level.INFO
45
46  @staticmethod
47  def log(content, level=Level.INFO, color=Color.DEFAULT, new_line=True, out=sys.stdout):
48    if level <= Logger.Verbosity:
49      content = "{}{}{}".format(Logger.Color.terminal_code(color, out), content,
50                                Logger.Color.terminal_code(Logger.Color.DEFAULT, out))
51      if new_line:
52        print(content, file=out)
53      else:
54        print(content, end="", file=out)
55      out.flush()
56
57  @staticmethod
58  def fail(msg, file=None, line=-1, line_text=None, variables=None):
59    Logger.log("error: ", Logger.Level.ERROR, color=Logger.Color.RED, new_line=False,
60               out=sys.stderr)
61    Logger.log(msg, Logger.Level.ERROR, out=sys.stderr)
62
63    if line_text:
64      loc = ""
65      if file:
66        loc += file + ":"
67      if line > 0:
68        loc += str(line) + ":"
69      if loc:
70        loc += " "
71      Logger.log(loc, Logger.Level.ERROR, color=Logger.Color.GRAY, new_line=False,
72                 out=sys.stderr)
73      Logger.log(line_text, Logger.Level.ERROR, out=sys.stderr)
74
75    if variables:
76      longest_name = max(len(var) for var in variables)
77
78      for var in collections.OrderedDict(sorted(variables.items())):
79        padding = " " * (longest_name - len(var))
80        Logger.log(var, Logger.Level.ERROR, color=Logger.Color.GREEN, new_line=False,
81                   out=sys.stderr)
82        Logger.log(padding, Logger.Level.ERROR, new_line=False, out=sys.stderr)
83        Logger.log(" = ", Logger.Level.ERROR, new_line=False, out=sys.stderr)
84        Logger.log(variables[var], Logger.Level.ERROR, out=sys.stderr)
85
86    sys.exit(1)
87
88  @staticmethod
89  def start_test(name):
90    Logger.log("TEST ", color=Logger.Color.PURPLE, new_line=False)
91    Logger.log(name + "... ", new_line=False)
92
93  @staticmethod
94  def test_passed():
95    Logger.log("PASS", color=Logger.Color.BLUE)
96
97  @staticmethod
98  def test_failed(msg, statement, variables):
99    Logger.log("FAIL", color=Logger.Color.RED)
100    Logger.fail(msg, statement.filename, statement.line_no, statement.original_text, variables)
101