casegen 2.0.0 → 3.0.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/.rspec +1 -0
- data/.rubocop.yml +109 -0
- data/.ruby-version +1 -1
- data/Gemfile +3 -1
- data/Gemfile.lock +63 -6
- data/README.md +10 -119
- data/Rakefile +9 -7
- data/bin/casegen +2 -1
- data/casegen.gemspec +13 -9
- data/doc/bounding_box.rb +37 -0
- data/doc/cart.rb +43 -0
- data/doc/expect_only.rb +28 -0
- data/doc/pricing.rb +50 -0
- data/doc/ruby_array.rb +41 -0
- data/lib/case_gen/combination.rb +38 -0
- data/lib/case_gen/combo_matcher.rb +15 -0
- data/lib/case_gen/exclude_rule.rb +50 -0
- data/lib/case_gen/expect_rule.rb +24 -0
- data/lib/case_gen/generator.rb +40 -0
- data/lib/case_gen/output/exclude.rb +6 -0
- data/lib/case_gen/output/exclude_as_table.rb +13 -0
- data/lib/case_gen/output/exclude_as_text.rb +12 -0
- data/lib/case_gen/output/exclude_inline.rb +13 -0
- data/lib/case_gen/output/exclude_inline_footnotes.rb +20 -0
- data/lib/case_gen/output.rb +66 -0
- data/lib/case_gen/rule_description.rb +11 -0
- data/lib/case_gen/set.rb +16 -0
- data/lib/casegen.rb +15 -183
- data/spec/cart_sample_spec.rb +46 -0
- data/spec/case_gen/combination_spec.rb +11 -0
- data/spec/case_gen/exclude_rule_spec.rb +17 -0
- data/spec/exclude_as_table_spec.rb +39 -0
- data/spec/exclude_as_text_spec.rb +58 -0
- data/spec/exclude_inline_footnotes_spec.rb +58 -0
- data/spec/exclude_inline_spec.rb +50 -0
- data/spec/expect_only_spec.rb +30 -0
- data/spec/spec_helper.rb +113 -0
- metadata +103 -40
- data/.idea/encodings.xml +0 -5
- data/.idea/misc.xml +0 -5
- data/.idea/modules.xml +0 -9
- data/.idea/vcs.xml +0 -7
- data/doc/calc.sample.txt +0 -13
- data/doc/cart.sample.rb +0 -3
- data/doc/cart.sample.txt +0 -33
- data/doc/ruby_array.sample.rb +0 -26
- data/lib/agents/sets/enum/by.rb +0 -244
- data/lib/agents/sets/enum/cluster.rb +0 -164
- data/lib/agents/sets/enum/inject.rb +0 -50
- data/lib/agents/sets/enum/nest.rb +0 -117
- data/lib/agents/sets/enum/op.rb +0 -283
- data/lib/agents/sets/enum/pipe.rb +0 -160
- data/lib/agents/sets/enum/tree.rb +0 -442
- data/lib/agents/sets.rb +0 -313
- data/test/agents/console_output_test.rb +0 -27
- data/test/agents/sets.test.rb +0 -227
- data/test/agents_test.rb +0 -41
- data/test/casegen.tests.rb +0 -0
- data/test/parser_test.rb +0 -163
- data/test/test_helper.rb +0 -2
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CaseGen
|
4
|
+
module ComboMatcher
|
5
|
+
def matches_criteria(combo, additional_ignore_keys = [])
|
6
|
+
criteria_keys = (@rule_data.keys - additional_ignore_keys) - ignore_keys
|
7
|
+
criteria = @rule_data.slice(*criteria_keys)
|
8
|
+
criteria == combo.hash_row.slice(*criteria_keys)
|
9
|
+
end
|
10
|
+
|
11
|
+
def ignore_keys
|
12
|
+
%i[description reason note index]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CaseGen
|
4
|
+
class ExcludeRule
|
5
|
+
include ComboMatcher
|
6
|
+
include RuleDescription
|
7
|
+
|
8
|
+
attr_reader :rule_data, :description
|
9
|
+
|
10
|
+
def initialize(rule_data)
|
11
|
+
@rule_data = rule_data
|
12
|
+
@description = rule_description(rule_data)
|
13
|
+
@criteria = rule_data[:criteria]
|
14
|
+
end
|
15
|
+
|
16
|
+
def apply(combos)
|
17
|
+
matches = combos.select do |combo|
|
18
|
+
case @criteria
|
19
|
+
when String
|
20
|
+
combo.instance_eval(@criteria)
|
21
|
+
when Proc
|
22
|
+
combo.instance_exec(&@criteria)
|
23
|
+
when nil
|
24
|
+
# if the rule data has keys matching the combo, then compare the
|
25
|
+
# values of provided keys.
|
26
|
+
matches_criteria(combo)
|
27
|
+
else
|
28
|
+
raise "Unknown rule criteria class: #{@criteria.class}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
process_matches(combos, matches)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def process_matches(combos, matches)
|
38
|
+
combos.each do |combo|
|
39
|
+
next unless matches.include?(combo)
|
40
|
+
next if combo.excluded?
|
41
|
+
|
42
|
+
combo.exclude_with(self)
|
43
|
+
expect_keys = combo.names.select { |name| combo.send(name) == :expect }
|
44
|
+
expect_keys.each do |expect_key|
|
45
|
+
combo.send("#{expect_key}=", '')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CaseGen
|
4
|
+
class ExpectRule
|
5
|
+
include ComboMatcher
|
6
|
+
|
7
|
+
def initialize(rule_data)
|
8
|
+
@rule_data = rule_data
|
9
|
+
end
|
10
|
+
|
11
|
+
def apply(combos)
|
12
|
+
combos.each do |combo|
|
13
|
+
expect_keys = combo.names.select { |name| combo.send(name) == :expect }
|
14
|
+
next if expect_keys.none?
|
15
|
+
|
16
|
+
next unless matches_criteria(combo, expect_keys)
|
17
|
+
|
18
|
+
expect_keys.each do |expect_key|
|
19
|
+
combo.send("#{expect_key}=", @rule_data[expect_key])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tablesmith'
|
4
|
+
|
5
|
+
module CaseGen
|
6
|
+
class Generator
|
7
|
+
attr_reader :sets, :rules, :combos, :exclusions
|
8
|
+
|
9
|
+
def initialize(sets, rules)
|
10
|
+
@sets = sets.map do |title, values|
|
11
|
+
CaseGen::Set.new(title, values)
|
12
|
+
end
|
13
|
+
@rules = rules
|
14
|
+
@combos = generate_combinations
|
15
|
+
apply_rules
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def generate_combinations
|
21
|
+
hash_pairs = @sets.map(&:hash_pairs)
|
22
|
+
product_of(hash_pairs).map { |c| Combination.new(c) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def product_of(sets)
|
26
|
+
head, *rest = sets
|
27
|
+
head.product(*rest)
|
28
|
+
end
|
29
|
+
|
30
|
+
def apply_rules
|
31
|
+
@rules.each do |type, rules|
|
32
|
+
klass = CaseGen.const_get("#{type.to_s.capitalize}Rule")
|
33
|
+
rules.each_with_index do |rule_data, idx|
|
34
|
+
rule_data[:index] = idx + 1
|
35
|
+
klass.new(rule_data).apply(@combos)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CaseGen
|
4
|
+
class ExcludeAsText < CaseGen::Output
|
5
|
+
def exclude_output(_)
|
6
|
+
body = @generator.rules[:exclude].map do |rule|
|
7
|
+
[rule[:criteria], " #{rule_description(rule)}", '']
|
8
|
+
end
|
9
|
+
(header + body).join("\n")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CaseGen
|
4
|
+
class ExcludeInlineFootnotes < CaseGen::Output
|
5
|
+
def partition_exclusions?
|
6
|
+
false
|
7
|
+
end
|
8
|
+
|
9
|
+
def exclude_description(rule)
|
10
|
+
"[#{rule.rule_data[:index]}]"
|
11
|
+
end
|
12
|
+
|
13
|
+
def exclude_output(_)
|
14
|
+
body = @generator.rules[:exclude].map do |rule|
|
15
|
+
["[#{rule[:index]}] #{rule_description(rule)}"]
|
16
|
+
end
|
17
|
+
(header + body).join("\n")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CaseGen
|
4
|
+
class Output
|
5
|
+
def self.create(generator, output_type = :exclude)
|
6
|
+
klass_name = output_type.to_s.split('_').map(&:capitalize).join.to_s
|
7
|
+
Object.const_get("CaseGen::#{klass_name}").new(generator)
|
8
|
+
end
|
9
|
+
|
10
|
+
include RuleDescription
|
11
|
+
|
12
|
+
def initialize(generator)
|
13
|
+
@generator = generator
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
update_excluded_values
|
18
|
+
include, exclude = partition_exclusions
|
19
|
+
as_table(include).tap { |o| o << exclude_output(exclude) }
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def exclude_output(_exclude)
|
25
|
+
''
|
26
|
+
end
|
27
|
+
|
28
|
+
def as_table(combos)
|
29
|
+
combos.map(&:hash_row).to_table.to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
def update_excluded_values
|
33
|
+
@generator.combos.each do |combo|
|
34
|
+
if combo.excluded?
|
35
|
+
value = exclude_description(combo.excluded_by_rule)
|
36
|
+
combo.append(:exclude, value)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def partition_exclusions
|
42
|
+
combos = @generator.combos
|
43
|
+
|
44
|
+
if partition_exclusions?
|
45
|
+
exclude, include = combos.partition(&:excluded?)
|
46
|
+
[include, exclude]
|
47
|
+
else
|
48
|
+
[combos, []]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def partition_exclusions?
|
53
|
+
true
|
54
|
+
end
|
55
|
+
|
56
|
+
def exclude_description(_rule)
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
|
60
|
+
def header
|
61
|
+
['', 'exclude', '-------']
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
Dir[File.join(__dir__, 'output', '*.rb')].sort.each { |fn| require fn }
|
data/lib/case_gen/set.rb
ADDED
data/lib/casegen.rb
CHANGED
@@ -1,185 +1,17 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
attr_reader :data, :reference_agents
|
17
|
-
|
18
|
-
def initialize(data, agents)
|
19
|
-
@data = data
|
20
|
-
@reference_agents = agents
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
class Agents
|
25
|
-
include Singleton
|
26
|
-
|
27
|
-
def initialize
|
28
|
-
clear
|
29
|
-
end
|
30
|
-
|
31
|
-
def register(agent)
|
32
|
-
if agent.class == Class && agent.ancestors.include?(Agent)
|
33
|
-
@agents << agent
|
34
|
-
else
|
35
|
-
raise AgentException.new("To register an agent, you must pass in a Class instance that's a subclass of Agent")
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def method_missing(methid, *args, &block)
|
40
|
-
@agents.send(methid, *args, &block)
|
41
|
-
end
|
42
|
-
|
43
|
-
def get_agent_by_id(id)
|
44
|
-
@agents.each do |agent|
|
45
|
-
return agent if agent.agent_id =~ /#{id}/i
|
46
|
-
end
|
47
|
-
# rather than return nil and allow the client to get bumfuzzled if
|
48
|
-
# they forget to check for nil, let's blow up and tell them how to
|
49
|
-
# not let it happen again
|
50
|
-
raise AgentException.new("Requested an agent that does not exist. You can query for existance with .id_registered?")
|
51
|
-
end
|
52
|
-
|
53
|
-
def id_registered?(id)
|
54
|
-
begin
|
55
|
-
get_agent_by_id(id)
|
56
|
-
return true
|
57
|
-
rescue AgentException
|
58
|
-
return false
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
# removes all registered agents
|
63
|
-
def clear
|
64
|
-
@agents = []
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
class ParserException < Exception
|
69
|
-
end
|
70
|
-
|
71
|
-
class Parser
|
72
|
-
attr_reader :agents
|
73
|
-
|
74
|
-
def initialize(data)
|
75
|
-
@data = data
|
76
|
-
@agents = []
|
77
|
-
parse
|
78
|
-
end
|
79
|
-
|
80
|
-
def parse
|
81
|
-
lines = @data.split(/\n/)
|
82
|
-
while !lines.empty?
|
83
|
-
line = lines.shift
|
84
|
-
next if line.strip.empty?
|
85
|
-
|
86
|
-
data = nil
|
87
|
-
agent_class, reference_agents = parse_agent(line)
|
88
|
-
|
89
|
-
next_line = lines.shift
|
90
|
-
if next_line =~ /^-+/
|
91
|
-
data = parse_data(lines).join("\n")
|
92
|
-
else
|
93
|
-
raise ParserException.new("Expected hyphen line after the agent declaration for <#{agent_class}>")
|
94
|
-
end
|
95
|
-
|
96
|
-
@agents << agent_class.new(data, reference_agents)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def parse_data(lines)
|
101
|
-
end_index = -1
|
102
|
-
lines.each_with_index do |line, index|
|
103
|
-
if line =~ /^-+/
|
104
|
-
end_index = index - 2
|
105
|
-
return lines.slice!(0, end_index)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
return lines.slice!(0, lines.length)
|
109
|
-
end
|
110
|
-
|
111
|
-
def parse_agent(line)
|
112
|
-
agent_name, *reference_agent_names = line.split(/(?=\()/)
|
113
|
-
raise ParserException.new("Nested agents ( e.g. a(b(c)) ) not supported yet") if reference_agent_names.length > 1
|
114
|
-
if reference_agent_names.length > 0
|
115
|
-
reference_agent_names = reference_agent_names[0].gsub(/\(|\)/, '').split(/,/)
|
116
|
-
reference_agent_names.collect! do |name|
|
117
|
-
name.strip
|
118
|
-
end
|
119
|
-
else
|
120
|
-
reference_agent_names = []
|
121
|
-
end
|
122
|
-
|
123
|
-
[agent_name, reference_agent_names].flatten.each do |a_name|
|
124
|
-
raise ParserException.new("Unregistered agent <#{a_name}> in agent name data <#{line}>") if !Agents.instance.id_registered?(a_name)
|
125
|
-
end
|
126
|
-
|
127
|
-
reference_agents = []
|
128
|
-
reference_agent_names.each do |ref_name|
|
129
|
-
@agents.each do |agent|
|
130
|
-
reference_agents << agent if agent.class.agent_id =~ /#{ref_name}/i
|
131
|
-
end
|
132
|
-
end
|
133
|
-
agent_class = Agents.instance.get_agent_by_id(agent_name)
|
134
|
-
[agent_class, reference_agents]
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
class CaseGen
|
139
|
-
def CaseGen.version
|
140
|
-
'2.0.0'
|
141
|
-
end
|
142
|
-
|
143
|
-
def initialize(data)
|
144
|
-
load_agents
|
145
|
-
Parser.new(data)
|
146
|
-
end
|
147
|
-
|
148
|
-
def load_agents
|
149
|
-
agent_dir = "#{File.dirname(__FILE__)}/agents"
|
150
|
-
agent_fns = Dir[File.join(agent_dir, '*.rb')]
|
151
|
-
agent_fns.each do |fn|
|
152
|
-
require fn
|
153
|
-
end
|
154
|
-
ObjectSpace.each_object(Class) do |klass|
|
155
|
-
if klass.ancestors.include?(Agent) && (klass != Agent)
|
156
|
-
Agents.instance.register(klass)
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
class Console
|
163
|
-
def initialize
|
164
|
-
put_banner
|
165
|
-
|
166
|
-
if ARGV[0].nil? || !File.exists?(ARGV[0])
|
167
|
-
puts "Case file required: #{File.basename($0)} [case filename]. For example:"
|
168
|
-
puts " #{File.basename($0)} cases.txt"
|
169
|
-
puts
|
170
|
-
exit
|
171
|
-
end
|
172
|
-
|
173
|
-
CaseGen.new(File.read(ARGV[0]))
|
174
|
-
end
|
175
|
-
|
176
|
-
def put_banner
|
177
|
-
$stderr.puts "cLabs Casegen #{CaseGen.version}"
|
178
|
-
end
|
179
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'case_gen/rule_description'
|
4
|
+
require_relative 'case_gen/set'
|
5
|
+
require_relative 'case_gen/combo_matcher'
|
6
|
+
require_relative 'case_gen/exclude_rule'
|
7
|
+
require_relative 'case_gen/expect_rule'
|
8
|
+
require_relative 'case_gen/combination'
|
9
|
+
require_relative 'case_gen/generator'
|
10
|
+
require_relative 'case_gen/output'
|
11
|
+
|
12
|
+
module CaseGen
|
13
|
+
def self.generate(sets, rules, output_type = :exclude)
|
14
|
+
generator = CaseGen::Generator.new(sets, rules)
|
15
|
+
CaseGen::Output.create(generator, output_type).to_s
|
180
16
|
end
|
181
17
|
end
|
182
|
-
|
183
|
-
if __FILE__ == $0
|
184
|
-
CLabs::CaseGen::Console.new
|
185
|
-
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe 'Cart Sample' do
|
6
|
+
let(:expected) do
|
7
|
+
<<~_
|
8
|
+
+-------------+--------+----------+-----------------+-----------------+
|
9
|
+
| payment | amount | shipping | ship_to_country | bill_to_country |
|
10
|
+
+-------------+--------+----------+-----------------+-----------------+
|
11
|
+
| Credit | 100 | Ground | US | US |
|
12
|
+
| Credit | 100 | Air | US | US |
|
13
|
+
| Credit | 100 | Air | Outside US | US |
|
14
|
+
| Credit | 100 | Air | Outside US | Outside US |
|
15
|
+
| Credit | 1000 | Ground | US | US |
|
16
|
+
| Credit | 1000 | Air | US | US |
|
17
|
+
| Credit | 1000 | Air | Outside US | US |
|
18
|
+
| Credit | 1000 | Air | Outside US | Outside US |
|
19
|
+
| Credit | 10000 | Ground | US | US |
|
20
|
+
| Credit | 10000 | Air | US | US |
|
21
|
+
| Credit | 10000 | Air | Outside US | US |
|
22
|
+
| Credit | 10000 | Air | Outside US | Outside US |
|
23
|
+
| Check | 100 | Ground | US | US |
|
24
|
+
| Check | 100 | Air | US | US |
|
25
|
+
| Check | 100 | Air | Outside US | US |
|
26
|
+
| Check | 1000 | Ground | US | US |
|
27
|
+
| Check | 1000 | Air | US | US |
|
28
|
+
| Check | 1000 | Air | Outside US | US |
|
29
|
+
| Check | 10000 | Ground | US | US |
|
30
|
+
| Check | 10000 | Air | US | US |
|
31
|
+
| Check | 10000 | Air | Outside US | US |
|
32
|
+
| Online Bank | 100 | Ground | US | US |
|
33
|
+
| Online Bank | 100 | Air | US | US |
|
34
|
+
| Online Bank | 100 | Air | Outside US | US |
|
35
|
+
| Online Bank | 100 | Air | Outside US | Outside US |
|
36
|
+
+-------------+--------+----------+-----------------+-----------------+
|
37
|
+
_
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'works' do
|
41
|
+
require_relative '../doc/cart'
|
42
|
+
|
43
|
+
fix = Fixtures[:cart]
|
44
|
+
expect(CaseGen.generate(fix[:sets], fix[:rules])).to eq expected
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe CaseGen::ExcludeRule do
|
4
|
+
it 'removes expect if excluded inline' do
|
5
|
+
combo = CaseGen::Combination.new([{a: 1}, {b: :expect}])
|
6
|
+
rule = described_class.new({criteria: 'a == 1', note: 'nope'})
|
7
|
+
rule.apply([combo])
|
8
|
+
expect(combo).to be_excluded
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'marks combo as exclude on matching key/values in rule data' do
|
12
|
+
combo = CaseGen::Combination.new([{a: 1}, {b: 2}])
|
13
|
+
rule = described_class.new({b: 2, note: 'nope'})
|
14
|
+
rule.apply([combo])
|
15
|
+
expect(combo).to be_excluded
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require_relative '../doc/bounding_box'
|
5
|
+
|
6
|
+
RSpec.describe 'Exclude as table' do
|
7
|
+
let(:expected_combo_table) do
|
8
|
+
<<~_
|
9
|
+
+---------+---------+--------+---------+
|
10
|
+
| width | height | aspect | result |
|
11
|
+
+---------+---------+--------+---------+
|
12
|
+
| inside | inside | wide | 200x100 |
|
13
|
+
| inside | inside | tall | 100x200 |
|
14
|
+
| inside | outside | tall | 100x400 |
|
15
|
+
| outside | inside | wide | 400x100 |
|
16
|
+
| outside | outside | wide | 500x400 |
|
17
|
+
| outside | outside | tall | 400x500 |
|
18
|
+
+---------+---------+--------+---------+
|
19
|
+
_
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:expected_exclude_as_table) do
|
23
|
+
<<~_
|
24
|
+
+---------+---------+--------+--------+--------------------------------------------+
|
25
|
+
| width | height | aspect | result | exclude |
|
26
|
+
+---------+---------+--------+--------+--------------------------------------------+
|
27
|
+
| inside | outside | wide | | a narrower image cannot have a wide aspect |
|
28
|
+
| outside | inside | tall | | a shorter image cannot have a tall aspect |
|
29
|
+
+---------+---------+--------+--------+--------------------------------------------+
|
30
|
+
_
|
31
|
+
end
|
32
|
+
|
33
|
+
let(:fix) { Fixtures[:box] }
|
34
|
+
|
35
|
+
it 'output' do
|
36
|
+
output = CaseGen.generate(fix[:sets], fix[:rules], :exclude_as_table)
|
37
|
+
expect(output.to_s).to eq "#{expected_combo_table}\n#{expected_exclude_as_table}"
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require_relative '../doc/pricing'
|
5
|
+
|
6
|
+
RSpec.describe 'Exclude as text' do
|
7
|
+
let(:expected_combo_table) do
|
8
|
+
<<~_
|
9
|
+
+----------+----------+-------+--------+
|
10
|
+
| subtotal | discount | promo | total |
|
11
|
+
+----------+----------+-------+--------+
|
12
|
+
| 25 | 0% | none | 25.00 |
|
13
|
+
| 25 | 0% | apr | 17.50 |
|
14
|
+
| 25 | 0% | fall | 16.25 |
|
15
|
+
| 75 | 10% | none | 67.50 |
|
16
|
+
| 75 | 10% | apr | 47.25 |
|
17
|
+
| 75 | 10% | fall | 43.88 |
|
18
|
+
| 200 | 20% | none | 160.00 |
|
19
|
+
+----------+----------+-------+--------+
|
20
|
+
_
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:expected_exclude_as_text) do
|
24
|
+
<<~_
|
25
|
+
exclude
|
26
|
+
-------
|
27
|
+
subtotal < 100 && discount == '20%'
|
28
|
+
Total must be above $100 to apply the 20% discount
|
29
|
+
|
30
|
+
(subtotal < 50) && discount == '10%'
|
31
|
+
Total must be above $50 to apply the 10% discount
|
32
|
+
|
33
|
+
discount != '20%' && subtotal == 200
|
34
|
+
Orders over 100 automatically get 20% discount
|
35
|
+
|
36
|
+
discount != '10%' && subtotal == 75
|
37
|
+
Orders between 50 and 100 automatically get 10% discount
|
38
|
+
|
39
|
+
discount == '20%' && promo != 'none'
|
40
|
+
20% discount cannot be combined with promo
|
41
|
+
_
|
42
|
+
end
|
43
|
+
|
44
|
+
let(:generator) do
|
45
|
+
fix = Fixtures[:pricing]
|
46
|
+
CaseGen::Generator.new(fix[:sets], fix[:rules])
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'output only combos table' do
|
50
|
+
output = CaseGen::Exclude.new(generator)
|
51
|
+
expect(output.to_s).to eq expected_combo_table
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'outputs with exclude as text' do
|
55
|
+
output = CaseGen::ExcludeAsText.new(generator)
|
56
|
+
expect(output.to_s).to eq "#{expected_combo_table}\n#{expected_exclude_as_text}"
|
57
|
+
end
|
58
|
+
end
|