theorem 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2707643c05984ddc7bb49ef7f536fad90dc70ddc7fa058ec031f3945df8e4188
4
- data.tar.gz: 173b64d78b6de42218ebb90714c651a459e1ef377492840985ae8f5c0ae94a7f
3
+ metadata.gz: e3451c37e94f11e1fed722a6ab987454f8ccaa7d52edcc906ef0635cb92d177b
4
+ data.tar.gz: 544bcaef77540b26c750741bffd35ef363c331e155f1ca49c99696959ff21eae
5
5
  SHA512:
6
- metadata.gz: e1f9df341383f804e7437a2193e2c9cd6978861d8dd3351533b7f14f059e3fd8e941e865c455325edcfa724da490549af329fbf5cd7fdd460333d1105fefeccc
7
- data.tar.gz: c9fd46000ef01e28b7f63f4c7512f599732004f129938085585b3725b8bf0abbea88961fea7048bdb5d8753dffb52b2228c4c0dacc24983668e2f3fdd2293193
6
+ metadata.gz: 9963c7729eeaedbf7b9ec575931d2918630d04244eecd0c6d9b5178636edc20ec1867f4bf2a33e30527481cb76ee3e56dd140124ffd279e808d977bee25edd6b
7
+ data.tar.gz: c2224d035456e70630851b8f1d8acf1e4519b7310c1805ce1ec45c98689138b5ae0cea04cb582e4ec8aad67db376d42a68235394516589813c4264321aed7aa0
data/bin/theorize CHANGED
@@ -1,7 +1,18 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
- require_relative '../src/harness'
3
+ require 'slop'
4
+ require_relative '../src/theorem'
4
5
 
5
- path = ARGV[0] || '.'
6
+ opts = Slop.parse do |o|
7
+ o.array '--require', 'files to require', delimiter: ','
8
+ o.string '-m', '--module', 'module (default: Theorem::Hypothesis)', default: 'Theorem::Hypothesis'
9
+ o.string '-h', '--harness', 'harness (default: Theorem::Hypothesis)', default: 'Theorem::Harness'
10
+ o.array '-p', '--publisher', 'publishers (default: Theorem::StdoutReporter)', delimiter: ',', default: ['Theorem::StdoutReporter']
11
+ o.string '-d', '--directory', 'directory to load tests (default: ".")', default: '.'
12
+ o.on '--help' do
13
+ puts o
14
+ exit
15
+ end
16
+ end
6
17
 
7
- Theorem::Hypothesis::Harness.run! path
18
+ Theorem.run! opts[:directory], opts
data/src/harness.rb CHANGED
@@ -1,59 +1,43 @@
1
- require_relative './theorem'
2
- require 'extended_dir'
1
+ # frozen_string_literal: true
3
2
 
4
- # module
3
+ require_relative './theorem/harness'
4
+ require 'parallel'
5
+
6
+ # harness
5
7
  module Theorem
6
- # module
7
- module Hypothesis
8
- on_completed_test do |test|
9
- print test.failed? ? 'X' : '.'
10
- end
8
+ # default test harness
9
+ module Harness
10
+ include Control::Harness
11
+ end
11
12
 
12
- # harness
13
- class Harness
14
- def self.locate_tests(dir)
15
- ExtendedDir.require_all("./#{dir}")
13
+ # parallel harness
14
+ module ParallelHarness
15
+ include Control::Harness
16
16
 
17
- Hypothesis.registry
18
- end
17
+ on_run do |tests|
18
+ Parallel.map(tests, in_threads: 6, &:run!).flatten
19
+ end
20
+ end
19
21
 
20
- def self.get_test_count(test_cases)
21
- test_cases.map do |test_case|
22
- test_case.tests.size
23
- end.inject(&:+)
24
- end
22
+ # module retry harness
23
+ module RetryHarness
24
+ include Control::Harness
25
25
 
26
- def self.report_failures(failed_tests)
27
- failed_tests.each do |failure|
28
- puts "❌ Failure in #{failure.full_name}\nError: #{failure.error}\nBacktrace:\n------\n#{failure.error.backtrace.join("\n")}"
29
- end
30
- end
26
+ on_run do |tests|
27
+ arr_of_tests = tests.map { |test| { test: test, index: 0 } }
31
28
 
