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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 732fd064266fbd5f93dab80bee925ea5a61031de4cfdc82a9015ce5ac0e16c0d
4
- data.tar.gz: 82a1e6dabb420fce9d2260c07a7913ecc996838b3f4e0d98f2f5a8938cafcdaa
3
+ metadata.gz: c492a383143335b6073d8677862b0228568e00977882f2c8483a8f6a78851a14
4
+ data.tar.gz: de415989640870528ad0f031c694173893600327d0f563d429339660c09a5b55
5
5
  SHA512:
6
- metadata.gz: ac549caf454efbc7d6e5806176897dd10a93177c34bea768f27030a49ed1c2da3bf8ad63ee86deb45ee4f5148a48f136f04ad24cacc63b921c03cdcd0912be37
7
- data.tar.gz: 1acaf812da2937c14ae7b509fcdd96bf0c3211b4eeaa06eabe97ce032c1d50401915e316bfa3a39558e78895646fb11186c18fa0c730e45dd9f5a3c04f7a7577
6
+ metadata.gz: 65a16a5f32ff2a33717c675b0d6128212b93ce93a5eafff87ea7ea949deff1925fd2844ddd7b67dae1da74a3af18a8eb9d9146efaccfeaed3b71f16a5d1338ff
7
+ data.tar.gz: 567112f783bdd3ccc730378c3b89f4492869916302f5face9b2602f144d4ce55afe65997b506e0e5f3adaed8e759b38b23254b1376d6919e58b37141f0294427
@@ -1,5 +1,6 @@
1
+ require_relative '../thoreau'
1
2
  require_relative './dsl'
2
3
 
3
4
  at_exit do
4
- Thoreau::TestSuite.run_all!
5
+ Thoreau::Model::TestSuite.run_all!
5
6
  end
@@ -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
- .map { |key| setup_key_to_inputs key }
60
- .reduce(Hash.new) { |m, h| m.merge(h) }
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 = fam.input_specs
64
- .map { |is| setup_values.merge(is) }
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
- input_sets.map do |input_set|
57
+ input_hashes.map do |input_hash|
73
58
  expectation = fam.use_legacy_snapshot ?
74
59
  :use_legacy_snapshot :
75
- Models::Outcome.new(output: fam.expected_output,
60
+ Model::Outcome.new(output: fam.expected_output,
76
61
  exception: fam.expected_exception)
77
62
 
78
- Thoreau::Models::TestCase.new family_desc: "#{fam.kind.to_s.ljust(10).capitalize} #{fam.desc}",
79
- input: input_set,
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.
@@ -7,8 +7,8 @@ module Thoreau
7
7
 
8
8
  include Logging
9
9
 
10
- def initialize(name)
11
- @suite_name = name
10
+ def initialize(suite_name)
11
+ @suite_name = suite_name
12
12
  end
13
13
 
14
14
  def run_test_cases! cases, skipped
@@ -3,7 +3,7 @@ module Thoreau
3
3
  attr_accessor :legacy_outcome_path
4
4
 
5
5
  def initialize
6
- @legacy_outcome_path = './tmp/legacy-outcomes.pstore'
6
+ @legacy_outcome_path = './spec/legacy-outcomes.pstore'
7
7
  end
8
8
  end
9
9
  end
@@ -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 SuiteContext
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/models/test_case'
4
- require 'thoreau/models/test_clan'
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/clan'
8
- require 'thoreau/dsl/suite_context'
9
- require 'thoreau/dsl/test_cases'
10
- require 'thoreau/dsl/appendix'
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 = Models::Appendix.new
25
- top_level_clan_model = Thoreau::Models::TestClan.new name, appendix: appendix
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::SuiteContext.new suite_data: @suite_data,
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::Models::TestClan.new name,
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,5 +1,5 @@
1
1
  module Thoreau
2
- module Models
2
+ module Model
3
3
  class Outcome
4
4
  # Reprents the outcome of a given test case.
5
5
  # It can either be successful and have an `output`,
@@ -1,5 +1,5 @@
1
1
  module Thoreau
2
- module Models
2
+ module Model
3
3
 
4
4
  class Setup
5
5
 
@@ -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 Models
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 problem
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 @actual.exception.to_s == @expectation.exception.to_s
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
- @assert_result ? nil : "Assertion failed. (got #{@assert_result})"
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
- failure_expected? ^ !!problem.nil?
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 action itself.
112
+ # Only capture exceptions around the subject itself.
93
113
  output = context.instance_exec(&(@action_block))
94
- @actual = Models::Outcome.new output: output
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 = Models::Outcome.new exception: e
118
+ @actual = Model::Outcome.new exception: e
99
119
  return
100
120
  ensure
101
121
  @ran = true
@@ -3,7 +3,7 @@ require_relative '../errors'
3
3
 
4
4
  module Thoreau
5
5
 
6
- module Models
6
+ module Model
7
7
  class TestClan # set of TestFamilies
8
8
 
9
9
  include Thoreau::Logging
@@ -1,5 +1,5 @@
1
1
  module Thoreau
2
- module Models
2
+ module Model
3
3
 
4
4
  class TestFamily
5
5
  attr_reader :asserts,
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Thoreau
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3.0"
3
3
  end
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.2.2
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-09-09 00:00:00.000000000 Z
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/suite_context.rb
136
- - lib/thoreau/dsl/test_cases.rb
131
+ - lib/thoreau/dsl/test_suite_data.rb
137
132
  - lib/thoreau/errors.rb
138
- - lib/thoreau/legacy_expected_outcomes.rb
139
- - lib/thoreau/logging.rb
140
- - lib/thoreau/models/appendix.rb
141
- - lib/thoreau/models/outcome.rb
142
- - lib/thoreau/models/setup.rb
143
- - lib/thoreau/models/test_case.rb
144
- - lib/thoreau/models/test_clan.rb
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/test_suite.rb
150
- - lib/thoreau/test_suite_data.rb
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: []
@@ -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
@@ -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
@@ -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