rproof 0.0.1
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.
- checksums.yaml +7 -0
- data/LICENSE +674 -0
- data/README.md +9 -0
- data/lib/rproof.rb +16 -0
- data/lib/rproof/abstract_reporter.rb +37 -0
- data/lib/rproof/assertion.rb +18 -0
- data/lib/rproof/censor.rb +52 -0
- data/lib/rproof/composite_reporter.rb +53 -0
- data/lib/rproof/live_reporter.rb +161 -0
- data/lib/rproof/located_info.rb +28 -0
- data/lib/rproof/test.rb +41 -0
- data/lib/rproof/test_result.rb +63 -0
- data/lib/rproof/test_runner.rb +24 -0
- data/lib/rproof/test_suite.rb +60 -0
- data/lib/rproof/version.rb +3 -0
- data/lib/rproof/warning.rb +15 -0
- data/lib/rproof/xml_reporter.rb +86 -0
- metadata +87 -0
data/README.md
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
Configuration to get Rproof working on your machine:
|
2
|
+
|
3
|
+
- clone this project into <local repositery folder>
|
4
|
+
|
5
|
+
- run gem install bundler if Bundler gem is not already install.
|
6
|
+
|
7
|
+
- in <local repositery folder>, run bundle install to install dependencies
|
8
|
+
|
9
|
+
- in <local repositery folder>/sample, run ruby run_rubyunit_test_sample to watch a simple test example
|
data/lib/rproof.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative './rproof/abstract_reporter'
|
2
|
+
require_relative './rproof/assertion'
|
3
|
+
require_relative './rproof/censor'
|
4
|
+
require_relative './rproof/composite_reporter'
|
5
|
+
require_relative './rproof/live_reporter'
|
6
|
+
require_relative './rproof/located_info'
|
7
|
+
require_relative './rproof/test_result'
|
8
|
+
require_relative './rproof/test_runner'
|
9
|
+
require_relative './rproof/test_suite'
|
10
|
+
require_relative './rproof/test'
|
11
|
+
require_relative './rproof/xml_reporter'
|
12
|
+
require_relative './rproof/warning'
|
13
|
+
|
14
|
+
module Rproof
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
########################################################################################################################
|
2
|
+
# Defines the interface of a reporter.
|
3
|
+
########################################################################################################################
|
4
|
+
|
5
|
+
require_relative 'test_result'
|
6
|
+
|
7
|
+
module Rproof
|
8
|
+
class AbstractReporter
|
9
|
+
def report_campaign_begin
|
10
|
+
end
|
11
|
+
|
12
|
+
def report_suite_begin(id, name, description)
|
13
|
+
end
|
14
|
+
|
15
|
+
def report_test_begin(id, name, description)
|
16
|
+
end
|
17
|
+
|
18
|
+
def report_assertion(assertion)
|
19
|
+
end
|
20
|
+
|
21
|
+
def report_warning(warning)
|
22
|
+
end
|
23
|
+
|
24
|
+
def report_exception(exception)
|
25
|
+
end
|
26
|
+
|
27
|
+
def report_test_end(id, test_result)
|
28
|
+
end
|
29
|
+
|
30
|
+
def report_suite_end(id, test_results)
|
31
|
+
end
|
32
|
+
|
33
|
+
# test_results is either a Test_Result or a Test_Result Array
|
34
|
+
def report_campaign_end(test_results, start_time, end_time)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
########################################################################################################################
|
2
|
+
# Stores assertion result information
|
3
|
+
########################################################################################################################
|
4
|
+
|
5
|
+
require_relative 'located_info'
|
6
|
+
|
7
|
+
module Rproof
|
8
|
+
class Assertion < LocatedInfo
|
9
|
+
def initialize(expected, obtained, is_successful, comment)
|
10
|
+
super()
|
11
|
+
@expected = expected
|
12
|
+
@obtained = obtained
|
13
|
+
@is_successful = is_successful
|
14
|
+
@comment = comment
|
15
|
+
end
|
16
|
+
attr_reader :expected, :obtained, :is_successful, :comment
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
########################################################################################################################
|
2
|
+
# Provide various assertion, warning and exception methods
|
3
|
+
########################################################################################################################
|
4
|
+
|
5
|
+
require_relative 'abstract_reporter'
|
6
|
+
require_relative 'assertion'
|
7
|
+
require_relative 'test_result'
|
8
|
+
require_relative 'warning'
|
9
|
+
|
10
|
+
module Rproof
|
11
|
+
class Censor
|
12
|
+
def initialize(reporter, name, description)
|
13
|
+
@reporter = reporter
|
14
|
+
@test_result = TestResult.new name, description
|
15
|
+
end
|
16
|
+
attr_reader :test_result
|
17
|
+
|
18
|
+
def assert_different(expected, obtained, comment)
|
19
|
+
@test_result.add_assertion Assertion.new(expected, obtained, (obtained != expected), comment)
|
20
|
+
@reporter.report_assertion @test_result.assertions.last
|
21
|
+
end
|
22
|
+
|
23
|
+
def assert_equal(expected, obtained, comment)
|
24
|
+
@test_result.add_assertion Assertion.new(expected, obtained, (obtained == expected), comment)
|
25
|
+
@reporter.report_assertion @test_result.assertions.last
|
26
|
+
end
|
27
|
+
|
28
|
+
def assert_exception(expected, comment, &block)
|
29
|
+
error = nil
|
30
|
+
begin
|
31
|
+
block.call
|
32
|
+
rescue Exception => error
|
33
|
+
ensure
|
34
|
+
assert_equal(expected, error.class, comment)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def assert(statement, comment)
|
39
|
+
assert_equal true, statement, comment
|
40
|
+
end
|
41
|
+
|
42
|
+
def warning(message)
|
43
|
+
@test_result.add_warning Warning.new(message)
|
44
|
+
@reporter.report_warning @test_result.warnings.last
|
45
|
+
end
|
46
|
+
|
47
|
+
def log_exception(error)
|
48
|
+
@test_result.add_exception error
|
49
|
+
@reporter.report_exception @test_result.exceptions.last
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
########################################################################################################################
|
2
|
+
#
|
3
|
+
########################################################################################################################
|
4
|
+
|
5
|
+
require_relative 'abstract_reporter'
|
6
|
+
|
7
|
+
module Rproof
|
8
|
+
class CompositeReporter < AbstractReporter
|
9
|
+
def initialize
|
10
|
+
@reporters = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def add(reporter)
|
14
|
+
@reporters << reporter
|
15
|
+
end
|
16
|
+
|
17
|
+
def report_campaign_begin
|
18
|
+
@reporters.each { |r| r.report_campaign_begin }
|
19
|
+
end
|
20
|
+
|
21
|
+
def report_suite_begin(id, name, description)
|
22
|
+
@reporters.each { |r| r.report_suite_begin id, name, description }
|
23
|
+
end
|
24
|
+
|
25
|
+
def report_test_begin(id, name, description)
|
26
|
+
@reporters.each { |r| r.report_test_begin id, name, description }
|
27
|
+
end
|
28
|
+
|
29
|
+
def report_assertion(assertion)
|
30
|
+
@reporters.each { |r| r.report_assertion assertion }
|
31
|
+
end
|
32
|
+
|
33
|
+
def report_warning(warning)
|
34
|
+
@reporters.each { |r| r.report_warning warning }
|
35
|
+
end
|
36
|
+
|
37
|
+
def report_exception(exception)
|
38
|
+
@reporters.each { |r| r.report_exception exception }
|
39
|
+
end
|
40
|
+
|
41
|
+
def report_test_end(id, test_result)
|
42
|
+
@reporters.each { |r| r.report_test_end id, test_result }
|
43
|
+
end
|
44
|
+
|
45
|
+
def report_suite_end(id, test_results)
|
46
|
+
@reporters.each { |r| r.report_suite_end id, test_results }
|
47
|
+
end
|
48
|
+
|
49
|
+
def report_campaign_end(test_results, start_time, end_time)
|
50
|
+
@reporters.each { |r| r.report_campaign_end test_results, start_time, end_time }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
########################################################################################################################
|
2
|
+
# Implements a live reporter: assertion results are shown on-the-flow, with two verbose levels: dotted or full.
|
3
|
+
########################################################################################################################
|
4
|
+
|
5
|
+
require 'colorize'
|
6
|
+
|
7
|
+
require_relative 'abstract_reporter'
|
8
|
+
require_relative 'assertion'
|
9
|
+
|
10
|
+
module Rproof
|
11
|
+
class LiveReporter < AbstractReporter
|
12
|
+
|
13
|
+
OK = '['.bold + 'OK'.green.bold + ']'.bold
|
14
|
+
KO = '['.bold + 'KO'.red.bold + ']'.bold
|
15
|
+
WA = '['.bold + 'W!'.yellow.bold + ']'.bold
|
16
|
+
WARNING = '/!\\ WARNING /!\\'.yellow.bold
|
17
|
+
|
18
|
+
STATUS = {
|
19
|
+
untested: 'untested'.bold.on_blue,
|
20
|
+
exception: 'exception'.bold.on_magenta,
|
21
|
+
failed: 'failed'.bold.red,
|
22
|
+
warning: 'succeed'.bold.green + ' with ' + 'warnings'.bold.yellow,
|
23
|
+
succeed: 'succeed'.bold.green
|
24
|
+
}
|
25
|
+
|
26
|
+
INDENT = " "
|
27
|
+
|
28
|
+
def initialize(verbose: false, cli_width: 80, justification: ([60, cli_width - 100].max))
|
29
|
+
@verbose = verbose
|
30
|
+
@justification = justification
|
31
|
+
end
|
32
|
+
|
33
|
+
def report_campaign_begin
|
34
|
+
if @verbose
|
35
|
+
puts "Running test campaign..."
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def report_suite_begin(id, name, description)
|
40
|
+
end
|
41
|
+
|
42
|
+
def report_test_begin(id, name, description)
|
43
|
+
if @verbose
|
44
|
+
puts
|
45
|
+
puts '-' * 120
|
46
|
+
puts "Running #{name}"
|
47
|
+
puts description
|
48
|
+
puts
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def report_assertion(assertion)
|
53
|
+
if @verbose
|
54
|
+
if assertion.is_successful
|
55
|
+
puts "#{INDENT}#{(assertion.comment + ' ').ljust(@justification, '_')} #{OK} obtained #{assertion.obtained.inspect}"
|
56
|
+
else
|
57
|
+
puts "#{INDENT}#{(assertion.comment + ' ').ljust(@justification, '_')} #{KO} expected #{assertion.expected.inspect}"
|
58
|
+
puts "#{INDENT}#{' ' * @justification} obtained #{assertion.obtained.inspect}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def report_warning(warning)
|
64
|
+
if @verbose
|
65
|
+
puts "#{INDENT}#{WARNING} #{warning.message}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def report_exception(exception)
|
70
|
+
if @verbose
|
71
|
+
puts "#{INDENT}exception: " + exception.message.bold.on_magenta
|
72
|
+
puts INDENT + exception.backtrace.join("\n#{INDENT}").bold.magenta
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def report_test_end(id, test_result)
|
77
|
+
if @verbose
|
78
|
+
puts
|
79
|
+
puts "End: #{STATUS[test_result.status]}. #{test_result.successes_nb} successes, #{test_result.failures_nb} failures, #{test_result.warnings.count} warnings, #{test_result.exceptions.count} exceptions"
|
80
|
+
else
|
81
|
+
case
|
82
|
+
when !test_result.exceptions.empty? then dot = "E".bold.on_magenta
|
83
|
+
when !test_result.failures.empty? then dot = "F".bold.red
|
84
|
+
when !test_result.warnings.empty? then dot = "W".bold.yellow
|
85
|
+
else dot = "."
|
86
|
+
end
|
87
|
+
print dot
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def report_suite_end(id, test_results)
|
92
|
+
end
|
93
|
+
|
94
|
+
def report_campaign_end(test_results, start_time, end_time)
|
95
|
+
if test_results.is_a? Array # if false, campaign was a single test
|
96
|
+
campaign_status = :succeed
|
97
|
+
successes_nb = 0
|
98
|
+
failures_nb = 0
|
99
|
+
warnings_nb = 0
|
100
|
+
exceptions_nb = 0
|
101
|
+
|
102
|
+
results = test_results.flatten
|
103
|
+
results.each do |result|
|
104
|
+
campaign_status = TestResult.get_worse_status campaign_status, result.status
|
105
|
+
successes_nb += result.successes_nb
|
106
|
+
failures_nb += result.failures_nb
|
107
|
+
warnings_nb += result.warnings.count
|
108
|
+
exceptions_nb += result.exceptions.count
|
109
|
+
end
|
110
|
+
if @verbose
|
111
|
+
puts
|
112
|
+
puts "End of campaign: #{STATUS[campaign_status]}. #{successes_nb} successes, #{failures_nb} failures, #{warnings_nb} warnings, #{exceptions_nb} exceptions"
|
113
|
+
else
|
114
|
+
puts
|
115
|
+
puts "#{STATUS[campaign_status]} in #{end_time - start_time}. #{successes_nb} successes, #{failures_nb} failures, #{warnings_nb} warnings, #{exceptions_nb} exceptions"
|
116
|
+
if warnings_nb > 0
|
117
|
+
puts
|
118
|
+
puts " warnings:"
|
119
|
+
results.each do |result|
|
120
|
+
result.warnings.each do |warning|
|
121
|
+
full_comment = "in #{warning.file}:#{warning.line}:#{warning.method}: #{warning.message} "
|
122
|
+
puts " #{full_comment.ljust(@justification, '_')} #{WA}"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
if failures_nb > 0
|
127
|
+
puts
|
128
|
+
puts " failures:"
|
129
|
+
results.each do |result|
|
130
|
+
result.failures.each do |failure|
|
131
|
+
full_comment = "in #{failure.file}:#{failure.line}:#{failure.method}: #{failure.comment} "
|
132
|
+
puts " #{full_comment.ljust(@justification, '_')} #{KO} #{"expected".bold} #{failure.expected.inspect}, #{"obtained".bold} #{failure.obtained.inspect}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
if exceptions_nb > 0
|
137
|
+
print_header('exceptions')
|
138
|
+
print_exceptions(results)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
def print_header(header)
|
147
|
+
puts
|
148
|
+
puts " #{header}:"
|
149
|
+
end
|
150
|
+
|
151
|
+
def print_exceptions(results)
|
152
|
+
results.each do |result|
|
153
|
+
result.exceptions.each do |exception|
|
154
|
+
puts " " + exception.message.bold.on_magenta
|
155
|
+
puts " " + exception.backtrace.join("\n ").bold.magenta
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
########################################################################################################################
|
2
|
+
# Determines and stored location data for a test information
|
3
|
+
########################################################################################################################
|
4
|
+
|
5
|
+
require 'pathname'
|
6
|
+
|
7
|
+
module Rproof
|
8
|
+
class LocatedInfo
|
9
|
+
def initialize
|
10
|
+
@pathname = nil
|
11
|
+
@file = nil
|
12
|
+
@line = nil
|
13
|
+
@method = nil
|
14
|
+
caller.each do |line|
|
15
|
+
matches = line.match /^.*\.rb/
|
16
|
+
pathname = Pathname.new(matches[0])
|
17
|
+
if not pathname.to_s.match(/lib\/(censor)|(assertion)|(warning)\.rb$/) and nil == @file # ignore lib files, until test definition file
|
18
|
+
@pathname = pathname
|
19
|
+
@file = pathname.basename
|
20
|
+
matches = line.match /^.*\.rb:(\d*):in `([^']*)'/
|
21
|
+
@line = matches[1]
|
22
|
+
@method = matches[2]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
attr_reader :pathname, :file, :line, :method
|
27
|
+
end
|
28
|
+
end
|
data/lib/rproof/test.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
########################################################################################################################
|
2
|
+
# Define an atomic test. This class has to be inherited in child classes, where the developer writes test code.
|
3
|
+
########################################################################################################################
|
4
|
+
|
5
|
+
require_relative 'abstract_reporter'
|
6
|
+
require_relative 'censor'
|
7
|
+
|
8
|
+
module Rproof
|
9
|
+
class Test
|
10
|
+
def initialize(reporter, name, description = nil)
|
11
|
+
@id = object_id
|
12
|
+
@reporter = reporter
|
13
|
+
@name = name
|
14
|
+
@description = description
|
15
|
+
@censor = Censor.new reporter, name, description
|
16
|
+
end
|
17
|
+
|
18
|
+
def setup
|
19
|
+
end
|
20
|
+
|
21
|
+
def run
|
22
|
+
raise "This method has to be overriden. Please redefine 'run' method with your test code."
|
23
|
+
end
|
24
|
+
|
25
|
+
def clean_up
|
26
|
+
end
|
27
|
+
|
28
|
+
def execute
|
29
|
+
@reporter.report_test_begin(@id, @name, @description)
|
30
|
+
begin
|
31
|
+
setup
|
32
|
+
run
|
33
|
+
clean_up
|
34
|
+
rescue Exception => e
|
35
|
+
@censor.log_exception e
|
36
|
+
end
|
37
|
+
@reporter.report_test_end(@id, @censor.test_result)
|
38
|
+
@censor.test_result
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require_relative 'assertion'
|
2
|
+
|
3
|
+
module Rproof
|
4
|
+
class TestResult
|
5
|
+
def initialize(name, description)
|
6
|
+
@name = name
|
7
|
+
@description = description
|
8
|
+
@assertions = []
|
9
|
+
@warnings = []
|
10
|
+
@exceptions = []
|
11
|
+
end
|
12
|
+
attr_reader :name, :description, :assertions, :warnings, :exceptions
|
13
|
+
|
14
|
+
def add_assertion(assertion)
|
15
|
+
@assertions << assertion
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_warning(warning)
|
19
|
+
@warnings << warning
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_exception(exception)
|
23
|
+
@exceptions << exception
|
24
|
+
end
|
25
|
+
|
26
|
+
def successes_nb
|
27
|
+
successes.count
|
28
|
+
end
|
29
|
+
|
30
|
+
def failures_nb
|
31
|
+
failures.count
|
32
|
+
end
|
33
|
+
|
34
|
+
def successes
|
35
|
+
@assertions.select { |assertion| assertion.is_successful }
|
36
|
+
end
|
37
|
+
|
38
|
+
def failures
|
39
|
+
@assertions.select { |assertion| not assertion.is_successful }
|
40
|
+
end
|
41
|
+
|
42
|
+
def status
|
43
|
+
if @exceptions.count > 0
|
44
|
+
:exception
|
45
|
+
elsif failures_nb > 0
|
46
|
+
:failed
|
47
|
+
else
|
48
|
+
:succeed
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Return worse status between the two
|
53
|
+
def self.get_worse_status(status_1, status_2)
|
54
|
+
if [status_1, status_2].include? :exception
|
55
|
+
:exception
|
56
|
+
elsif [status_1, status_2].include? :failed
|
57
|
+
:failed
|
58
|
+
else
|
59
|
+
:succeed
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|