32
- def self.report_passes(passing_tests)
33
- passing_tests.each do |pass|
34
- puts "✓ #{pass.full_name}"
29
+ final_results = []
30
+ arr_of_tests.each do |test|
31
+ test[:index] += 1
32
+ results = test[:test].run!
33
+ if results.any?(&:failed?) && test[:index] <= 3
34
+ puts "Retrying iteration: #{test[:index]}\n#{results.map(&:full_name).join("\n")}"
35
+ redo
35
36
  end
37
+ final_results.concat results
36
38
  end
37
39
 
38
- def self.run!(dir)
39
- test_cases = locate_tests(dir)
40
- total_count = get_test_count(test_cases)
41
-
42
- puts "Total tests #{total_count}"
43
-
44
- results = test_cases.each_with_object([]) do |test_case, memo|
45
- memo.concat test_case.run!
46
- end
47
-
48
- puts "\n\nSummary\n-------"
49
-
50
- failed_tests, passed_tests = results.partition(&:failed?)
51
-
52
- report_passes(passed_tests)
53
- report_failures(failed_tests)
54
-
55
- exit failed_tests.any? ? 1 : 0
56
- end
40
+ final_results
57
41
  end
58
42
  end
59
43
  end
@@ -0,0 +1,70 @@
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.to_s.red}\nBacktrace:\n------\n#{failure.error.backtrace.map(&:red).join("\n")}"
67
+ end
68
+ end
69
+ end
70
+ end
@@ -54,6 +54,10 @@ module Theorem
54
54
  end
55
55
  end
56
56
 
57
+ def reverse_prepare(&block)
58
+ @state.unshift block
59
+ end
60
+
57
61
  def prepare(&block)
58
62
  @state << block
59
63
  end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'hypothesis'
4
+ require 'extended_dir'
5
+ module Theorem
6
+ module Control
7
+ # control harness
8
+ module Harness
9
+ def self.included(mod)
10
+ mod.extend(ClassMethods)
11
+ mod.define_singleton_method :included do |inner|
12
+ inner.define_singleton_method :run! do |directory, options = {}|
13
+ tests = inner.instance_exec directory, options, &mod.test_loader
14
+ results = inner.instance_exec tests, options, &mod.run_loader
15
+ inner.completed_suite_subscribers.each do |subscriber|
16
+ subscriber.call(results)
17
+ end
18
+ exit results.any?(&:failed?) ? 1 : 0
19
+ end
20
+ end
21
+ end
22
+
23
+ # harness helpers
24
+ module ClassMethods
25
+ DEFAULT_LOADER = ->(directory, tags) do
26
+ ExtendedDir.require_all("./#{directory}")
27
+
28
+ registry
29
+ end
30
+
31
+ DEFAULT_RUNNER = ->(tests, options) do
32
+ tests.each_with_object([]) do |test, memo|
33
+ memo.concat test.run!
34
+ end
35
+ end
36
+
37
+ def load_tests(&block)
38
+ @on_load_tests = block
39
+ end
40
+
41
+ def on_run(&block)
42
+ @on_run = block
43
+ end
44
+
45
+ def run_loader
46
+ @on_run || DEFAULT_RUNNER
47
+ end
48
+
49
+ def test_loader
50
+ @on_load_tests || DEFAULT_LOADER
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -19,6 +19,8 @@ module Theorem
19
19
  klass.instance_eval do
20
20
  @before_all ||= Beaker.new
21
21
  @before_each ||= Beaker.new
22
+ @after_all ||= Beaker.new
23
+ @after_each ||= Beaker.new
22
24
  @around = Flask.new
23
25
  @tests = []
24
26
  @completed_tests = []
@@ -12,6 +12,15 @@ module Theorem
12
12
  registry << klass
13
13
  end
14
14
 
15
+ def on_extra_event(&block)
16
+ @extra_events ||= []
17
+ @extra_events << block
18
+ end
19
+
20
+ def extra_event_subscribers
21
+ @extra_events || []
22
+ end
23
+
15
24
  def on_completed_test(&block)
16
25
  @completed_tests ||= []
17
26
  @completed_tests << block
@@ -20,6 +29,15 @@ module Theorem
20
29
  def completed_test_subscribers
21
30
  @completed_tests || []
22
31
  end
