thoreau 0.2.0 → 0.2.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 +4 -4
- data/lib/thoreau/case/builder.rb +110 -0
- data/lib/thoreau/case/context_builder.rb +28 -0
- data/lib/thoreau/case/runner.rb +42 -0
- data/lib/thoreau/case.rb +97 -0
- data/lib/thoreau/dsl/appendix.rb +18 -0
- data/lib/thoreau/dsl/context.rb +55 -0
- data/lib/thoreau/dsl/expanded.rb +13 -0
- data/lib/thoreau/dsl/groups.rb +20 -0
- data/lib/thoreau/dsl/groups_support.rb +58 -0
- data/lib/thoreau/dsl.rb +55 -0
- data/lib/thoreau/legacy_results.rb +8 -0
- data/lib/thoreau/rspec/configuration.rb +14 -0
- data/lib/thoreau/rspec/example_helpers.rb +7 -0
- data/lib/thoreau/rspec.rb +19 -0
- data/lib/thoreau/setup.rb +15 -0
- data/lib/thoreau/spec_group.rb +45 -0
- data/lib/thoreau/test_suite.rb +41 -0
- data/lib/thoreau/util.rb +12 -0
- data/lib/thoreau/version.rb +3 -0
- data/lib/thoreau.rb +12 -0
- metadata +22 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a8c65711c30e69f7c09e814361f34d2c6b55501223f5b422eed26f23363dd7fb
|
4
|
+
data.tar.gz: dbe902b4cb31334a3afe3a42b3fdde8078eb34ec26c1029fd25ec8825d2c6add
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ddc80c61cc57201d339e9315df32add749b0219c363b92ce3cfbe8432c8a0076c2a584d8f9feb002202582431b33349c3069200ab44ee36ff7c172bd15df324
|
7
|
+
data.tar.gz: 5e28db2a7a84fc7f9024dca9160115dd9973625f357f4ec499625b2b116e67335590d816b678aed099d20e55e9c4b7928e53d5c828340d886f8f30a6b9544e58
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module Thoreau
|
2
|
+
class Case
|
3
|
+
# Build test cases.
|
4
|
+
#
|
5
|
+
# It is responsible for:
|
6
|
+
# - building an list of Test::Case objects based
|
7
|
+
# on the groups provided.
|
8
|
+
# - expanding input specs in the groups into multiple cases
|
9
|
+
# - skipping unfocused tests, if any are focused
|
10
|
+
# - returning a count of those skipped
|
11
|
+
class Builder
|
12
|
+
|
13
|
+
def initialize(groups, suite_context)
|
14
|
+
@groups = groups
|
15
|
+
@suite_context = suite_context
|
16
|
+
end
|
17
|
+
|
18
|
+
def logger
|
19
|
+
@suite_context.logger
|
20
|
+
end
|
21
|
+
|
22
|
+
def any_focused?
|
23
|
+
@groups.count(&:focused?) > 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def skipped_count
|
27
|
+
return 0 unless any_focused?
|
28
|
+
@groups.count - @groups.count(&:focused?)
|
29
|
+
end
|
30
|
+
|
31
|
+
def build_test_cases!
|
32
|
+
logger.debug "build_test_cases!"
|
33
|
+
|
34
|
+
@groups
|
35
|
+
.select { |g| any_focused? && g.focused? || !any_focused? }
|
36
|
+
.flat_map do |g|
|
37
|
+
build_group_cases g
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def setup_key_to_inputs key
|
44
|
+
setup = @suite_context.setups[key.to_s]
|
45
|
+
raise "Unrecognized setup context '#{key}'. Available: #{@suite_setups.keys.to_sentence}" if setup.nil?
|
46
|
+
|
47
|
+
return setup.values if setup.block.nil?
|
48
|
+
|
49
|
+
result = Class.new.new.instance_eval(&setup.block)
|
50
|
+
logger.error "Setup #{key} did not return a hash object" unless result.is_a?(Hash)
|
51
|
+
result
|
52
|
+
end
|
53
|
+
|
54
|
+
def build_group_cases g
|
55
|
+
# We have "specs" for the inputs. These may be actual
|
56
|
+
# values, or they may be enumerables that need to execute.
|
57
|
+
# So we need to "explode" (or enumerate) the values,
|
58
|
+
# generating a single test for each combination.
|
59
|
+
#
|
60
|
+
setup_values = g.setups
|
61
|
+
.map { |key| setup_key_to_inputs key }
|
62
|
+
.reduce(Hash.new) { |m, h| m.merge(h) }
|
63
|
+
|
64
|
+
input_sets = g.input_specs
|
65
|
+
.map { |is| setup_values.merge(is) }
|
66
|
+
.flat_map do |input_spec|
|
67
|
+
explode_input_specs(input_spec.keys, input_spec)
|
68
|
+
end
|
69
|
+
|
70
|
+
input_sets.map do |input_set|
|
71
|
+
Thoreau::Case.new(
|
72
|
+
group: g,
|
73
|
+
input: input_set,
|
74
|
+
action: @suite_context.data.action,
|
75
|
+
expected_output: g.expected_output,
|
76
|
+
expected_exception: g.expected_exception,
|
77
|
+
asserts: g.asserts,
|
78
|
+
suite_context: @suite_context,
|
79
|
+
logger: logger)
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
# Expand any values that are enumerators (Thoreau::DSL::Expanded),
|
85
|
+
# creating a list of objects, where all the combinations
|
86
|
+
# of enumerated values are present.
|
87
|
+
def explode_input_specs(keys, input_spec)
|
88
|
+
k = keys.pop
|
89
|
+
|
90
|
+
value_spec = input_spec[k]
|
91
|
+
specs = if value_spec.is_a?(Thoreau::DSL::Expanded)
|
92
|
+
value_spec.map do |v|
|
93
|
+
input_spec.merge(k => v)
|
94
|
+
end
|
95
|
+
else
|
96
|
+
[input_spec]
|
97
|
+
end
|
98
|
+
|
99
|
+
# Are we done?
|
100
|
+
return specs if keys.empty?
|
101
|
+
|
102
|
+
specs.flat_map do |spec|
|
103
|
+
explode_input_specs(keys, spec) # recurse!
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Thoreau
|
2
|
+
class Case
|
3
|
+
class ContextBuilder
|
4
|
+
|
5
|
+
def initialize(group:, input:)
|
6
|
+
@group = group
|
7
|
+
@input = input
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_context
|
11
|
+
temp_class = Class.new
|
12
|
+
temp_context = temp_class.new
|
13
|
+
inject_hash_into_context(@input, temp_context)
|
14
|
+
temp_context
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def inject_hash_into_context(h, temp_context)
|
20
|
+
h.each do |lval, rval|
|
21
|
+
temp_context.instance_variable_set("@#{lval}", rval)
|
22
|
+
temp_context.class.attr_accessor lval
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Thoreau
|
2
|
+
class Case
|
3
|
+
class Runner
|
4
|
+
|
5
|
+
def initialize(context)
|
6
|
+
@context = context
|
7
|
+
end
|
8
|
+
|
9
|
+
def logger
|
10
|
+
@context.logger
|
11
|
+
end
|
12
|
+
|
13
|
+
def run_test_cases! cases, skipped
|
14
|
+
logger.info " § #{@context.name} §"
|
15
|
+
cases.each do |c|
|
16
|
+
if c.ok?
|
17
|
+
logger.info " ✓ #{c.desc}"
|
18
|
+
else
|
19
|
+
logger.error "❓ #{c.desc}, #{c.problem}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
logger.info (summary cases, skipped)
|
23
|
+
logger.info ""
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
def summary cases, skipped
|
28
|
+
ok = cases.count(&:ok?)
|
29
|
+
total = cases.count
|
30
|
+
failed = cases.count(&:failed?)
|
31
|
+
if failed == 0
|
32
|
+
" ∴ All OK 👌🏾 #{skipped > 0 ? "#{skipped} skipped." : ""}"
|
33
|
+
else
|
34
|
+
" 🛑 #{failed} problem(s) detected. [#{ok} of #{total} OK#{skipped > 0 ? ", #{skipped} skipped" : ""}.]"
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
data/lib/thoreau/case.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'active_support/core_ext/module/delegation'
|
2
|
+
require_relative './case/context_builder'
|
3
|
+
|
4
|
+
module Thoreau
|
5
|
+
class Case
|
6
|
+
def initialize group:,
|
7
|
+
input:,
|
8
|
+
action:,
|
9
|
+
expected_output:,
|
10
|
+
expected_exception:,
|
11
|
+
asserts:,
|
12
|
+
logger:,
|
13
|
+
suite_context:
|
14
|
+
@group = group
|
15
|
+
@input = input
|
16
|
+
@action = action
|
17
|
+
if expected_output.is_a?(Proc)
|
18
|
+
@expected_output_proc = expected_output
|
19
|
+
else
|
20
|
+
@expected_output = expected_output
|
21
|
+
end
|
22
|
+
@expected_exception = expected_exception
|
23
|
+
@assert_proc = asserts
|
24
|
+
@logger = logger
|
25
|
+
@suite_context = suite_context
|
26
|
+
@ran = false
|
27
|
+
end
|
28
|
+
|
29
|
+
delegate :failure_expected?, to: :@group
|
30
|
+
|
31
|
+
def desc
|
32
|
+
"#{@group.kind}: #{@group.desc} #{(@input == {} ? nil : @input.sort.to_h) || @expected_exception || "(no args)"}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def problem
|
36
|
+
run unless @ran
|
37
|
+
if @expected_exception
|
38
|
+
|
39
|
+
logger.debug " -> @expected_exception:#{@expected_exception} @raised_exception:#{@raised_exception}"
|
40
|
+
|
41
|
+
if @raised_exception.to_s == @expected_exception.to_s
|
42
|
+
nil
|
43
|
+
elsif @raised_exception.nil?
|
44
|
+
"Expected exception, but none raised"
|
45
|
+
elsif @raised_exception.is_a?(NameError)
|
46
|
+
"Did you forget to define an input? Error: #{@raised_exception}"
|
47
|
+
else
|
48
|
+
"Expected '#{@expected_exception}' exception, but raised '#{@raised_exception}' (#{@raised_exception.class.name})"
|
49
|
+
end
|
50
|
+
|
51
|
+
elsif @assert_proc
|
52
|
+
|
53
|
+
logger.debug " -> @assert_result: #{@assert_result}"
|
54
|
+
|
55
|
+
@assert_result ? nil : "Assertion failed. (got #{@assert_result})"
|
56
|
+
else
|
57
|
+
|
58
|
+
logger.debug " -> @result: #{@result} @expected_output: #{@expected_output} @raised_exception:#{@raised_exception}"
|
59
|
+
|
60
|
+
if @raised_exception
|
61
|
+
"Expected output, but raised exception '#{@raised_exception}'"
|
62
|
+
elsif @expected_output != @result
|
63
|
+
"Expected '#{@expected_output}', but got '#{@result}'"
|
64
|
+
else
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def ok?
|
71
|
+
failure_expected? ^ !!problem.nil?
|
72
|
+
end
|
73
|
+
|
74
|
+
def failed?
|
75
|
+
!ok?
|
76
|
+
end
|
77
|
+
|
78
|
+
def run
|
79
|
+
logger.debug("create_context for #{desc} -> ")
|
80
|
+
context_builder = Case::ContextBuilder.new(group: @group, input: @input)
|
81
|
+
context = context_builder.create_context
|
82
|
+
begin
|
83
|
+
# Only capture exceptions around the action itself.
|
84
|
+
@result = context.instance_exec(&(@action))
|
85
|
+
rescue Exception => e
|
86
|
+
@raised_exception = e
|
87
|
+
return
|
88
|
+
ensure
|
89
|
+
@ran = true
|
90
|
+
end
|
91
|
+
|
92
|
+
@assert_result = context.instance_exec(@result, &(@assert_proc)) if @assert_proc
|
93
|
+
@expected_output = context.instance_exec(@result, &(@expected_output_proc)) if @expected_output_proc
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative '../setup'
|
2
|
+
|
3
|
+
module Thoreau
|
4
|
+
module DSL
|
5
|
+
class Appendix
|
6
|
+
def initialize(context)
|
7
|
+
@context = context
|
8
|
+
end
|
9
|
+
|
10
|
+
def setup name, values = {}, &block
|
11
|
+
raise "duplicate setup block #{name}" unless @context.setups[name].nil?
|
12
|
+
@context.setups[name.to_s] = Thoreau::Setup.new(name, values, block)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Thoreau
|
2
|
+
module DSL
|
3
|
+
class Data
|
4
|
+
attr_accessor :action
|
5
|
+
attr_accessor :cases
|
6
|
+
attr_accessor :appendix
|
7
|
+
attr_accessor :groups
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@groups = []
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Context
|
15
|
+
|
16
|
+
attr_reader :data
|
17
|
+
attr_reader :name
|
18
|
+
attr_reader :logger
|
19
|
+
attr_reader :setups
|
20
|
+
|
21
|
+
def initialize name, logger
|
22
|
+
@name = name
|
23
|
+
@logger = logger
|
24
|
+
@data = Data.new
|
25
|
+
@setups = {}
|
26
|
+
end
|
27
|
+
|
28
|
+
def action(&block)
|
29
|
+
logger.debug "adding action"
|
30
|
+
@data.action = block
|
31
|
+
end
|
32
|
+
|
33
|
+
alias testing action
|
34
|
+
alias subject action
|
35
|
+
|
36
|
+
def cases(&block)
|
37
|
+
logger.debug "adding cases"
|
38
|
+
@data.cases = block
|
39
|
+
end
|
40
|
+
|
41
|
+
alias test_cases cases
|
42
|
+
|
43
|
+
def appendix(&block)
|
44
|
+
logger.debug "adding appendix"
|
45
|
+
@data.appendix = block
|
46
|
+
end
|
47
|
+
|
48
|
+
def context
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Thoreau
|
2
|
+
module DSL
|
3
|
+
class Groups
|
4
|
+
|
5
|
+
attr_reader :context
|
6
|
+
|
7
|
+
def initialize(context)
|
8
|
+
@context = context
|
9
|
+
end
|
10
|
+
|
11
|
+
def logger *args
|
12
|
+
@context.logger *args
|
13
|
+
end
|
14
|
+
|
15
|
+
include Thoreau::DSL::GroupsSupport
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require_relative '../spec_group'
|
2
|
+
require_relative './expanded'
|
3
|
+
require 'active_support/core_ext/array/conversions'
|
4
|
+
|
5
|
+
module Thoreau
|
6
|
+
module DSL
|
7
|
+
|
8
|
+
SPEC_GROUP_NAMES = %i[happy sad spec edge edges boundary corner gigo]
|
9
|
+
# gigo = garbage in / garbage out
|
10
|
+
#
|
11
|
+
GROUP_PROPS = %w[assert asserts raises output equal equals expect expects expected legacy pending fails inputs input setup setups].sort.freeze
|
12
|
+
PROPS_SPELL_CHECKER = DidYouMean::SpellChecker.new(dictionary: GROUP_PROPS)
|
13
|
+
|
14
|
+
module GroupsSupport
|
15
|
+
# Note: requires `logger` and `context`.
|
16
|
+
SPEC_GROUP_NAMES.each do |sym|
|
17
|
+
define_method sym do |*args|
|
18
|
+
desc = args.shift if args.size > 1 && args.first.is_a?(String)
|
19
|
+
raise "Too many arguments to #{sym}!" if args.size > 1
|
20
|
+
|
21
|
+
spec = args.first || {}
|
22
|
+
spec.keys
|
23
|
+
.reject { |k| GROUP_PROPS.include? k.to_s }
|
24
|
+
.each do |k|
|
25
|
+
suggestions = PROPS_SPELL_CHECKER.correct(k)
|
26
|
+
logger.error "Ignoring unrecognized property '#{k}'."
|
27
|
+
logger.info " Did you mean #{suggestions.to_sentence}?" if suggestions.size > 0
|
28
|
+
logger.info " Available properties: #{GROUP_PROPS.to_sentence}"
|
29
|
+
end
|
30
|
+
|
31
|
+
group = SpecGroup.new asserts: spec[:assert] || spec[:asserts],
|
32
|
+
desc: desc,
|
33
|
+
expected_exception: spec[:raises],
|
34
|
+
expected_output: spec[:output] || spec[:equals] || spec[:equal] || spec[:expected] || spec[:expects],
|
35
|
+
failure_expected: spec[:pending] || spec[:fails],
|
36
|
+
input_specs: [spec[:inputs] || spec[:input] || {}].flatten,
|
37
|
+
kind: sym,
|
38
|
+
legacy: spec[:legacy],
|
39
|
+
setups: [spec[:setup], spec[:setups]].flatten.compact
|
40
|
+
logger.debug "Adding group #{group}"
|
41
|
+
context.data.groups.push(group)
|
42
|
+
group
|
43
|
+
end
|
44
|
+
|
45
|
+
define_method "#{sym}!" do |*args|
|
46
|
+
group = self.send(sym, *args)
|
47
|
+
group.focus = true
|
48
|
+
group
|
49
|
+
end
|
50
|
+
|
51
|
+
def expanded(a)
|
52
|
+
Thoreau::DSL::Expanded.new(a)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
data/lib/thoreau/dsl.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
require 'thoreau/test_suite'
|
4
|
+
require 'thoreau/case'
|
5
|
+
require 'thoreau/case/builder'
|
6
|
+
require 'thoreau/case/runner'
|
7
|
+
require 'thoreau/dsl/groups_support'
|
8
|
+
require 'thoreau/dsl/context'
|
9
|
+
require 'thoreau/dsl/groups'
|
10
|
+
require 'thoreau/dsl/appendix'
|
11
|
+
|
12
|
+
at_exit do
|
13
|
+
Thoreau::TestSuite.run_all!
|
14
|
+
end
|
15
|
+
|
16
|
+
module Thoreau
|
17
|
+
module DSL
|
18
|
+
|
19
|
+
attr_reader :logger
|
20
|
+
|
21
|
+
def test_suite name = nil, focus: false, &block
|
22
|
+
@logger = Logger.new(STDOUT, formatter: proc { |severity, datetime, progname, msg|
|
23
|
+
"#{severity}: #{msg}\n"
|
24
|
+
})
|
25
|
+
logger.level = Logger::INFO
|
26
|
+
logger.level = Logger::DEBUG if ENV['DEBUG']
|
27
|
+
|
28
|
+
@context = Thoreau::DSL::Context.new(name, @logger)
|
29
|
+
|
30
|
+
appendix_context = Thoreau::DSL::Appendix.new(@context)
|
31
|
+
groups_context = Thoreau::DSL::Groups.new(@context)
|
32
|
+
|
33
|
+
@context.instance_eval(&block)
|
34
|
+
appendix_context.instance_eval(&@context.data.appendix) unless @context.data.appendix.nil?
|
35
|
+
groups_context.instance_eval(&@context.data.cases) unless @context.data.cases.nil?
|
36
|
+
|
37
|
+
TestSuite.new(context: @context, focus: focus, logger: logger, name: name)
|
38
|
+
end
|
39
|
+
|
40
|
+
def xtest_suite name = nil, &block
|
41
|
+
end
|
42
|
+
|
43
|
+
alias suite test_suite
|
44
|
+
alias xsuite xtest_suite
|
45
|
+
|
46
|
+
def test_suite! name = nil, &block
|
47
|
+
test_suite name, focus: true, &block
|
48
|
+
end
|
49
|
+
|
50
|
+
alias suite! test_suite!
|
51
|
+
|
52
|
+
include Thoreau::DSL::GroupsSupport
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
require 'rspec/core'
|
3
|
+
require 'thoreau'
|
4
|
+
require 'thoreau/rspec/example_helpers'
|
5
|
+
require 'thoreau/rspec/configuration'
|
6
|
+
require 'thoreau/rspec/railtie' if defined?(Rails::Railtie)
|
7
|
+
|
8
|
+
module Thoreau
|
9
|
+
module Rspec
|
10
|
+
|
11
|
+
::RSpec.configure do |c|
|
12
|
+
c.include ExampleHelpers
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.config
|
16
|
+
@config ||= Configuration.new(RSpec.configuration)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Thoreau
|
2
|
+
|
3
|
+
class SpecGroup
|
4
|
+
attr_reader :asserts,
|
5
|
+
:desc,
|
6
|
+
:expected_exception,
|
7
|
+
:expected_output,
|
8
|
+
:input_specs,
|
9
|
+
:kind,
|
10
|
+
:legacy,
|
11
|
+
:setups
|
12
|
+
attr_writer :focus
|
13
|
+
|
14
|
+
def initialize(asserts:,
|
15
|
+
desc:,
|
16
|
+
expected_exception:,
|
17
|
+
expected_output:,
|
18
|
+
failure_expected:,
|
19
|
+
input_specs:,
|
20
|
+
legacy:,
|
21
|
+
kind:,
|
22
|
+
setups:
|
23
|
+
)
|
24
|
+
@asserts = asserts
|
25
|
+
@desc = desc
|
26
|
+
@expected_exception = expected_exception
|
27
|
+
@expected_output = expected_output
|
28
|
+
@failure_expected = failure_expected
|
29
|
+
@input_specs = input_specs
|
30
|
+
@kind = kind
|
31
|
+
@legacy = legacy
|
32
|
+
@setups = setups
|
33
|
+
end
|
34
|
+
|
35
|
+
def failure_expected?
|
36
|
+
@failure_expected
|
37
|
+
end
|
38
|
+
|
39
|
+
def focused?
|
40
|
+
@focus
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Thoreau
|
2
|
+
class TestSuite
|
3
|
+
|
4
|
+
attr_reader :name
|
5
|
+
attr_reader :logger
|
6
|
+
|
7
|
+
@@suites = []
|
8
|
+
|
9
|
+
def initialize(context:, logger:, name:, focus:)
|
10
|
+
@context = context
|
11
|
+
@logger = logger
|
12
|
+
@name = name
|
13
|
+
@focus = focus
|
14
|
+
@@suites << self
|
15
|
+
@builder = Thoreau::Case::Builder.new @context.data.groups, @context
|
16
|
+
end
|
17
|
+
|
18
|
+
def build_and_run
|
19
|
+
cases = @builder.build_test_cases!
|
20
|
+
|
21
|
+
runner = Thoreau::Case::Runner.new @context
|
22
|
+
runner.run_test_cases! cases,
|
23
|
+
@builder.skipped_count # for reporting
|
24
|
+
end
|
25
|
+
|
26
|
+
def focused?
|
27
|
+
@focus || @builder.any_focused?
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.run_all!
|
31
|
+
run_all = !@@suites.any?(&:focused?)
|
32
|
+
@@suites.each do |suite|
|
33
|
+
if suite.focused? || run_all
|
34
|
+
suite.build_and_run
|
35
|
+
else
|
36
|
+
suite.logger.info("Suite '#{suite.name}' skipped (unfocused)")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/thoreau/util.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
def combos_of(entries)
|
2
|
+
return [{}] if entries.size == 0
|
3
|
+
|
4
|
+
first_response = entries.first.map { |x| { x[0] => x[1] } }
|
5
|
+
return first_response if entries.size == 1
|
6
|
+
|
7
|
+
combos_of_rest = combos_of(entries.slice(1..(entries.size)))
|
8
|
+
|
9
|
+
first_response.flat_map do |f|
|
10
|
+
combos_of_rest.map { |r| r.merge(f) }
|
11
|
+
end
|
12
|
+
end
|
data/lib/thoreau.rb
ADDED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thoreau
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Peterson
|
@@ -106,7 +106,27 @@ email:
|
|
106
106
|
executables: []
|
107
107
|
extensions: []
|
108
108
|
extra_rdoc_files: []
|
109
|
-
files:
|
109
|
+
files:
|
110
|
+
- lib/thoreau.rb
|
111
|
+
- lib/thoreau/case.rb
|
112
|
+
- lib/thoreau/case/builder.rb
|
113
|
+
- lib/thoreau/case/context_builder.rb
|
114
|
+
- lib/thoreau/case/runner.rb
|
115
|
+
- lib/thoreau/dsl.rb
|
116
|
+
- lib/thoreau/dsl/appendix.rb
|
117
|
+
- lib/thoreau/dsl/context.rb
|
118
|
+
- lib/thoreau/dsl/expanded.rb
|
119
|
+
- lib/thoreau/dsl/groups.rb
|
120
|
+
- lib/thoreau/dsl/groups_support.rb
|
121
|
+
- lib/thoreau/legacy_results.rb
|
122
|
+
- lib/thoreau/rspec.rb
|
123
|
+
- lib/thoreau/rspec/configuration.rb
|
124
|
+
- lib/thoreau/rspec/example_helpers.rb
|
125
|
+
- lib/thoreau/setup.rb
|
126
|
+
- lib/thoreau/spec_group.rb
|
127
|
+
- lib/thoreau/test_suite.rb
|
128
|
+
- lib/thoreau/util.rb
|
129
|
+
- lib/thoreau/version.rb
|
110
130
|
homepage: https://github.com/ndp/thoreau
|
111
131
|
licenses: []
|
112
132
|
metadata:
|