thoreau 0.2.2 → 0.3.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.
- checksums.yaml +4 -4
- data/lib/thoreau/auto_run.rb +2 -1
- data/lib/thoreau/case/case_builder.rb +22 -26
- data/lib/thoreau/case/suite_runner.rb +2 -2
- data/lib/thoreau/configuration.rb +1 -1
- data/lib/thoreau/dsl/context/appendix.rb +17 -0
- data/lib/thoreau/dsl/context/clan.rb +96 -0
- data/lib/thoreau/dsl/{suite_context.rb → context/suite.rb} +3 -10
- data/lib/thoreau/dsl/context/test_cases.rb +21 -0
- data/lib/thoreau/dsl/test_suite_data.rb +29 -0
- data/lib/thoreau/dsl.rb +18 -17
- data/lib/thoreau/model/appendix.rb +37 -0
- data/lib/thoreau/{models → model}/outcome.rb +1 -1
- data/lib/thoreau/{models → model}/setup.rb +1 -1
- data/lib/thoreau/{models → model}/test_case.rb +29 -9
- data/lib/thoreau/{models → model}/test_clan.rb +1 -1
- data/lib/thoreau/{models → model}/test_family.rb +1 -1
- data/lib/thoreau/model/test_suite.rb +49 -0
- data/lib/thoreau/{legacy_expected_outcomes.rb → service/legacy_expected_outcomes.rb} +0 -0
- data/lib/thoreau/{logging.rb → service/logging.rb} +0 -0
- data/lib/thoreau/{util.rb → service/util.rb} +0 -0
- data/lib/thoreau/version.rb +1 -1
- metadata +17 -23
- data/lib/thoreau/dsl/appendix.rb +0 -18
- data/lib/thoreau/dsl/clan.rb +0 -94
- data/lib/thoreau/dsl/test_cases.rb +0 -20
- data/lib/thoreau/models/appendix.rb +0 -17
- data/lib/thoreau/test_suite.rb +0 -47
- data/lib/thoreau/test_suite_data.rb +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c492a383143335b6073d8677862b0228568e00977882f2c8483a8f6a78851a14
|
4
|
+
data.tar.gz: de415989640870528ad0f031c694173893600327d0f563d429339660c09a5b55
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65a16a5f32ff2a33717c675b0d6128212b93ce93a5eafff87ea7ea949deff1925fd2844ddd7b67dae1da74a3af18a8eb9d9146efaccfeaed3b71f16a5d1338ff
|
7
|
+
data.tar.gz: 567112f783bdd3ccc730378c3b89f4492869916302f5face9b2602f144d4ce55afe65997b506e0e5f3adaed8e759b38b23254b1376d6919e58b37141f0294427
|
data/lib/thoreau/auto_run.rb
CHANGED
@@ -38,45 +38,30 @@ module Thoreau
|
|
38
38
|
|
39
39
|
private
|
40
40
|
|
41
|
-
def setup_key_to_inputs key
|
42
|
-
setup = @appendix.setups[key.to_s]
|
43
|
-
raise "Unrecognized setup context '#{key}'. Available: #{@appendix.setups.keys.to_sentence}" if setup.nil?
|
44
|
-
logger.debug(" setup_key_to_inputs `#{key}`: #{setup}")
|
45
|
-
return setup.values if setup.block.nil?
|
46
|
-
|
47
|
-
result = Class.new.new.instance_eval(&setup.block)
|
48
|
-
logger.error "Setup #{key} did not return a hash object" unless result.is_a?(Hash)
|
49
|
-
result
|
50
|
-
end
|
51
|
-
|
52
41
|
def build_family_cases fam
|
53
42
|
# We have "specs" for the inputs. These may be actual
|
54
43
|
# values, or they may be enumerables that need to execute.
|
55
44
|
# So we need to "explode" (or enumerate) the values,
|
56
45
|
# generating a single test for each combination.
|
57
46
|
#
|
58
|
-
setup_values = fam.setups
|
59
|
-
|
60
|
-
|
47
|
+
setup_values = @appendix.setup_values fam.setups
|
48
|
+
|
49
|
+
# calculate the inputs, expanded from the setup values above
|
50
|
+
input_hashes = build_input_hashes fam.input_specs, setup_values
|
51
|
+
|
61
52
|
logger.debug(" -> setup_values = #{setup_values}")
|
62
53
|
logger.debug(" -> fam.input_specs = #{fam.input_specs}")
|
63
|
-
input_sets
|
64
|
-
|
65
|
-
.flat_map do |input_spec|
|
66
|
-
explode_input_specs(input_spec.keys, input_spec)
|
67
|
-
end
|
68
|
-
input_sets = [{}] if input_sets.size == 0
|
69
|
-
logger.debug(" -> input_sets: #{input_sets}")
|
70
|
-
logger.debug(" build cases for '#{fam.desc}', #{setup_values.size} setups, #{input_sets.size} input sets, build_family_cases")
|
54
|
+
logger.debug(" -> input_sets: #{input_hashes}")
|
55
|
+
logger.debug(" build cases for '#{fam.desc}', #{setup_values.size} setups, #{input_hashes.size} input sets, build_family_cases")
|
71
56
|
|
72
|
-
|
57
|
+
input_hashes.map do |input_hash|
|
73
58
|
expectation = fam.use_legacy_snapshot ?
|
74
59
|
:use_legacy_snapshot :
|
75
|
-
|
60
|
+
Model::Outcome.new(output: fam.expected_output,
|
76
61
|
exception: fam.expected_exception)
|
77
62
|
|
78
|
-
Thoreau::
|
79
|
-
input:
|
63
|
+
Thoreau::Model::TestCase.new family_desc: "#{fam.kind.to_s.ljust(10).capitalize} #{fam.desc}",
|
64
|
+
input: input_hash,
|
80
65
|
action_block: @action_block,
|
81
66
|
expectation: expectation,
|
82
67
|
asserts: fam.asserts,
|
@@ -85,6 +70,17 @@ module Thoreau
|
|
85
70
|
|
86
71
|
end
|
87
72
|
|
73
|
+
|
74
|
+
def build_input_hashes input_specs, setup_values
|
75
|
+
sets = input_specs
|
76
|
+
.map { |is| setup_values.merge(is) }
|
77
|
+
.flat_map do |input_spec|
|
78
|
+
explode_input_specs(input_spec.keys, input_spec)
|
79
|
+
end
|
80
|
+
sets = [{}] if sets.size == 0
|
81
|
+
sets
|
82
|
+
end
|
83
|
+
|
88
84
|
# Expand any values that are enumerators (Thoreau::DSL::Expanded),
|
89
85
|
# creating a list of objects, where all the combinations
|
90
86
|
# of enumerated values are present.
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Thoreau
|
2
|
+
module DSL
|
3
|
+
module Context
|
4
|
+
class Appendix
|
5
|
+
def initialize(appendix_model, &appendix_block)
|
6
|
+
@model = appendix_model
|
7
|
+
self.instance_eval(&appendix_block)
|
8
|
+
end
|
9
|
+
|
10
|
+
def setup name, values = {}, &block
|
11
|
+
@model.add_setup(name, values, block)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require_relative '../../model/test_family'
|
2
|
+
require_relative '../expanded'
|
3
|
+
require_relative '../../service/util'
|
4
|
+
require 'active_support/core_ext/array/conversions'
|
5
|
+
|
6
|
+
module Thoreau
|
7
|
+
module DSL
|
8
|
+
module Context
|
9
|
+
|
10
|
+
SPEC_FAMILY_NAMES = %i[happy sad spec test edge edges boundary corner gigo]
|
11
|
+
# gigo = garbage in / garbage out
|
12
|
+
#
|
13
|
+
PROPS = {
|
14
|
+
asserts: %i[assert asserts post post_condition],
|
15
|
+
expected_exception: %i[raises],
|
16
|
+
expected_output: %i[equals equal expected expect expects output],
|
17
|
+
failure_expected: %i[fails pending],
|
18
|
+
input_specs: %i[input inputs],
|
19
|
+
setups: %i[setup setups assemble]
|
20
|
+
}
|
21
|
+
ALL_PROPS = PROPS.values.flatten.map(&:to_s)
|
22
|
+
PROPS_SPELL_CHECKER = DidYouMean::SpellChecker.new(dictionary: ALL_PROPS)
|
23
|
+
|
24
|
+
module Clan
|
25
|
+
|
26
|
+
# Note: requires `@test_clan_model`.
|
27
|
+
|
28
|
+
def action(&block)
|
29
|
+
logger.debug " + Adding subject block"
|
30
|
+
@test_clan_model.action_block = block
|
31
|
+
end
|
32
|
+
|
33
|
+
alias act action
|
34
|
+
alias testing action
|
35
|
+
alias subject action
|
36
|
+
|
37
|
+
def self.def_family_methods_for(sym)
|
38
|
+
define_method sym do |*args|
|
39
|
+
desc = args.shift if args.size > 1 && args.first.is_a?(String)
|
40
|
+
raise "Too many arguments to #{sym}!" if args.size > 1
|
41
|
+
|
42
|
+
spec = args.first&.stringify_keys || {}
|
43
|
+
spec.keys
|
44
|
+
.reject { |k| ALL_PROPS.include? k }
|
45
|
+
.each do |k|
|
46
|
+
suggestions = PROPS_SPELL_CHECKER.correct(k)
|
47
|
+
logger.error "Ignoring unrecognized property '#{k}'."
|
48
|
+
logger.info " Did you mean #{suggestions.to_sentence}?" if suggestions.size > 0
|
49
|
+
logger.info " Available properties: #{ALL_PROPS.to_sentence}"
|
50
|
+
end
|
51
|
+
|
52
|
+
params = HashUtil.normalize_props(spec.symbolize_keys, PROPS).tap { |props|
|
53
|
+
# These two props are easier to deal with downstream as empty arrays
|
54
|
+
props[:input_specs] = [props[:input_specs]].flatten.compact
|
55
|
+
props[:setups] = [props[:setups]].flatten.compact
|
56
|
+
}.merge kind: sym,
|
57
|
+
desc: desc
|
58
|
+
|
59
|
+
family = Model::TestFamily.new **params
|
60
|
+
|
61
|
+
yield family if block_given?
|
62
|
+
|
63
|
+
logger.debug " * Created new family #{params.inspect}"
|
64
|
+
@test_clan_model.add_test_family family
|
65
|
+
end
|
66
|
+
|
67
|
+
define_method "#{sym}!" do |*args|
|
68
|
+
family = self.send(sym, *args)
|
69
|
+
family.focus = true
|
70
|
+
family
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
SPEC_FAMILY_NAMES.each do |sym|
|
75
|
+
def_family_methods_for sym
|
76
|
+
end
|
77
|
+
|
78
|
+
def_family_methods_for :legacy do |r|
|
79
|
+
r.use_legacy_snapshot = true
|
80
|
+
end
|
81
|
+
|
82
|
+
alias legacy_spec legacy
|
83
|
+
alias legacy_test legacy
|
84
|
+
alias legacy_code legacy
|
85
|
+
alias legacy_spec! legacy!
|
86
|
+
alias legacy_test! legacy!
|
87
|
+
alias legacy_code! legacy!
|
88
|
+
|
89
|
+
def expanded(a)
|
90
|
+
Thoreau::DSL::Expanded.new(a)
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -1,10 +1,10 @@
|
|
1
|
-
require_relative '../test_suite_data'
|
2
1
|
require 'active_support/core_ext/module/delegation'
|
3
2
|
|
4
3
|
module Thoreau
|
5
4
|
module DSL
|
5
|
+
module Context
|
6
6
|
|
7
|
-
class
|
7
|
+
class Suite
|
8
8
|
|
9
9
|
include Thoreau::Logging
|
10
10
|
|
@@ -32,15 +32,8 @@ module Thoreau
|
|
32
32
|
@suite_data.appendix_block = block
|
33
33
|
end
|
34
34
|
|
35
|
-
def context
|
36
|
-
self
|
37
|
-
end
|
38
|
-
|
39
|
-
def add_test_family family
|
40
|
-
suite_data.add_test_family family
|
41
|
-
end
|
42
|
-
|
43
35
|
end
|
44
36
|
|
45
37
|
end
|
46
38
|
end
|
39
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Thoreau
|
2
|
+
module DSL
|
3
|
+
module Context
|
4
|
+
class TestCases
|
5
|
+
|
6
|
+
include Thoreau::Logging
|
7
|
+
|
8
|
+
attr_reader :test_clan_model
|
9
|
+
|
10
|
+
def initialize(clan_model, &context)
|
11
|
+
@test_clan_model = clan_model
|
12
|
+
|
13
|
+
self.instance_eval(&context)
|
14
|
+
end
|
15
|
+
|
16
|
+
include Thoreau::DSL::Context::Clan
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative '../model/setup'
|
2
|
+
|
3
|
+
module Thoreau
|
4
|
+
module DSL
|
5
|
+
class TestSuiteData
|
6
|
+
|
7
|
+
include Thoreau::Logging
|
8
|
+
|
9
|
+
attr_accessor :appendix_block
|
10
|
+
attr_reader :test_cases_blocks
|
11
|
+
|
12
|
+
attr_reader :name
|
13
|
+
attr_reader :test_clans
|
14
|
+
|
15
|
+
def initialize name, appendix:, test_clan:
|
16
|
+
@name = name
|
17
|
+
@appendix = appendix
|
18
|
+
@test_clans = [test_clan]
|
19
|
+
@test_cases_blocks = []
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_setup(name, values, block)
|
23
|
+
logger.debug " Adding setup block #{name}"
|
24
|
+
@appendix.add_setup Thoreau::Model::Setup.new(name, values, block)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/thoreau/dsl.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
|
-
require 'thoreau/logging'
|
2
|
-
require 'thoreau/test_suite'
|
3
|
-
require 'thoreau/
|
4
|
-
require 'thoreau/
|
1
|
+
require 'thoreau/service/logging'
|
2
|
+
require 'thoreau/model/test_suite'
|
3
|
+
require 'thoreau/model/test_case'
|
4
|
+
require 'thoreau/model/test_clan'
|
5
5
|
require 'thoreau/case/case_builder'
|
6
6
|
require 'thoreau/case/suite_runner'
|
7
|
-
require 'thoreau/dsl/
|
8
|
-
require 'thoreau/dsl/
|
9
|
-
require 'thoreau/dsl/
|
10
|
-
require 'thoreau/dsl/
|
7
|
+
require 'thoreau/dsl/test_suite_data'
|
8
|
+
require 'thoreau/dsl/context/clan'
|
9
|
+
require 'thoreau/dsl/context/suite'
|
10
|
+
require 'thoreau/dsl/context/test_cases'
|
11
|
+
require 'thoreau/dsl/context/appendix'
|
11
12
|
require_relative './errors'
|
12
13
|
|
13
14
|
module Thoreau
|
@@ -21,33 +22,33 @@ module Thoreau
|
|
21
22
|
def test_suite name = nil, focus: false, &block
|
22
23
|
logger.debug("# Processing keyword `test_suite`")
|
23
24
|
|
24
|
-
appendix =
|
25
|
-
top_level_clan_model = Thoreau::
|
26
|
-
@suite_data = TestSuiteData.new name, test_clan: top_level_clan_model, appendix: appendix
|
25
|
+
appendix = Model::Appendix.new
|
26
|
+
top_level_clan_model = Thoreau::Model::TestClan.new name, appendix: appendix
|
27
|
+
@suite_data = Thoreau::DSL::TestSuiteData.new name, test_clan: top_level_clan_model, appendix: appendix
|
27
28
|
|
28
29
|
# Evaluate all the top-level keywords: test_cases, appendix
|
29
|
-
@suite_context = Thoreau::DSL::
|
30
|
+
@suite_context = Thoreau::DSL::Context::Suite.new suite_data: @suite_data,
|
30
31
|
test_clan_model: top_level_clan_model
|
31
32
|
logger.debug("## Evaluating suite")
|
32
33
|
@suite_context.instance_eval(&block)
|
33
34
|
|
34
35
|
logger.debug("## Evaluating appendix block")
|
35
36
|
appendix_block = @suite_data.appendix_block
|
36
|
-
Thoreau::DSL::Appendix.new(@suite_data, &appendix_block) unless appendix_block.nil?
|
37
|
+
Thoreau::DSL::Context::Appendix.new(@suite_data, &appendix_block) unless appendix_block.nil?
|
37
38
|
|
38
39
|
logger.debug("## Evaluating test_cases blocks")
|
39
40
|
@suite_data.test_cases_blocks.each do |name, cases_block|
|
40
41
|
|
41
42
|
raise TestCasesAtMultipleLevelsError unless @suite_data.test_clans.first.empty?
|
42
43
|
|
43
|
-
test_clan_model = Thoreau::
|
44
|
+
test_clan_model = Thoreau::Model::TestClan.new name,
|
44
45
|
appendix: appendix,
|
45
46
|
action_block: top_level_clan_model.action_block
|
46
|
-
Thoreau::DSL::TestCases.new(test_clan_model, &cases_block)
|
47
|
+
Thoreau::DSL::Context::TestCases.new(test_clan_model, &cases_block)
|
47
48
|
@suite_data.test_clans << test_clan_model
|
48
49
|
end
|
49
50
|
|
50
|
-
TestSuite.new(data: @suite_data, focus: focus)
|
51
|
+
Model::TestSuite.new(data: @suite_data, focus: focus)
|
51
52
|
end
|
52
53
|
|
53
54
|
def xtest_suite name = nil, &block
|
@@ -62,7 +63,7 @@ module Thoreau
|
|
62
63
|
|
63
64
|
alias suite! test_suite!
|
64
65
|
|
65
|
-
include Thoreau::DSL::Clan
|
66
|
+
include Thoreau::DSL::Context::Clan
|
66
67
|
|
67
68
|
end
|
68
69
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Thoreau
|
2
|
+
module Model
|
3
|
+
class Appendix
|
4
|
+
|
5
|
+
attr_reader :setups
|
6
|
+
|
7
|
+
def initialize setups: {}
|
8
|
+
@setups = setups
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_setup setup
|
12
|
+
raise "Duplicate setup block #{setup.name}" unless setups[setup.name].nil?
|
13
|
+
@setups[setup.name] = setup
|
14
|
+
end
|
15
|
+
|
16
|
+
def setup_values keys
|
17
|
+
keys
|
18
|
+
.map { |key| self.setup_key_to_inputs key }
|
19
|
+
.reduce(Hash.new) { |m, h| m.merge(h) }
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def setup_key_to_inputs key
|
25
|
+
setup = self.setups[key.to_s]
|
26
|
+
raise "Unrecognized setup context '#{key}'. Available: #{self.setups.keys.to_sentence}" if setup.nil?
|
27
|
+
logger.debug(" setup_key_to_inputs `#{key}`: #{setup}")
|
28
|
+
return setup.values if setup.block.nil?
|
29
|
+
|
30
|
+
result = Class.new.new.instance_eval(&setup.block)
|
31
|
+
logger.error "Setup #{key} did not return a hash object" unless result.is_a?(Hash)
|
32
|
+
result
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'active_support/core_ext/module/delegation'
|
2
2
|
require_relative '../case/context_builder'
|
3
3
|
require_relative './outcome'
|
4
|
-
require_relative '../legacy_expected_outcomes'
|
4
|
+
require_relative '../service/legacy_expected_outcomes'
|
5
5
|
|
6
6
|
module Thoreau
|
7
|
-
module
|
7
|
+
module Model
|
8
8
|
class TestCase
|
9
9
|
|
10
10
|
include Thoreau::Logging
|
@@ -39,7 +39,7 @@ module Thoreau
|
|
39
39
|
"#{@family_desc} #{(@input == {} ? nil : @input.sort.to_h) || @expectation.exception || "(no args)"}"
|
40
40
|
end
|
41
41
|
|
42
|
-
def
|
42
|
+
def result_analysis
|
43
43
|
|
44
44
|
run unless @ran
|
45
45
|
|
@@ -47,7 +47,10 @@ module Thoreau
|
|
47
47
|
|
48
48
|
logger.debug " -> Expected Exception #{@expectation.exception} @actual.exception:#{@actual.exception}"
|
49
49
|
|
50
|
-
if @
|
50
|
+
if @expectation.exception.is_a?(Class) &&
|
51
|
+
@actual.exception.class == @expectation.exception
|
52
|
+
nil
|
53
|
+
elsif @actual.exception.to_s == @expectation.exception.to_s
|
51
54
|
nil
|
52
55
|
elsif @actual.exception.nil?
|
53
56
|
"Expected exception, but none raised"
|
@@ -61,7 +64,12 @@ module Thoreau
|
|
61
64
|
|
62
65
|
logger.debug " -> Assert Proc result=#{@assert_result}"
|
63
66
|
|
64
|
-
@
|
67
|
+
if @actual.exception.nil?
|
68
|
+
@assert_result ? nil : "Assertion failed. (got '#{@assert_result}', result='#{@actual.output}')"
|
69
|
+
else
|
70
|
+
"Expected assertion, but raised exception '#{@actual.exception}'"
|
71
|
+
end
|
72
|
+
|
65
73
|
else
|
66
74
|
|
67
75
|
logger.debug " -> Result expected: result=#{@actual.output} expected_output: #{@expectation.output} @actual.exception:#{@actual.exception}"
|
@@ -76,8 +84,20 @@ module Thoreau
|
|
76
84
|
end
|
77
85
|
end
|
78
86
|
|
87
|
+
def problem
|
88
|
+
if failure_expected?
|
89
|
+
if result_analysis.nil?
|
90
|
+
"Failure expected but didn't. Is this implemented already?"
|
91
|
+
else
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
else
|
95
|
+
result_analysis
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
79
99
|
def ok?
|
80
|
-
|
100
|
+
problem.nil?
|
81
101
|
end
|
82
102
|
|
83
103
|
def failed?
|
@@ -89,13 +109,13 @@ module Thoreau
|
|
89
109
|
context_builder = Case::ContextBuilder.new(input: @input)
|
90
110
|
context = context_builder.create_context
|
91
111
|
begin
|
92
|
-
# Only capture exceptions around the
|
112
|
+
# Only capture exceptions around the subject itself.
|
93
113
|
output = context.instance_exec(&(@action_block))
|
94
|
-
@actual =
|
114
|
+
@actual = Model::Outcome.new output: output
|
95
115
|
rescue Exception => e
|
96
116
|
logger.debug("** Exception: #{e.class.name} #{e}")
|
97
117
|
logger.debug("Available local variables: #{@input.keys.empty? ? '(none)' : @input.keys.to_sentence}") if e.is_a? NameError
|
98
|
-
@actual =
|
118
|
+
@actual = Model::Outcome.new exception: e
|
99
119
|
return
|
100
120
|
ensure
|
101
121
|
@ran = true
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'active_support/core_ext/module/delegation'
|
2
|
+
require_relative './appendix'
|
3
|
+
require_relative '../case/multi_clan_case_builder'
|
4
|
+
|
5
|
+
module Thoreau
|
6
|
+
module Model
|
7
|
+
class TestSuite
|
8
|
+
|
9
|
+
@@suites = []
|
10
|
+
|
11
|
+
def initialize(data:, focus:)
|
12
|
+
@data = data
|
13
|
+
@focus = focus
|
14
|
+
@@suites << self
|
15
|
+
|
16
|
+
# @builder = Thoreau::Case::CaseBuilder.new test_clan: @data.test_clan
|
17
|
+
@builder = Thoreau::Case::MultiClanCaseBuilder.new test_clans: @data.test_clans
|
18
|
+
end
|
19
|
+
|
20
|
+
delegate :name, to: :@data
|
21
|
+
|
22
|
+
def build_and_run
|
23
|
+
logger.debug("## build_and_run")
|
24
|
+
cases = @builder.build_test_cases!
|
25
|
+
logger.debug(" ... built #{cases.size} cases")
|
26
|
+
|
27
|
+
runner = Thoreau::Case::SuiteRunner.new @data.name
|
28
|
+
runner.run_test_cases! cases,
|
29
|
+
@builder.skipped_count # for reporting
|
30
|
+
end
|
31
|
+
|
32
|
+
def focused?
|
33
|
+
@focus || @builder.any_focused?
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.run_all!
|
37
|
+
logger.debug("# run_all! ############")
|
38
|
+
run_all = !@@suites.any?(&:focused?)
|
39
|
+
@@suites.each do |suite|
|
40
|
+
if suite.focused? || run_all
|
41
|
+
suite.build_and_run
|
42
|
+
else
|
43
|
+
logger.info(" Suite '#{suite.name}' skipped (unfocused)")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
data/lib/thoreau/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thoreau
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Peterson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-12-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -17,9 +17,6 @@ dependencies:
|
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '5'
|
20
|
-
- - "<"
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: '7'
|
23
20
|
type: :runtime
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -27,9 +24,6 @@ dependencies:
|
|
27
24
|
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '5'
|
30
|
-
- - "<"
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: '7'
|
33
27
|
- !ruby/object:Gem::Dependency
|
34
28
|
name: rainbow
|
35
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -129,26 +123,26 @@ files:
|
|
129
123
|
- lib/thoreau/case/suite_runner.rb
|
130
124
|
- lib/thoreau/configuration.rb
|
131
125
|
- lib/thoreau/dsl.rb
|
132
|
-
- lib/thoreau/dsl/appendix.rb
|
133
|
-
- lib/thoreau/dsl/clan.rb
|
126
|
+
- lib/thoreau/dsl/context/appendix.rb
|
127
|
+
- lib/thoreau/dsl/context/clan.rb
|
128
|
+
- lib/thoreau/dsl/context/suite.rb
|
129
|
+
- lib/thoreau/dsl/context/test_cases.rb
|
134
130
|
- lib/thoreau/dsl/expanded.rb
|
135
|
-
- lib/thoreau/dsl/
|
136
|
-
- lib/thoreau/dsl/test_cases.rb
|
131
|
+
- lib/thoreau/dsl/test_suite_data.rb
|
137
132
|
- lib/thoreau/errors.rb
|
138
|
-
- lib/thoreau/
|
139
|
-
- lib/thoreau/
|
140
|
-
- lib/thoreau/
|
141
|
-
- lib/thoreau/
|
142
|
-
- lib/thoreau/
|
143
|
-
- lib/thoreau/
|
144
|
-
- lib/thoreau/
|
145
|
-
- lib/thoreau/models/test_family.rb
|
133
|
+
- lib/thoreau/model/appendix.rb
|
134
|
+
- lib/thoreau/model/outcome.rb
|
135
|
+
- lib/thoreau/model/setup.rb
|
136
|
+
- lib/thoreau/model/test_case.rb
|
137
|
+
- lib/thoreau/model/test_clan.rb
|
138
|
+
- lib/thoreau/model/test_family.rb
|
139
|
+
- lib/thoreau/model/test_suite.rb
|
146
140
|
- lib/thoreau/rspec.rb
|
147
141
|
- lib/thoreau/rspec/configuration.rb
|
148
142
|
- lib/thoreau/rspec/example_helpers.rb
|
149
|
-
- lib/thoreau/
|
150
|
-
- lib/thoreau/
|
151
|
-
- lib/thoreau/util.rb
|
143
|
+
- lib/thoreau/service/legacy_expected_outcomes.rb
|
144
|
+
- lib/thoreau/service/logging.rb
|
145
|
+
- lib/thoreau/service/util.rb
|
152
146
|
- lib/thoreau/version.rb
|
153
147
|
homepage: https://github.com/ndp/thoreau
|
154
148
|
licenses: []
|
data/lib/thoreau/dsl/appendix.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
require_relative '../models/setup'
|
2
|
-
|
3
|
-
module Thoreau
|
4
|
-
module DSL
|
5
|
-
class Appendix
|
6
|
-
def initialize(appendix_model, &appendix_block)
|
7
|
-
@model = appendix_model
|
8
|
-
self.instance_eval(&appendix_block)
|
9
|
-
end
|
10
|
-
|
11
|
-
def setup name, values = {}, &block
|
12
|
-
@model.add_setup(name, values, block)
|
13
|
-
end
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
end
|
18
|
-
end
|
data/lib/thoreau/dsl/clan.rb
DELETED
@@ -1,94 +0,0 @@
|
|
1
|
-
require_relative '../models/test_family'
|
2
|
-
require_relative './expanded'
|
3
|
-
require_relative '../util'
|
4
|
-
require 'active_support/core_ext/array/conversions'
|
5
|
-
|
6
|
-
module Thoreau
|
7
|
-
module DSL
|
8
|
-
|
9
|
-
SPEC_FAMILY_NAMES = %i[happy sad spec test edge edges boundary corner gigo]
|
10
|
-
# gigo = garbage in / garbage out
|
11
|
-
#
|
12
|
-
PROPS = {
|
13
|
-
asserts: %i[assert asserts post post_condition],
|
14
|
-
expected_exception: %i[raises],
|
15
|
-
expected_output: %i[equals equal expected expect expects output],
|
16
|
-
failure_expected: %i[fails pending],
|
17
|
-
input_specs: %i[input inputs],
|
18
|
-
setups: %i[setup setups]
|
19
|
-
}
|
20
|
-
ALL_PROPS = PROPS.values.flatten.map(&:to_s)
|
21
|
-
PROPS_SPELL_CHECKER = DidYouMean::SpellChecker.new(dictionary: ALL_PROPS)
|
22
|
-
|
23
|
-
module Clan
|
24
|
-
|
25
|
-
# Note: requires `@test_clan_model`.
|
26
|
-
|
27
|
-
def action(&block)
|
28
|
-
logger.debug " + Adding action block"
|
29
|
-
@test_clan_model.action_block = block
|
30
|
-
end
|
31
|
-
alias testing action
|
32
|
-
alias subject action
|
33
|
-
|
34
|
-
|
35
|
-
def self.def_family_methods_for(sym)
|
36
|
-
define_method sym do |*args|
|
37
|
-
desc = args.shift if args.size > 1 && args.first.is_a?(String)
|
38
|
-
raise "Too many arguments to #{sym}!" if args.size > 1
|
39
|
-
|
40
|
-
spec = args.first&.stringify_keys || {}
|
41
|
-
spec.keys
|
42
|
-
.reject { |k| ALL_PROPS.include? k }
|
43
|
-
.each do |k|
|
44
|
-
suggestions = PROPS_SPELL_CHECKER.correct(k)
|
45
|
-
logger.error "Ignoring unrecognized property '#{k}'."
|
46
|
-
logger.info " Did you mean #{suggestions.to_sentence}?" if suggestions.size > 0
|
47
|
-
logger.info " Available properties: #{ALL_PROPS.to_sentence}"
|
48
|
-
end
|
49
|
-
|
50
|
-
params = HashUtil.normalize_props(spec.symbolize_keys, PROPS).tap { |props|
|
51
|
-
# These two props are easier to deal with downstream as empty arrays
|
52
|
-
props[:input_specs] = [props[:input_specs]].flatten.compact
|
53
|
-
props[:setups] = [props[:setups]].flatten.compact
|
54
|
-
}.merge kind: sym,
|
55
|
-
desc: desc
|
56
|
-
|
57
|
-
family = Models::TestFamily.new **params
|
58
|
-
|
59
|
-
yield family if block_given?
|
60
|
-
|
61
|
-
logger.debug " * Created new family #{params.inspect}"
|
62
|
-
@test_clan_model.add_test_family family
|
63
|
-
end
|
64
|
-
|
65
|
-
define_method "#{sym}!" do |*args|
|
66
|
-
family = self.send(sym, *args)
|
67
|
-
family.focus = true
|
68
|
-
family
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
SPEC_FAMILY_NAMES.each do |sym|
|
73
|
-
def_family_methods_for sym
|
74
|
-
end
|
75
|
-
|
76
|
-
def_family_methods_for :legacy do |r|
|
77
|
-
r.use_legacy_snapshot = true
|
78
|
-
end
|
79
|
-
|
80
|
-
alias legacy_spec legacy
|
81
|
-
alias legacy_test legacy
|
82
|
-
alias legacy_code legacy
|
83
|
-
alias legacy_spec! legacy!
|
84
|
-
alias legacy_test! legacy!
|
85
|
-
alias legacy_code! legacy!
|
86
|
-
|
87
|
-
def expanded(a)
|
88
|
-
Thoreau::DSL::Expanded.new(a)
|
89
|
-
end
|
90
|
-
|
91
|
-
end
|
92
|
-
|
93
|
-
end
|
94
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module Thoreau
|
2
|
-
module DSL
|
3
|
-
class TestCases
|
4
|
-
|
5
|
-
include Thoreau::Logging
|
6
|
-
|
7
|
-
attr_reader :test_clan_model
|
8
|
-
|
9
|
-
def initialize(clan_model, &context)
|
10
|
-
@test_clan_model = clan_model
|
11
|
-
|
12
|
-
self.instance_eval(&context)
|
13
|
-
end
|
14
|
-
|
15
|
-
include Thoreau::DSL::Clan
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|
20
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module Thoreau
|
2
|
-
module Models
|
3
|
-
class Appendix
|
4
|
-
|
5
|
-
attr_reader :setups
|
6
|
-
|
7
|
-
def initialize setups: {}
|
8
|
-
@setups = setups
|
9
|
-
end
|
10
|
-
|
11
|
-
def add_setup setup
|
12
|
-
raise "Duplicate setup block #{setup.name}" unless setups[setup.name].nil?
|
13
|
-
@setups[setup.name] = setup
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
data/lib/thoreau/test_suite.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
require_relative './models/appendix'
|
2
|
-
require_relative './case/multi_clan_case_builder'
|
3
|
-
require 'active_support/core_ext/module/delegation'
|
4
|
-
|
5
|
-
module Thoreau
|
6
|
-
class TestSuite
|
7
|
-
|
8
|
-
@@suites = []
|
9
|
-
|
10
|
-
def initialize(data:, focus:)
|
11
|
-
@data = data
|
12
|
-
@focus = focus
|
13
|
-
@@suites << self
|
14
|
-
|
15
|
-
# @builder = Thoreau::Case::CaseBuilder.new test_clan: @data.test_clan
|
16
|
-
@builder = Thoreau::Case::MultiClanCaseBuilder.new test_clans: @data.test_clans
|
17
|
-
end
|
18
|
-
|
19
|
-
delegate :name, to: :@data
|
20
|
-
|
21
|
-
def build_and_run
|
22
|
-
logger.debug("## build_and_run")
|
23
|
-
cases = @builder.build_test_cases!
|
24
|
-
logger.debug(" ... built #{cases.size} cases")
|
25
|
-
|
26
|
-
runner = Thoreau::Case::SuiteRunner.new @data.name
|
27
|
-
runner.run_test_cases! cases,
|
28
|
-
@builder.skipped_count # for reporting
|
29
|
-
end
|
30
|
-
|
31
|
-
def focused?
|
32
|
-
@focus || @builder.any_focused?
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.run_all!
|
36
|
-
logger.debug("# run_all! ############")
|
37
|
-
run_all = !@@suites.any?(&:focused?)
|
38
|
-
@@suites.each do |suite|
|
39
|
-
if suite.focused? || run_all
|
40
|
-
suite.build_and_run
|
41
|
-
else
|
42
|
-
logger.info(" Suite '#{suite.name}' skipped (unfocused)")
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
require_relative './models/test_clan'
|
2
|
-
|
3
|
-
module Thoreau
|
4
|
-
class TestSuiteData
|
5
|
-
|
6
|
-
include Thoreau::Logging
|
7
|
-
|
8
|
-
attr_accessor :appendix_block
|
9
|
-
attr_reader :test_cases_blocks
|
10
|
-
|
11
|
-
attr_reader :name
|
12
|
-
attr_reader :test_clans
|
13
|
-
|
14
|
-
def initialize name, appendix:, test_clan:
|
15
|
-
@name = name
|
16
|
-
@appendix = appendix
|
17
|
-
@test_clans = [test_clan]
|
18
|
-
@test_cases_blocks = []
|
19
|
-
end
|
20
|
-
|
21
|
-
def add_setup(name, values, block)
|
22
|
-
logger.debug " Adding setup block #{name}"
|
23
|
-
@appendix.add_setup Thoreau::Models::Setup.new(name, values, block)
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
27
|
-
end
|