32
+
33
+ def on_completed_suite(&block)
34
+ @completed_suites ||= []
35
+ @completed_suites << block
36
+ end
37
+
38
+ def completed_suite_subscribers
39
+ @completed_suites || []
40
+ end
23
41
  end
24
42
  end
25
43
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Theorem
4
+ module Control
5
+ # reporter mixin
6
+ module Reporter
7
+ def self.extended(mod)
8
+ mod.extend(mod)
9
+ mod.define_singleton_method :included do |root|
10
+ mod.subscriptions.each do |subscription, handler|
11
+ mod.instance_exec root, subscription, handler do |root, sub, handle|
12
+ root.send(sub, &handle)
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ def subscribe(name, &block)
19
+ @subscriptions ||= {}
20
+ @subscriptions[name] = block
21
+ end
22
+
23
+ def subscriptions
24
+ @subscriptions
25
+ end
26
+ end
27
+ end
28
+ end
data/src/theorem/test.rb CHANGED
@@ -33,6 +33,12 @@ module Theorem
33
33
 
34
34
  @parent_before_each ||= []
35
35
  @parent_before_each << me.before_each_beaker
36
+
37
+ @parent_after_each ||= []
38
+ @parent_after_each.unshift me.after_each_beaker
39
+
40
+ @parent_after_all ||= []
41
+ @parent_after_all.unshift me.after_all_beaker
36
42
  end
37
43
  super
38
44
  end
@@ -49,6 +55,14 @@ module Theorem
49
55
  @before_each.prepare(&block)
50
56
  end
51
57
 
58
+ def after_each(&block)
59
+ @after_each.reverse_prepare(&block)
60
+ end
61
+
62
+ def after_all(&block)
63
+ @after_all.reverse_prepare(&block)
64
+ end
65
+
52
66
  def experiments(klass, **opts, &block)
53
67
  obj = Class.new
54
68
  obj.include(control)
@@ -70,6 +84,14 @@ module Theorem
70
84
  @before_each
71
85
  end
72
86
 
87
+ def after_each_beaker
88
+ @after_each
89
+ end
90
+
91
+ def after_all_beaker
92
+ @after_all
93
+ end
94
+
73
95
  def test(name, &block)
74
96
  @tests << Test.new(name, to_s, &block)
75
97
  end
@@ -84,15 +106,20 @@ module Theorem
84
106
 
85
107
  results = []
86
108
  @tests.each do |test|
87
- before_each_failures = run_before_each_beakers(test_case)
88
- return before_each_failures if before_each_failures.any?
89
-
90
- error = run_test(test, test_case)
109
+ error ||= run_before_each_beakers(test_case)
110
+ error ||= run_test(test, test_case)
111
+ error ||= run_after_each_beakers(test_case)
91
112
 
92
113
  completed_test = CompletedTest.new(test, error)
93
114
  publish_test_completion(completed_test)
94
115
  results << completed_test
95
116
  end
117
+
118
+ after_failures = run_after_all_beakers(test_case)
119
+ if after_failures.any?
120
+ return after_failures
121
+ end
122
+
96
123
  results
97
124
  end
98
125
 
@@ -113,11 +140,13 @@ module Theorem
113
140
  end
114
141
  end
115
142
 
116
- def run_before_each_beakers(test_case)
117
- @parent_before_each&.each do |beaker|
143
+ def run_after_all_beakers(test_case)
144
+ @after_all.run!(test_case)
145
+
146
+ @parent_after_all&.each do |beaker|
118
147
  beaker.run!(test_case)
119
148
  end
120
- @before_each.run!(test_case)
149
+
121
150
  []
122
151
  rescue Exception => error
123
152
  Theorem.handle_exception(error)
@@ -127,6 +156,31 @@ module Theorem
127
156
  end
128
157
  end
129
158
 
159
+ def run_after_each_beakers(test_case)
160
+ @after_each.run!(test_case)
161
+
162
+ @parent_after_each&.each do |beaker|
163
+ beaker.run!(test_case)
164
+ end
165
+ nil
166
+ rescue Exception => error
167
+ Theorem.handle_exception(error)
168
+
169
+ error
170
+ end
171
+
172
+ def run_before_each_beakers(test_case)
173
+ @parent_before_each&.each do |beaker|
174
+ beaker.run!(test_case)
175
+ end
176
+ @before_each.run!(test_case)
177
+ nil
178
+ rescue Exception => error
179
+ Theorem.handle_exception(error)
180
+
181
+ error
182
+ end
183
+
130
184
  def run_before_all_beakers(test_case)
