rubysl-test-unit 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,51 @@
1
+ #--
2
+ #
3
+ # Author:: Nathaniel Talbott.
4
+ # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
5
+ # License:: Ruby license.
6
+
7
+ module Test
8
+ module Unit
9
+
10
+ # Encapsulates a test failure. Created by Test::Unit::TestCase
11
+ # when an assertion fails.
12
+ class Failure
13
+ attr_reader :test_name, :location, :message
14
+
15
+ SINGLE_CHARACTER = 'F'
16
+
17
+ # Creates a new Failure with the given location and
18
+ # message.
19
+ def initialize(test_name, location, message)
20
+ @test_name = test_name
21
+ @location = location
22
+ @message = message
23
+ end
24
+
25
+ # Returns a single character representation of a failure.
26
+ def single_character_display
27
+ SINGLE_CHARACTER
28
+ end
29
+
30
+ # Returns a brief version of the error description.
31
+ def short_display
32
+ "#@test_name: #{@message.split("\n")[0]}"
33
+ end
34
+
35
+ # Returns a verbose version of the error description.
36
+ def long_display
37
+ location_display = if(location.size == 1)
38
+ location[0].sub(/\A(.+:\d+).*/, ' [\\1]')
39
+ else
40
+ "\n [#{location.join("\n ")}]"
41
+ end
42
+ "Failure:\n#@test_name#{location_display}:\n#@message"
43
+ end
44
+
45
+ # Overridden to return long_display.
46
+ def to_s
47
+ long_display
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,160 @@
1
+ #--
2
+ #
3
+ # Author:: Nathaniel Talbott.
4
+ # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved.
5
+ # License:: Ruby license.
6
+
7
+ require 'test/unit/assertions'
8
+ require 'test/unit/failure'
9
+ require 'test/unit/error'
10
+ require 'test/unit/testsuite'
11
+ require 'test/unit/assertionfailederror'
12
+ require 'test/unit/util/backtracefilter'
13
+
14
+ module Test
15
+ module Unit
16
+
17
+ # Ties everything together. If you subclass and add your own
18
+ # test methods, it takes care of making them into tests and
19
+ # wrapping those tests into a suite. It also does the
20
+ # nitty-gritty of actually running an individual test and
21
+ # collecting its results into a Test::Unit::TestResult object.
22
+ class TestCase
23
+ include Assertions
24
+ include Util::BacktraceFilter
25
+
26
+ attr_reader :method_name
27
+
28
+ STARTED = name + "::STARTED"
29
+ FINISHED = name + "::FINISHED"
30
+
31
+ ##
32
+ # These exceptions are not caught by #run.
33
+
34
+ PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException, Interrupt,
35
+ SystemExit]
36
+
37
+ # Creates a new instance of the fixture for running the
38
+ # test represented by test_method_name.
39
+ def initialize(test_method_name)
40
+ unless(respond_to?(test_method_name) and
41
+ (method(test_method_name).arity == 0 ||
42
+ method(test_method_name).arity == -1))
43
+ throw :invalid_test
44
+ end
45
+ @method_name = test_method_name
46
+ @test_passed = true
47
+ end
48
+
49
+ # Rolls up all of the test* methods in the fixture into
50
+ # one suite, creating a new instance of the fixture for
51
+ # each method.
52
+ def self.suite
53
+ method_names = public_instance_methods(true)
54
+ tests = method_names.delete_if {|method_name| method_name !~ /^test./}
55
+ suite = TestSuite.new(name)
56
+ tests.sort.each do
57
+ |test|
58
+ catch(:invalid_test) do
59
+ suite << new(test)
60
+ end
61
+ end
62
+ if (suite.empty?)
63
+ catch(:invalid_test) do
64
+ suite << new("default_test")
65
+ end
66
+ end
67
+ return suite
68
+ end
69
+
70
+ # Runs the individual test method represented by this
71
+ # instance of the fixture, collecting statistics, failures
72
+ # and errors in result.
73
+ def run(result)
74
+ yield(STARTED, name)
75
+ @_result = result
76
+ begin
77
+ setup
78
+ __send__(@method_name)
79
+ rescue AssertionFailedError => e
80
+ add_failure(e.message, e.backtrace)
81
+ rescue Exception
82
+ raise if PASSTHROUGH_EXCEPTIONS.include? $!.class
83
+ add_error($!)
84
+ ensure
85
+ begin
86
+ teardown
87
+ rescue AssertionFailedError => e
88
+ add_failure(e.message, e.backtrace)
89
+ rescue Exception
90
+ raise if PASSTHROUGH_EXCEPTIONS.include? $!.class
91
+ add_error($!)
92
+ end
93
+ end
94
+ result.add_run
95
+ yield(FINISHED, name)
96
+ end
97
+
98
+ # Called before every test method runs. Can be used
99
+ # to set up fixture information.
100
+ def setup
101
+ end
102
+
103
+ # Called after every test method runs. Can be used to tear
104
+ # down fixture information.
105
+ def teardown
106
+ end
107
+
108
+ def default_test
109
+ flunk("No tests were specified")
110
+ end
111
+
112
+ # Returns whether this individual test passed or
113
+ # not. Primarily for use in teardown so that artifacts
114
+ # can be left behind if the test fails.
115
+ def passed?
116
+ return @test_passed
117
+ end
118
+ private :passed?
119
+
120
+ def size
121
+ 1
122
+ end
123
+
124
+ def add_assertion
125
+ @_result.add_assertion
126
+ end
127
+ private :add_assertion
128
+
129
+ def add_failure(message, all_locations=caller())
130
+ @test_passed = false
131
+ @_result.add_failure(Failure.new(name, filter_backtrace(all_locations), message))
132
+ end
133
+ private :add_failure
134
+
135
+ def add_error(exception)
136
+ @test_passed = false
137
+ @_result.add_error(Error.new(name, exception))
138
+ end
139
+ private :add_error
140
+
141
+ # Returns a human-readable name for the specific test that
142
+ # this instance of TestCase represents.
143
+ def name
144
+ "#{@method_name}(#{self.class.name})"
145
+ end
146
+
147
+ # Overridden to return #name.
148
+ def to_s
149
+ name
150
+ end
151
+
152
+ # It's handy to be able to compare TestCase instances.
153
+ def ==(other)
154
+ return false unless(other.kind_of?(self.class))
155
+ return false unless(@method_name == other.method_name)
156
+ self.class == other.class
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,80 @@
1
+ #--
2
+ # Author:: Nathaniel Talbott.
3
+ # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
4
+ # License:: Ruby license.
5
+
6
+ require 'test/unit/util/observable'
7
+
8
+ module Test
9
+ module Unit
10
+
11
+ # Collects Test::Unit::Failure and Test::Unit::Error so that
12
+ # they can be displayed to the user. To this end, observers
13
+ # can be added to it, allowing the dynamic updating of, say, a
14
+ # UI.
15
+ class TestResult
16
+ include Util::Observable
17
+
18
+ CHANGED = "CHANGED"
19
+ FAULT = "FAULT"
20
+
21
+ attr_reader(:run_count, :assertion_count)
22
+
23
+ # Constructs a new, empty TestResult.
24
+ def initialize
25
+ @run_count, @assertion_count = 0, 0
26
+ @failures, @errors = Array.new, Array.new
27
+ end
28
+
29
+ # Records a test run.
30
+ def add_run
31
+ @run_count += 1
32
+ notify_listeners(CHANGED, self)
33
+ end
34
+
35
+ # Records a Test::Unit::Failure.
36
+ def add_failure(failure)
37
+ @failures << failure
38
+ notify_listeners(FAULT, failure)
39
+ notify_listeners(CHANGED, self)
40
+ end
41
+
42
+ # Records a Test::Unit::Error.
43
+ def add_error(error)
44
+ @errors << error
45
+ notify_listeners(FAULT, error)
46
+ notify_listeners(CHANGED, self)
47
+ end
48
+
49
+ # Records an individual assertion.
50
+ def add_assertion
51
+ @assertion_count += 1
52
+ notify_listeners(CHANGED, self)
53
+ end
54
+
55
+ # Returns a string contain the recorded runs, assertions,
56
+ # failures and errors in this TestResult.
57
+ def to_s
58
+ "#{run_count} tests, #{assertion_count} assertions, #{failure_count} failures, #{error_count} errors"
59
+ end
60
+
61
+ # Returns whether or not this TestResult represents
62
+ # successful completion.
63
+ def passed?
64
+ return @failures.empty? && @errors.empty?
65
+ end
66
+
67
+ # Returns the number of failures this TestResult has
68
+ # recorded.
69
+ def failure_count
70
+ return @failures.size
71
+ end
72
+
73
+ # Returns the number of errors this TestResult has
74
+ # recorded.
75
+ def error_count
76
+ return @errors.size
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,76 @@
1
+ #--
2
+ #
3
+ # Author:: Nathaniel Talbott.
4
+ # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved.
5
+ # License:: Ruby license.
6
+
7
+ module Test
8
+ module Unit
9
+
10
+ # A collection of tests which can be #run.
11
+ #
12
+ # Note: It is easy to confuse a TestSuite instance with
13
+ # something that has a static suite method; I know because _I_
14
+ # have trouble keeping them straight. Think of something that
15
+ # has a suite method as simply providing a way to get a
16
+ # meaningful TestSuite instance.
17
+ class TestSuite
18
+ attr_reader :name, :tests
19
+
20
+ STARTED = name + "::STARTED"
21
+ FINISHED = name + "::FINISHED"
22
+
23
+ # Creates a new TestSuite with the given name.
24
+ def initialize(name="Unnamed TestSuite")
25
+ @name = name
26
+ @tests = []
27
+ end
28
+
29
+ # Runs the tests and/or suites contained in this
30
+ # TestSuite.
31
+ def run(result, &progress_block)
32
+ yield(STARTED, name)
33
+ @tests.each do |test|
34
+ test.run(result, &progress_block)
35
+ end
36
+ yield(FINISHED, name)
37
+ end
38
+
39
+ # Adds the test to the suite.
40
+ def <<(test)
41
+ @tests << test
42
+ self
43
+ end
44
+
45
+ def delete(test)
46
+ @tests.delete(test)
47
+ end
48
+
49
+ # Retuns the rolled up number of tests in this suite;
50
+ # i.e. if the suite contains other suites, it counts the
51
+ # tests within those suites, not the suites themselves.
52
+ def size
53
+ total_size = 0
54
+ @tests.each { |test| total_size += test.size }
55
+ total_size
56
+ end
57
+
58
+ def empty?
59
+ tests.empty?
60
+ end
61
+
62
+ # Overridden to return the name given the suite at
63
+ # creation.
64
+ def to_s
65
+ @name
66
+ end
67
+
68
+ # It's handy to be able to compare TestSuite instances.
69
+ def ==(other)
70
+ return false unless(other.kind_of?(self.class))
71
+ return false unless(@name == other.name)
72
+ @tests == other.tests
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,127 @@
1
+ #--
2
+ #
3
+ # Author:: Nathaniel Talbott.
4
+ # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved.
5
+ # License:: Ruby license.
6
+
7
+ require 'test/unit/ui/testrunnermediator'
8
+ require 'test/unit/ui/testrunnerutilities'
9
+
10
+ module Test
11
+ module Unit
12
+ module UI
13
+ module Console
14
+
15
+ # Runs a Test::Unit::TestSuite on the console.
16
+ class TestRunner
17
+ extend TestRunnerUtilities
18
+
19
+ # Creates a new TestRunner for running the passed
20
+ # suite. If quiet_mode is true, the output while
21
+ # running is limited to progress dots, errors and
22
+ # failures, and the final result. io specifies
23
+ # where runner output should go to; defaults to
24
+ # STDOUT.
25
+ def initialize(suite, output_level=NORMAL, io=STDOUT)
26
+ if (suite.respond_to?(:suite))
27
+ @suite = suite.suite
28
+ else
29
+ @suite = suite
30
+ end
31
+ @output_level = output_level
32
+ @io = io
33
+ @already_outputted = false
34
+ @faults = []
35
+ end
36
+
37
+ # Begins the test run.
38
+ def start
39
+ setup_mediator
40
+ attach_to_mediator
41
+ return start_mediator
42
+ end
43
+
44
+ private
45
+ def setup_mediator
46
+ @mediator = create_mediator(@suite)
47
+ suite_name = @suite.to_s
48
+ if ( @suite.kind_of?(Module) )
49
+ suite_name = @suite.name
50
+ end
51
+ output("Loaded suite #{suite_name}")
52
+ end
53
+
54
+ def create_mediator(suite)
55
+ return TestRunnerMediator.new(suite)
56
+ end
57
+
58
+ def attach_to_mediator
59
+ @mediator.add_listener(TestResult::FAULT, &method(:add_fault))
60
+ @mediator.add_listener(TestRunnerMediator::STARTED, &method(:started))
61
+ @mediator.add_listener(TestRunnerMediator::FINISHED, &method(:finished))
62
+ @mediator.add_listener(TestCase::STARTED, &method(:test_started))
63
+ @mediator.add_listener(TestCase::FINISHED, &method(:test_finished))
64
+ end
65
+
66
+ def start_mediator
67
+ return @mediator.run_suite
68
+ end
69
+
70
+ def add_fault(fault)
71
+ @faults << fault
72
+ output_single(fault.single_character_display, PROGRESS_ONLY)
73
+ @already_outputted = true
74
+ end
75
+
76
+ def started(result)
77
+ @result = result
78
+ output("Started")
79
+ end
80
+
81
+ def finished(elapsed_time)
82
+ nl
83
+ output("Finished in #{elapsed_time} seconds.")
84
+ @faults.each_with_index do |fault, index|
85
+ nl
86
+ output("%3d) %s" % [index + 1, fault.long_display])
87
+ end
88
+ nl
89
+ output(@result)
90
+ end
91
+
92
+ def test_started(name)
93
+ output_single(name + ": ", VERBOSE)
94
+ end
95
+
96
+ def test_finished(name)
97
+ output_single(".", PROGRESS_ONLY) unless (@already_outputted)
98
+ nl(VERBOSE)
99
+ @already_outputted = false
100
+ end
101
+
102
+ def nl(level=NORMAL)
103
+ output("", level)
104
+ end
105
+
106
+ def output(something, level=NORMAL)
107
+ @io.puts(something) if (output?(level))
108
+ @io.flush
109
+ end
110
+
111
+ def output_single(something, level=NORMAL)
112
+ @io.write(something) if (output?(level))
113
+ @io.flush
114
+ end
115
+
116
+ def output?(level)
117
+ level <= @output_level
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ if __FILE__ == $0
126
+ Test::Unit::UI::Console::TestRunner.start_command_line_test
127
+ end