7 """Redirects sys.stdout to self and stores all that is written to it
11 """Initilalizes with an empty buffer
15 self
.original
= sys
.stdout
17 def write(self
, line
):
18 """Mandatory write method that stores the written line
23 def status(self
, line
):
24 """Prints a status line to stdout
26 This line is written to the true stdout even if stdout is redirected.
29 line: The line to be written to stdout.
32 self
.original
.write(line
)
34 def error(self
, line
):
35 """Prints an error line to stdout
37 This line is written to the true stdout even if stdout is redirected.
38 The line is prefix with \033[31m to make it show up in red on a terminal
39 and suffixed with \033[m to restore to regular color.
42 self
.original
.write("\033[31m" + line
+ "\033[m")
45 """Prints an success line to stdout
47 This line is written to the true stdout even if stdout is redirected.
48 The line is prefix with \033[32m to make it show up in green on a terminal
49 and suffixed with \033[m to restore to regular color.
52 self
.original
.write("\033[32m" + line
+ "\033[m")
55 """Restores sys.stdout to the original stdout
57 When created, or when catch is called, the current
58 sys.stdout is stored. Upon calling this method the
59 stored stdout is restored.
62 sys
.stdout
= self
.original
65 """Stores the current stdout and redirects it to self
68 self
.original
= sys
.stdout
72 """Returns all the output catched so far as one big string
75 return "".join(self
.buf
)
77 class GitResult(unittest
.TestResult
):
78 """A custom implementation to match Git's test suite's output style
81 def __init__(self
, output
, verbose
=False):
82 """Initializes all counters to zero
86 self
.shouldStop
= False
95 def writeError(self
, test
):
96 """Outputs an error message for the specified test
99 msg
= ("* FAIL %d: %s\n\t %s\n" %
100 (self
.test_count
, test
.shortDescription(), test
.__str
__()))
101 self
.output
.error(msg
)
103 def addError(self
, test
, err
):
105 self
.writeError(test
)
108 def addFailure(self
, test
, err
):
109 self
.test_failure
+= 1
110 self
.writeError(test
)
113 def addSuccess(self
, test
):
114 self
.test_success
+= 1
115 msg
= "* ok %d: %s\n" % (self
.test_count
, test
.shortDescription())
116 self
.output
.status(msg
)
118 def startTest(self
, test
):
119 # Check if the description is set
120 description
= test
.shortDescription()
122 raise TypeError("Description should be set")
126 print("* expecting success:")
127 print("\t" + test
.id())
129 def wasSuccessful(self
):
130 return not self
.test_failure
and not self
.test_error
133 """Prints a status line
136 if self
.wasSuccessful():
137 msg
= "* passed all %d test(s)\n" % self
.test_count
138 self
.output
.good(msg
)
141 if self
.test_failure
:
142 msg
+= "failed %d test(s)" % self
.test_failure
147 msg
+= "errored on %d test(s)" % self
.test_error
151 self
.output
.error(msg
)
154 """A test running class that makes use of GitResult to run the tests
157 def run(self
, test
, verbose
=False):
158 """Runs the specified test
162 catcher
= OutputCatcher()
169 # Set up a result object
170 result
= GitResult(catcher
, verbose
)
178 # Print the test results
183 def printUsage(self
):
184 """Prints a simple usage message
187 msg
= "Unknown option.\nYou can specify -v/--verbose to be more verbose"
190 def runTests(self
, args
, classes
):
191 """Runs the specified test in a test suite after parsing args
194 args: A list of arguments to parse, supported: -v/--verbose
195 tests: The tests to run
200 # Check for a sane args length
205 # Sane length, check if known argument
207 if args
[1] == "-v" or args
[1] == "--verbose":
213 # Create suites from the supplied classes
214 loader
= unittest
.defaultTestLoader
218 for testClass
in classes
:
219 suite
= loader
.loadTestsFromTestCase(testClass
)
222 # Create a suite for the tests
223 suite
= unittest
.TestSuite(suites
)
226 res
= self
.run(suite
, verbose
=self
.verbose
)
228 if res
.wasSuccessful():