131
185
  @parent_before_all&.each do |beaker|
132
186
  beaker.run!(test_case)
data/src/theorem.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  require_relative 'theorem/hypothesis'
2
+ require_relative 'harness'
2
3
  require_relative 'experiment'
4
+ require_relative 'stdout_reporter'
5
+ require 'json'
3
6
 
4
7
  module Theorem
5
8
  # RSpec subclasses Exception, so the only way to catch them without a dependency is to catch Exception
@@ -17,6 +20,41 @@ module Theorem
17
20
  end
18
21
  end
19
22
 
23
+ def self.run!(directory, options)
24
+ options[:require].each do |file|
25
+ require file
26
+ end
27
+
28
+ raise StandardError, "Unknown Module: #{options[:module]}" unless defined? Object.const_get(options[:module])
29
+ raise StandardError, "Unknown Harness: #{options[:harness]}" unless defined? Object.const_get(options[:harness])
30
+
31
+ mod = Object.const_get(options[:module])
32
+ harness = Object.const_get options[:harness]
33
+ mod.include harness
34
+
35
+ options[:publisher].each do |publisher|
36
+ if defined? Object.const_get(publisher)
37
+ mod.include Object.const_get(publisher)
38
+ else
39
+ raise StandardError, "Unknown Publisher: #{publisher}"
40
+ end
41
+ end
42
+
43
+ mod.run!(directory, options)
44
+ end
45
+
46
+ module JsonReporter
47
+ extend Control::Reporter
48
+
49
+ subscribe :on_completed_suite do |results|
50
+ results = results.map do |result|
51
+ { name: result.full_name, failed: result.failed? }
52
+ end
53
+ puts results
54
+ puts "\n\n"
55
+ end
56
+ end
57
+
20
58
  module Hypothesis
21
59
  include Control::Hypothesis
22
60
  end
metadata CHANGED
@@ -1,29 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: theorem
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
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-08 00:00:00.000000000 Z
11
+ date: 2022-04-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: extended_dir
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: 0.1.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: 0.1.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: slop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 4.9.2
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 4.9.2
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rbs
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -67,7 +81,7 @@ dependencies:
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
- name: watir
84
+ name: parallel
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
87
  - - ">="
@@ -80,7 +94,7 @@ dependencies:
80
94
  - - ">="
81
95
  - !ruby/object:Gem::Version
82
96
  version: '0'
83
- description: simple. testing. ah.
97
+ description: simple and extensible test library toolkit
84
98
  email: sean.christopher.gregory@gmail.com
85
99
  executables:
86
100
  - theorize
@@ -90,21 +104,24 @@ files:
90
104
  - bin/theorize
91
105
  - src/experiment.rb
92
106
  - src/harness.rb
107
+ - src/stdout_reporter.rb
93
108
  - src/theorem.rb
94
109
  - src/theorem/beaker.rb
95
110
  - src/theorem/completed_test.rb
111
+ - src/theorem/harness.rb
96
112
  - src/theorem/hypothesis.rb
97
113
  - src/theorem/registry.rb
114
+ - src/theorem/reporter.rb
98
115
  - src/theorem/test.rb
99
116
  homepage: https://rubygems.org/gems/theorem
100
117
  licenses:
101
118
  - MIT
102
119
  metadata:
103
- source_code_uri: https://github.com/skinnyjames/theorem
120
+ source_code_uri: https://gitlab.com/skinnyjames/theorem
104
121
  post_install_message:
105
122
  rdoc_options: []
106
123
  require_paths:
107
- - lib
124
+ - src
108
125
  required_ruby_version: !ruby/object:Gem::Requirement
109
126
  requirements:
110
127
  - - ">="
@@ -116,8 +133,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
116
133
  - !ruby/object:Gem::Version
117
134
  version: '0'
118
135
  requirements: []
119
- rubygems_version: 3.2.31
136
+ rubygems_version: 3.2.22
120
137
  signing_key:
121
138
  specification_version: 4
122
- summary: simple. testing. ah.
139
+ summary: simple and extensible test library toolkit
123
140
  test_files: []