theorem 1.1.0 → 1.2.2
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 +4 -4
- data/src/harness.rb +0 -22
- data/src/publishers/stdout_reporter.rb +111 -0
- data/src/theorem/beaker.rb +8 -0
- data/src/theorem/completed_test.rb +5 -2
- data/src/theorem/harness.rb +36 -17
- data/src/theorem/hypothesis.rb +13 -3
- data/src/theorem/notation.rb +33 -0
- data/src/theorem/registry.rb +9 -23
- data/src/theorem/test.rb +60 -11
- data/src/theorem.rb +1 -14
- metadata +32 -3
- data/src/stdout_reporter.rb +0 -70
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fa09d87e0b219e171e02728791f787a6ecd68a759e8a21143e85302361f68a1d
|
|
4
|
+
data.tar.gz: 739e1c4e6e19a3145d7c87c8ea688d10be70cce45735939e7f5d0bdf1817d385
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 49ef938d77de1eacfd29a61c312acb396de525adb5c9b9699d3698cd31d8511c05665c560b55de61bc0fb9884024b32dbc61771cc0e44ae5267f26301cd46a18
|
|
7
|
+
data.tar.gz: 2fe7a59bec06dfd7b14c02e9245cdd0e9ca1ccf013f83254706cccd8e72a3aba9ac3048d9b0ed083b14f3d3e552c8cdd1b42ed75d24cc6ee67581740e5048f7f
|
data/src/harness.rb
CHANGED
|
@@ -16,26 +16,4 @@ module Theorem
|
|
|
16
16
|
filtered_registry(options)
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
|
-
|
|
20
|
-
# module retry harness
|
|
21
|
-
module RetryHarness
|
|
22
|
-
include Control::Harness
|
|
23
|
-
|
|
24
|
-
on_run do |tests|
|
|
25
|
-
arr_of_tests = tests.map { |test| { test: test, index: 0 } }
|
|
26
|
-
|
|
27
|
-
final_results = []
|
|
28
|
-
arr_of_tests.each do |test|
|
|
29
|
-
test[:index] += 1
|
|
30
|
-
results = test[:test].run!
|
|
31
|
-
if results.any?(&:failed?) && test[:index] <= 3
|
|
32
|
-
puts "Retrying iteration: #{test[:index]}\n#{results.map(&:full_name).join("\n")}"
|
|
33
|
-
redo
|
|
34
|
-
end
|
|
35
|
-
final_results.concat results
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
final_results
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
19
|
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../theorem/reporter'
|
|
4
|
+
|
|
5
|
+
module Theorem
|
|
6
|
+
module StringRefinements
|
|
7
|
+
refine String do
|
|
8
|
+
# colorization
|
|
9
|
+
def colorize(color_code)
|
|
10
|
+
"\e[#{color_code}m#{self}\e[0m"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def red
|
|
14
|
+
colorize(31)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def green
|
|
18
|
+
colorize(32)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def yellow
|
|
22
|
+
colorize(33)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def blue
|
|
26
|
+
colorize(34)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def pink
|
|
30
|
+
colorize(35)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def light_blue
|
|
34
|
+
colorize(36)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Default Stdout reporter
|
|
40
|
+
module StdoutReporter
|
|
41
|
+
extend Control::Reporter
|
|
42
|
+
using StringRefinements
|
|
43
|
+
|
|
44
|
+
subscribe :test_finished do |test|
|
|
45
|
+
print test.failed? ? 'x'.red : '.'.green
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
subscribe :suite_finished do |results, duration|
|
|
49
|
+
puts "\n"
|
|
50
|
+
report_summary(results)
|
|
51
|
+
|
|
52
|
+
failed_tests = results.select(&:failed?)
|
|
53
|
+
|
|
54
|
+
report_failures(failed_tests)
|
|
55
|
+
|
|
56
|
+
puts "\nTotal time: #{duration} seconds"
|
|
57
|
+
puts "Total tests: #{results.size}\n"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def inflate_percentiles(tests)
|
|
61
|
+
sorted = tests.reject { |t| t.duration.nil? }.sort_by(&:duration)
|
|
62
|
+
tests.each_with_object([]) do |test, arr|
|
|
63
|
+
_, below = sorted.partition do |duration_test|
|
|
64
|
+
if test.duration.nil?
|
|
65
|
+
true
|
|
66
|
+
else
|
|
67
|
+
test.duration >= duration_test.duration
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
hash = {}
|
|
71
|
+
hash[:percentile] = (below.size.to_f / (sorted.size.to_f + 1)) * 100
|
|
72
|
+
hash[:test] = test
|
|
73
|
+
arr << hash
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def report_summary(tests)
|
|
78
|
+
inflated = inflate_percentiles(tests)
|
|
79
|
+
|
|
80
|
+
top_20 = 80 / (100.0 * (tests.size + 1).to_f)
|
|
81
|
+
lowest_20 = 20 / (100.0 * (tests.size + 1).to_f)
|
|
82
|
+
|
|
83
|
+
inflated.each do |test|
|
|
84
|
+
icon = test[:test].failed? ? '❌'.red : '✓'.green
|
|
85
|
+
puts "#{icon} #{test[:test].full_name.blue} : #{duration(test)}"
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def duration(test)
|
|
90
|
+
return 'Not run' if test[:test].duration.nil?
|
|
91
|
+
|
|
92
|
+
str = "#{format('%<num>0.10f', num: test[:test].duration)} seconds"
|
|
93
|
+
rank = test[:percentile]
|
|
94
|
+
if rank < 10
|
|
95
|
+
str.red
|
|
96
|
+
elsif rank > 90
|
|
97
|
+
str.green
|
|
98
|
+
elsif rank < 30
|
|
99
|
+
str.yellow
|
|
100
|
+
else
|
|
101
|
+
str
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def report_failures(tests)
|
|
106
|
+
tests.each do |failure|
|
|
107
|
+
puts "\n\nFailure in #{failure.full_name}\nError: #{failure.error.message.to_s.red}\nBacktrace:\n------\n#{failure.error.backtrace.map(&:red).join("\n")}"
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
data/src/theorem/beaker.rb
CHANGED
|
@@ -9,6 +9,10 @@ module Theorem
|
|
|
9
9
|
@ctx = ctx
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
+
def name
|
|
13
|
+
@test.name
|
|
14
|
+
end
|
|
15
|
+
|
|
12
16
|
def run!
|
|
13
17
|
@test.run!(@ctx)
|
|
14
18
|
end
|
|
@@ -54,6 +58,10 @@ module Theorem
|
|
|
54
58
|
end
|
|
55
59
|
end
|
|
56
60
|
|
|
61
|
+
def empty?
|
|
62
|
+
@state.empty?
|
|
63
|
+
end
|
|
64
|
+
|
|
57
65
|
def reverse_prepare(&block)
|
|
58
66
|
@state.unshift block
|
|
59
67
|
end
|
|
@@ -4,11 +4,14 @@ module Theorem
|
|
|
4
4
|
module Control
|
|
5
5
|
# error class
|
|
6
6
|
class CompletedTest
|
|
7
|
-
attr_reader :test, :
|
|
7
|
+
attr_reader :test, :duration
|
|
8
|
+
attr_accessor :error, :notary
|
|
8
9
|
|
|
9
|
-
def initialize(test, error = nil)
|
|
10
|
+
def initialize(test, error = nil, notary:, duration: nil)
|
|
10
11
|
@test = test
|
|
11
12
|
@error = error
|
|
13
|
+
@notary = notary
|
|
14
|
+
@duration = duration
|
|
12
15
|
end
|
|
13
16
|
|
|
14
17
|
def full_name
|
data/src/theorem/harness.rb
CHANGED
|
@@ -11,9 +11,21 @@ module Theorem
|
|
|
11
11
|
mod.define_singleton_method :included do |inner|
|
|
12
12
|
inner.define_singleton_method :run! do |options: {}|
|
|
13
13
|
tests = inner.instance_exec options, &mod.test_loader
|
|
14
|
+
|
|
15
|
+
inner.suite_started_subscribers.each do |subscriber|
|
|
16
|
+
subscriber.call tests.map(&:tests).flatten.map do |test|
|
|
17
|
+
{ name: test.name, metadata: test.metadata }
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
14
22
|
results = inner.instance_exec tests, options, &mod.run_loader
|
|
15
|
-
|
|
16
|
-
|
|
23
|
+
ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
24
|
+
|
|
25
|
+
duration = ending - starting
|
|
26
|
+
|
|
27
|
+
inner.suite_finished_subscribers.each do |subscriber|
|
|
28
|
+
subscriber.call(results, duration)
|
|
17
29
|
end
|
|
18
30
|
exit results.any?(&:failed?) ? 1 : 0
|
|
19
31
|
end
|
|
@@ -22,19 +34,6 @@ module Theorem
|
|
|
22
34
|
|
|
23
35
|
# harness helpers
|
|
24
36
|
module ClassMethods
|
|
25
|
-
DEFAULT_LOADER = ->(options) do
|
|
26
|
-
directory = options[:directory] || '.'
|
|
27
|
-
|
|
28
|
-
ExtendedDir.require_all("./#{directory}")
|
|
29
|
-
|
|
30
|
-
registry
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
DEFAULT_RUNNER = ->(tests, options) do
|
|
34
|
-
tests.each_with_object([]) do |test, memo|
|
|
35
|
-
memo.concat test.run!
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
37
|
|
|
39
38
|
def load_tests(&block)
|
|
40
39
|
@on_load_tests = block
|
|
@@ -45,11 +44,31 @@ module Theorem
|
|
|
45
44
|
end
|
|
46
45
|
|
|
47
46
|
def run_loader
|
|
48
|
-
@on_run ||
|
|
47
|
+
@on_run || default_runner
|
|
49
48
|
end
|
|
50
49
|
|
|
51
50
|
def test_loader
|
|
52
|
-
@on_load_tests ||
|
|
51
|
+
@on_load_tests || default_loader
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def default_loader
|
|
57
|
+
lambda do |options|
|
|
58
|
+
directory = options[:directory] || '.'
|
|
59
|
+
|
|
60
|
+
ExtendedDir.require_all("./#{directory}")
|
|
61
|
+
|
|
62
|
+
registry
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def default_runner
|
|
67
|
+
lambda do |tests, options|
|
|
68
|
+
tests.each_with_object([]) do |test, memo|
|
|
69
|
+
memo.concat test.run!
|
|
70
|
+
end
|
|
71
|
+
end
|
|
53
72
|
end
|
|
54
73
|
end
|
|
55
74
|
end
|
data/src/theorem/hypothesis.rb
CHANGED
|
@@ -15,6 +15,16 @@ module Theorem
|
|
|
15
15
|
mod
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
+
klass.attr_reader :notary
|
|
19
|
+
|
|
20
|
+
klass.define_method :initialize do
|
|
21
|
+
@notary = Notation.new
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
klass.define_method :notate do |&block|
|
|
25
|
+
block.call(@notary)
|
|
26
|
+
end
|
|
27
|
+
|
|
18
28
|
klass.extend ClassMethods
|
|
19
29
|
klass.instance_eval do
|
|
20
30
|
@before_all ||= Beaker.new
|
|
@@ -29,9 +39,9 @@ module Theorem
|
|
|
29
39
|
mod.add_to_registry(klass)
|
|
30
40
|
end
|
|
31
41
|
|
|
32
|
-
mod.const_set(:Beaker, Beaker)
|
|
33
|
-
mod.const_set(:Test, Test)
|
|
34
|
-
mod.const_set(:CompletedTest, CompletedTest)
|
|
42
|
+
mod.const_set(:Beaker, Beaker) unless mod.const_defined?(:Beaker)
|
|
43
|
+
mod.const_set(:Test, Test) unless mod.const_defined?(:Test)
|
|
44
|
+
mod.const_set(:CompletedTest, CompletedTest) unless mod.const_defined?(:CompletedTest)
|
|
35
45
|
mod.extend(Registry)
|
|
36
46
|
end
|
|
37
47
|
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Theorem
|
|
4
|
+
module Control
|
|
5
|
+
class Notation
|
|
6
|
+
def initialize(state = {})
|
|
7
|
+
@state = state
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def write(key, value)
|
|
11
|
+
@state[key] = value
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def read(key)
|
|
15
|
+
@state[key]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def dump
|
|
19
|
+
@state
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def merge(notary)
|
|
23
|
+
Notation.new(@state.merge(notary.dump))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def edit(key, &block)
|
|
27
|
+
data = read(key)
|
|
28
|
+
block.call(data)
|
|
29
|
+
write(key, data)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
data/src/theorem/registry.rb
CHANGED
|
@@ -28,31 +28,17 @@ module Theorem
|
|
|
28
28
|
registry << klass
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def extra_event_subscribers
|
|
37
|
-
@extra_events || []
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def on_completed_test(&block)
|
|
41
|
-
@completed_tests ||= []
|
|
42
|
-
@completed_tests << block
|
|
43
|
-
end
|
|
31
|
+
%i[suite_started test_started test_finished suite_finished].each do |method|
|
|
32
|
+
define_method method do |&block|
|
|
33
|
+
instance_variable_set("@#{method}_subscribers", []) unless instance_variable_get("@#{method}_subscribers")
|
|
34
|
+
instance_variable_get("@#{method}_subscribers").append(block)
|
|
35
|
+
end
|
|
44
36
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
end
|
|
37
|
+
define_method "#{method}_subscribers" do
|
|
38
|
+
return [] unless instance_variable_get("@#{method}_subscribers")
|
|
48
39
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
@completed_suites << block
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def completed_suite_subscribers
|
|
55
|
-
@completed_suites || []
|
|
40
|
+
instance_variable_get("@#{method}_subscribers")
|
|
41
|
+
end
|
|
56
42
|
end
|
|
57
43
|
end
|
|
58
44
|
end
|
data/src/theorem/test.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
require_relative './beaker'
|
|
3
|
+
require_relative 'notation'
|
|
3
4
|
|
|
4
5
|
module Theorem
|
|
5
6
|
module Control
|
|
@@ -11,14 +12,19 @@ module Theorem
|
|
|
11
12
|
@block = block
|
|
12
13
|
@arguments = arguments
|
|
13
14
|
@metadata = metadata
|
|
15
|
+
@notary = Notation.new
|
|
14
16
|
end
|
|
15
17
|
|
|
16
|
-
attr_reader :block, :name, :arguments, :namespace, :metadata
|
|
18
|
+
attr_reader :block, :name, :arguments, :namespace, :metadata, :notary
|
|
17
19
|
|
|
18
20
|
def full_name
|
|
19
21
|
"#{namespace} #{name}"
|
|
20
22
|
end
|
|
21
23
|
|
|
24
|
+
def notate(&block)
|
|
25
|
+
block.call(notary)
|
|
26
|
+
end
|
|
27
|
+
|
|
22
28
|
def run!(ctx)
|
|
23
29
|
ctx.instance_exec self, **arguments, &block
|
|
24
30
|
end
|
|
@@ -100,32 +106,67 @@ module Theorem
|
|
|
100
106
|
def run!
|
|
101
107
|
test_case = new
|
|
102
108
|
|
|
109
|
+
# run before all beakers to create state in test case
|
|
103
110
|
before_failures = run_before_all_beakers(test_case)
|
|
111
|
+
|
|
104
112
|
if before_failures.any?
|
|
113
|
+
before_failures.each do |failure|
|
|
114
|
+
publish_test_completion(failure)
|
|
115
|
+
end
|
|
105
116
|
return before_failures
|
|
106
117
|
end
|
|
107
118
|
|
|
119
|
+
# duplicate the before_all arrangement for the after all hook
|
|
120
|
+
duplicate_test_case = test_case.clone
|
|
121
|
+
|
|
108
122
|
results = []
|
|
109
123
|
@tests.each do |test|
|
|
124
|
+
test_start = clock_time
|
|
125
|
+
|
|
126
|
+
publish_test_start(test)
|
|
127
|
+
|
|
110
128
|
error ||= run_before_each_beakers(test_case)
|
|
111
|
-
error ||= run_test(test, test_case)
|
|
112
|
-
error ||= run_after_each_beakers(test_case)
|
|
113
129
|
|
|
114
|
-
|
|
115
|
-
|
|
130
|
+
before_test_case = test_case.clone
|
|
131
|
+
error ||= run_test(test, before_test_case)
|
|
132
|
+
error ||= run_after_each_beakers(before_test_case)
|
|
133
|
+
|
|
134
|
+
notary = test_case.notary.merge(test.notary)
|
|
135
|
+
|
|
136
|
+
duration = clock_time - test_start
|
|
137
|
+
|
|
138
|
+
completed_test = CompletedTest.new(test, error, duration: duration, notary: notary.dump)
|
|
139
|
+
|
|
140
|
+
# publish_early if there are no after_all beakers
|
|
141
|
+
publish_test_completion(completed_test) if @after_all.empty?
|
|
142
|
+
|
|
116
143
|
results << completed_test
|
|
117
144
|
end
|
|
118
145
|
|
|
119
|
-
after_failures = run_after_all_beakers(
|
|
146
|
+
after_failures = run_after_all_beakers(results, duplicate_test_case)
|
|
147
|
+
|
|
120
148
|
if after_failures.any?
|
|
149
|
+
after_failures.each do |failure|
|
|
150
|
+
publish_test_completion(failure)
|
|
151
|
+
end
|
|
121
152
|
return after_failures
|
|
122
153
|
end
|
|
123
154
|
|
|
155
|
+
results.each do |completed_test|
|
|
156
|
+
# merge any after_all notations
|
|
157
|
+
completed_test.notary.merge!(duplicate_test_case.notary.dump)
|
|
158
|
+
publish_test_completion(completed_test) unless @after_all.empty?
|
|
159
|
+
end
|
|
160
|
+
|
|
124
161
|
results
|
|
125
162
|
end
|
|
126
163
|
|
|
127
164
|
private
|
|
128
165
|
|
|
166
|
+
def clock_time
|
|
167
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
168
|
+
end
|
|
169
|
+
|
|
129
170
|
def run_test(test, test_case)
|
|
130
171
|
if @around.empty?
|
|
131
172
|
begin
|
|
@@ -141,7 +182,7 @@ module Theorem
|
|
|
141
182
|
end
|
|
142
183
|
end
|
|
143
184
|
|
|
144
|
-
def run_after_all_beakers(test_case)
|
|
185
|
+
def run_after_all_beakers(results, test_case)
|
|
145
186
|
@after_all.run!(test_case)
|
|
146
187
|
|
|
147
188
|
@parent_after_all&.each do |beaker|
|
|
@@ -152,9 +193,12 @@ module Theorem
|
|
|
152
193
|
rescue Exception => error
|
|
153
194
|
Theorem.handle_exception(error)
|
|
154
195
|
|
|
155
|
-
|
|
156
|
-
|
|
196
|
+
results.each do |test|
|
|
197
|
+
test.error = error
|
|
198
|
+
test.notary = test_case.notary
|
|
157
199
|
end
|
|
200
|
+
|
|
201
|
+
results
|
|
158
202
|
end
|
|
159
203
|
|
|
160
204
|
def run_after_each_beakers(test_case)
|
|
@@ -192,16 +236,21 @@ module Theorem
|
|
|
192
236
|
Theorem.handle_exception(error)
|
|
193
237
|
|
|
194
238
|
@tests.map do |test|
|
|
195
|
-
CompletedTest.new(test, error)
|
|
239
|
+
CompletedTest.new(test, error, notary: test_case.notary)
|
|
196
240
|
end
|
|
197
241
|
end
|
|
198
242
|
|
|
199
243
|
def publish_test_completion(completed_test)
|
|
200
|
-
control.
|
|
244
|
+
control.test_finished_subscribers.each do |subscriber|
|
|
201
245
|
subscriber.call(completed_test)
|
|
202
246
|
end
|
|
203
247
|
end
|
|
204
248
|
|
|
249
|
+
def publish_test_start(test)
|
|
250
|
+
control.test_started_subscribers.each do |subscriber|
|
|
251
|
+
subscriber.call(test)
|
|
252
|
+
end
|
|
253
|
+
end
|
|
205
254
|
end
|
|
206
255
|
end
|
|
207
256
|
end
|
data/src/theorem.rb
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
require_relative 'theorem/hypothesis'
|
|
2
2
|
require_relative 'harness'
|
|
3
3
|
require_relative 'experiment'
|
|
4
|
-
require_relative 'stdout_reporter'
|
|
5
|
-
|
|
4
|
+
require_relative 'publishers/stdout_reporter'
|
|
6
5
|
require_relative 'theorem/harness'
|
|
7
6
|
require 'json'
|
|
8
7
|
|
|
@@ -45,18 +44,6 @@ module Theorem
|
|
|
45
44
|
mod.run!(options: options)
|
|
46
45
|
end
|
|
47
46
|
|
|
48
|
-
module JsonReporter
|
|
49
|
-
extend Control::Reporter
|
|
50
|
-
|
|
51
|
-
subscribe :on_completed_suite do |results|
|
|
52
|
-
results = results.map do |result|
|
|
53
|
-
{ name: result.full_name, failed: result.failed? }
|
|
54
|
-
end
|
|
55
|
-
puts results.to_json
|
|
56
|
-
puts "\n\n"
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
47
|
module Hypothesis
|
|
61
48
|
include Control::Hypothesis
|
|
62
49
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: theorem
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sean Gregory
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-04-
|
|
11
|
+
date: 2022-04-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: extended_dir
|
|
@@ -80,6 +80,34 @@ dependencies:
|
|
|
80
80
|
- - ">="
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: '0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: simplecov
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: simplecov-cobertura
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - ">="
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - ">="
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0'
|
|
83
111
|
description: simple and extensible test library toolkit
|
|
84
112
|
email: sean.christopher.gregory@gmail.com
|
|
85
113
|
executables:
|
|
@@ -90,12 +118,13 @@ files:
|
|
|
90
118
|
- bin/theorize
|
|
91
119
|
- src/experiment.rb
|
|
92
120
|
- src/harness.rb
|
|
93
|
-
- src/stdout_reporter.rb
|
|
121
|
+
- src/publishers/stdout_reporter.rb
|
|
94
122
|
- src/theorem.rb
|
|
95
123
|
- src/theorem/beaker.rb
|
|
96
124
|
- src/theorem/completed_test.rb
|
|
97
125
|
- src/theorem/harness.rb
|
|
98
126
|
- src/theorem/hypothesis.rb
|
|
127
|
+
- src/theorem/notation.rb
|
|
99
128
|
- src/theorem/registry.rb
|
|
100
129
|
- src/theorem/reporter.rb
|
|
101
130
|
- src/theorem/test.rb
|
data/src/stdout_reporter.rb
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative './theorem/reporter'
|
|
4
|
-
|
|
5
|
-
module Theorem
|
|
6
|
-
module StringRefinements
|
|
7
|
-
refine String do
|
|
8
|
-
# colorization
|
|
9
|
-
def colorize(color_code)
|
|
10
|
-
"\e[#{color_code}m#{self}\e[0m"
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def red
|
|
14
|
-
colorize(31)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def green
|
|
18
|
-
colorize(32)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def yellow
|
|
22
|
-
colorize(33)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def blue
|
|
26
|
-
colorize(34)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def pink
|
|
30
|
-
colorize(35)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def light_blue
|
|
34
|
-
colorize(36)
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
# Default Stdout reporter
|
|
40
|
-
module StdoutReporter
|
|
41
|
-
extend Control::Reporter
|
|
42
|
-
using StringRefinements
|
|
43
|
-
|
|
44
|
-
subscribe :on_completed_test do |test|
|
|
45
|
-
print test.failed? ? 'x'.red : '.'.green
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
subscribe :on_completed_suite do |results|
|
|
49
|
-
puts "\n"
|
|
50
|
-
report_summary(results)
|
|
51
|
-
|
|
52
|
-
failed_tests = results.select(&:failed?)
|
|
53
|
-
|
|
54
|
-
report_failures(failed_tests)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def report_summary(tests)
|
|
58
|
-
tests.each do |test|
|
|
59
|
-
icon = test.failed? ? '❌'.red : '✓'.green
|
|
60
|
-
puts "#{icon} #{test.full_name.blue}"
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def report_failures(tests)
|
|
65
|
-
tests.each do |failure|
|
|
66
|
-
puts "Failure in #{failure.full_name}\nError: #{failure.error.message.to_s.red}\nBacktrace:\n------\n#{failure.error.backtrace.map(&:red).join("\n")}"
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|