rubysl-test-unit 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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