app_archetype 1.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.doxie.json +25 -0
- data/.github/workflows/build.yml +25 -0
- data/.gitignore +22 -0
- data/.rubocop.yml +35 -0
- data/.ruby-version +1 -0
- data/CONTRIBUTING.md +51 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +172 -0
- data/LICENSE +21 -0
- data/README.md +138 -0
- data/Rakefile +19 -0
- data/app_archetype.gemspec +39 -0
- data/bin/archetype +20 -0
- data/lib/app_archetype.rb +14 -0
- data/lib/app_archetype/cli.rb +204 -0
- data/lib/app_archetype/cli/presenters.rb +106 -0
- data/lib/app_archetype/cli/prompts.rb +152 -0
- data/lib/app_archetype/generators.rb +95 -0
- data/lib/app_archetype/logger.rb +69 -0
- data/lib/app_archetype/renderer.rb +116 -0
- data/lib/app_archetype/template.rb +12 -0
- data/lib/app_archetype/template/helpers.rb +216 -0
- data/lib/app_archetype/template/manifest.rb +193 -0
- data/lib/app_archetype/template/plan.rb +172 -0
- data/lib/app_archetype/template/source.rb +39 -0
- data/lib/app_archetype/template/variable.rb +237 -0
- data/lib/app_archetype/template/variable_manager.rb +75 -0
- data/lib/app_archetype/template_manager.rb +113 -0
- data/lib/app_archetype/version.rb +6 -0
- data/lib/core_ext/string.rb +67 -0
- data/spec/app_archetype/cli/presenters_spec.rb +99 -0
- data/spec/app_archetype/cli/prompts_spec.rb +292 -0
- data/spec/app_archetype/cli_spec.rb +132 -0
- data/spec/app_archetype/generators_spec.rb +119 -0
- data/spec/app_archetype/logger_spec.rb +86 -0
- data/spec/app_archetype/renderer_spec.rb +291 -0
- data/spec/app_archetype/template/helpers_spec.rb +251 -0
- data/spec/app_archetype/template/manifest_spec.rb +245 -0
- data/spec/app_archetype/template/plan_spec.rb +191 -0
- data/spec/app_archetype/template/source_spec.rb +60 -0
- data/spec/app_archetype/template/variable_manager_spec.rb +103 -0
- data/spec/app_archetype/template/variable_spec.rb +245 -0
- data/spec/app_archetype/template_manager_spec.rb +221 -0
- data/spec/core_ext/string_spec.rb +143 -0
- data/spec/spec_helper.rb +29 -0
- metadata +370 -0
@@ -0,0 +1,191 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe AppArchetype::Template::Plan do
|
4
|
+
let(:template) { AppArchetype::Template::Source.new('path/to/template') }
|
5
|
+
let(:destination) { 'path/to/destination' }
|
6
|
+
let(:variables) do
|
7
|
+
OpenStruct.new(
|
8
|
+
foo: 'bar'
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
subject do
|
13
|
+
described_class.new(
|
14
|
+
template,
|
15
|
+
variables,
|
16
|
+
destination_path: destination
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#devise' do
|
21
|
+
let(:dest_exist) { true }
|
22
|
+
|
23
|
+
before do
|
24
|
+
allow(subject).to receive(:destination_exist?).and_return(dest_exist)
|
25
|
+
allow(template).to receive(:files).and_return(['path/to/file'])
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'creates file objects' do
|
29
|
+
subject.devise
|
30
|
+
expect(subject.files).to all be_a(AppArchetype::Template::OutputFile)
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'destination path does not exist' do
|
34
|
+
let(:dest_exist) { false }
|
35
|
+
|
36
|
+
it 'raises error' do
|
37
|
+
expect do
|
38
|
+
subject.devise
|
39
|
+
end.to raise_error('destination path does not exist')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#execute' do
|
45
|
+
let(:renderer) { double(AppArchetype::Renderer) }
|
46
|
+
|
47
|
+
before do
|
48
|
+
allow(renderer).to receive(:render)
|
49
|
+
allow(AppArchetype::Renderer)
|
50
|
+
.to receive(:new)
|
51
|
+
.and_return(renderer)
|
52
|
+
|
53
|
+
subject.execute
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'creates a renderer' do
|
57
|
+
expect(AppArchetype::Renderer)
|
58
|
+
.to have_received(:new).with(subject, false)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'renders plan' do
|
62
|
+
expect(renderer).to have_received(:render)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#destination_exist?' do
|
67
|
+
let(:dirname) { 'some-directory' }
|
68
|
+
let(:exist) { true }
|
69
|
+
|
70
|
+
before do
|
71
|
+
allow(File).to receive(:exist?).and_return(exist)
|
72
|
+
allow(File).to receive(:dirname).and_return(dirname)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'returns true' do
|
76
|
+
expect(subject.destination_exist?).to be true
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'when destination does not exist' do
|
80
|
+
let(:exist) { false }
|
81
|
+
|
82
|
+
it 'returns false' do
|
83
|
+
expect(subject.destination_exist?).to be false
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe '#render_dest_file_path' do
|
89
|
+
it 'creates a destination file path from source path' do
|
90
|
+
expect(
|
91
|
+
subject.render_dest_file_path('path/to/template/file')
|
92
|
+
).to eq 'path/to/destination/file'
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe '#render_path' do
|
97
|
+
it 'renders path with variables' do
|
98
|
+
expect(subject.render_path('{{foo}}')).to eq 'bar'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
RSpec.describe AppArchetype::Template::OutputFile do
|
104
|
+
let(:source_file) { 'path/to/source' }
|
105
|
+
let(:dest_file) { 'path/to/dest' }
|
106
|
+
|
107
|
+
subject { described_class.new(source_file, dest_file) }
|
108
|
+
|
109
|
+
describe '#source_directory?' do
|
110
|
+
before do
|
111
|
+
allow(File).to receive(:directory?)
|
112
|
+
subject.source_directory?
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'delegates source file directory check to File' do
|
116
|
+
expect(File).to have_received(:directory?).with(source_file)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe '#source_erb?' do
|
121
|
+
let(:ext) { '.erb' }
|
122
|
+
|
123
|
+
before do
|
124
|
+
allow(File).to receive(:extname).and_return(ext)
|
125
|
+
@result = subject.source_erb?
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'delegates source file template check to File' do
|
129
|
+
expect(File).to have_received(:extname).with(source_file)
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'returns true if file is erb' do
|
133
|
+
expect(@result).to be true
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'when not erb' do
|
137
|
+
let(:ext) { 'doc' }
|
138
|
+
|
139
|
+
it 'returns false' do
|
140
|
+
expect(@result).to be false
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe '#source_hbs?' do
|
146
|
+
let(:ext) { '.hbs' }
|
147
|
+
|
148
|
+
before do
|
149
|
+
allow(File).to receive(:extname).and_return(ext)
|
150
|
+
@result = subject.source_hbs?
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'delegates source file template check to File' do
|
154
|
+
expect(File).to have_received(:extname).with(source_file)
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'returns true if file is hbs' do
|
158
|
+
expect(@result).to be true
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'when not hbs' do
|
162
|
+
let(:ext) { 'doc' }
|
163
|
+
|
164
|
+
it 'returns false' do
|
165
|
+
expect(@result).to be false
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe '#source_file?' do
|
171
|
+
before do
|
172
|
+
allow(File).to receive(:file?)
|
173
|
+
subject.source_file?
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'delegates source file check to File' do
|
177
|
+
expect(File).to have_received(:file?).with(source_file)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
describe '#exist?' do
|
182
|
+
before do
|
183
|
+
allow(File).to receive(:exist?)
|
184
|
+
subject.exist?
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'delegates exist check to File' do
|
188
|
+
expect(File).to have_received(:exist?).with(dest_file)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe AppArchetype::Template::Source do
|
4
|
+
let(:path) { 'path/to/source' }
|
5
|
+
subject { described_class.new(path) }
|
6
|
+
|
7
|
+
describe '#load' do
|
8
|
+
let(:glob_files) { %w[file1 file2] }
|
9
|
+
let(:exist) { true }
|
10
|
+
|
11
|
+
before do
|
12
|
+
allow(Dir).to receive(:glob).and_return(glob_files)
|
13
|
+
allow(subject).to receive(:exist?).and_return(exist)
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when source exists' do
|
17
|
+
before do
|
18
|
+
subject.load
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'loads expected file paths into source_files' do
|
22
|
+
expect(subject.files).to eq glob_files
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'when source does not exist' do
|
27
|
+
let(:exist) { false }
|
28
|
+
|
29
|
+
it 'raises template source does not exist error' do
|
30
|
+
expect do
|
31
|
+
subject.load
|
32
|
+
end.to raise_error('template source does not exist')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#exist?' do
|
38
|
+
let(:path) { 'path/to/source' }
|
39
|
+
let(:exist) { true }
|
40
|
+
|
41
|
+
before { allow(File).to receive(:exist?).and_return(exist) }
|
42
|
+
|
43
|
+
it 'checks if file exists' do
|
44
|
+
expect(File).to receive(:exist?).with(path)
|
45
|
+
subject.exist?
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'returns true' do
|
49
|
+
expect(subject.exist?).to be true
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'when file does not exist' do
|
53
|
+
let(:exist) { false }
|
54
|
+
|
55
|
+
it 'returns false' do
|
56
|
+
expect(subject.exist?).to be false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe AppArchetype::Template::VariableManager do
|
4
|
+
let(:var_name) { 'example_string' }
|
5
|
+
let(:var_type) { 'string' }
|
6
|
+
let(:var_desc) { 'This is an example string variable' }
|
7
|
+
let(:var_default) { 'default value' }
|
8
|
+
let(:var_value) { 'set value' }
|
9
|
+
|
10
|
+
let(:variables_spec) do
|
11
|
+
{
|
12
|
+
var_name => {
|
13
|
+
'type' => var_type,
|
14
|
+
'description' => var_desc,
|
15
|
+
'default' => var_default
|
16
|
+
},
|
17
|
+
"#{var_name}_with_value" => {
|
18
|
+
'type' => var_type,
|
19
|
+
'description' => var_desc,
|
20
|
+
'default' => var_default,
|
21
|
+
'value' => var_value
|
22
|
+
},
|
23
|
+
'example_random_string' => {
|
24
|
+
'type' => 'string',
|
25
|
+
'description' => 'Example call to helper to generate 25 char string',
|
26
|
+
'value' => '#random_string,25'
|
27
|
+
}
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
subject { described_class.new(variables_spec) }
|
32
|
+
|
33
|
+
describe '#all' do
|
34
|
+
it 'returns array of template variables' do
|
35
|
+
expect(subject.all).to all(be_a AppArchetype::Template::Variable)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'has expected variables' do
|
39
|
+
expect(subject.all.map(&:name))
|
40
|
+
.to eq(
|
41
|
+
%w[
|
42
|
+
example_string
|
43
|
+
example_string_with_value
|
44
|
+
example_random_string
|
45
|
+
]
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#get' do
|
51
|
+
before { @var = subject.get(var_name) }
|
52
|
+
|
53
|
+
it 'returns variable' do
|
54
|
+
expect(@var.name).to eq var_name
|
55
|
+
expect(@var.type).to eq var_type
|
56
|
+
expect(@var.description).to eq var_desc
|
57
|
+
expect(@var.default).to eq var_default
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#to_h' do
|
62
|
+
let(:instance_helpers) { double }
|
63
|
+
let(:random_result) { 'random-string-25-chars-long' }
|
64
|
+
|
65
|
+
before do
|
66
|
+
allow_any_instance_of(AppArchetype::Template::Variable)
|
67
|
+
.to receive(:helpers)
|
68
|
+
.and_return(instance_helpers)
|
69
|
+
|
70
|
+
allow(instance_helpers)
|
71
|
+
.to receive(:random_string)
|
72
|
+
.and_return(random_result)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'returns hash representation of variables (key => value)' do
|
76
|
+
expect(subject.to_h).to eq(
|
77
|
+
var_name => var_default,
|
78
|
+
"#{var_name}_with_value" => var_value,
|
79
|
+
'example_random_string' => random_result
|
80
|
+
)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#method_missing' do
|
85
|
+
context 'when variable is defined without value' do
|
86
|
+
it 'returns default variable value' do
|
87
|
+
expect(subject.example_string).to eq var_default
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'when variable is defined with a value' do
|
92
|
+
it 'returns set variable value' do
|
93
|
+
expect(subject.example_string_with_value).to eq var_value
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'when variable is not defined' do
|
98
|
+
it 'raises NoMethodError' do
|
99
|
+
expect { subject.foo }.to raise_error(NoMethodError)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,245 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe AppArchetype::Template::Variable do
|
4
|
+
let(:description) { 'explanation of variable' }
|
5
|
+
let(:type) { 'string' }
|
6
|
+
let(:default) { 'default-value' }
|
7
|
+
let(:value) { nil }
|
8
|
+
|
9
|
+
let(:name) { 'var' }
|
10
|
+
let(:spec) do
|
11
|
+
{
|
12
|
+
'description' => description,
|
13
|
+
'type' => type,
|
14
|
+
'default' => default,
|
15
|
+
'value' => value
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
subject { described_class.new(name, spec) }
|
20
|
+
|
21
|
+
describe '::STRING_VALIDATOR' do
|
22
|
+
it 'returns true when given string input' do
|
23
|
+
expect(
|
24
|
+
described_class::STRING_VALIDATOR.call('this is string')
|
25
|
+
).to be true
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'returns false when given non string input' do
|
29
|
+
expect(
|
30
|
+
described_class::STRING_VALIDATOR.call(1)
|
31
|
+
).to be false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '::BOOLEAN_VALIDATOR' do
|
36
|
+
it 'returns true when given boolean input' do
|
37
|
+
expect(
|
38
|
+
described_class::BOOLEAN_VALIDATOR.call(true)
|
39
|
+
).to be true
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'returns true when given string representation of boolean input' do
|
43
|
+
expect(
|
44
|
+
described_class::BOOLEAN_VALIDATOR.call('true')
|
45
|
+
).to be true
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'returns false when given non boolean input' do
|
49
|
+
expect(
|
50
|
+
described_class::BOOLEAN_VALIDATOR.call('not bool')
|
51
|
+
).to be false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '::INTEGER_VALIDATOR' do
|
56
|
+
it 'returns true when given integer input' do
|
57
|
+
expect(
|
58
|
+
described_class::INTEGER_VALIDATOR.call(1)
|
59
|
+
).to be true
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'returns true when given string representation of integer' do
|
63
|
+
expect(
|
64
|
+
described_class::INTEGER_VALIDATOR.call('1')
|
65
|
+
).to be true
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'returns false when given non integer input' do
|
69
|
+
expect(
|
70
|
+
described_class::INTEGER_VALIDATOR.call('one')
|
71
|
+
).to be false
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#set!' do
|
76
|
+
context 'setting with a valid value' do
|
77
|
+
before { subject.set!('a value') }
|
78
|
+
|
79
|
+
it 'sets the value of the variable' do
|
80
|
+
expect(subject.value).to eq 'a value'
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'setting with an invalid value' do
|
85
|
+
let(:type) { 'integer' }
|
86
|
+
|
87
|
+
it 'raises invalid value runtime error' do
|
88
|
+
expect do
|
89
|
+
subject.set!('a string')
|
90
|
+
end.to raise_error('invalid value')
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe '#default' do
|
96
|
+
context 'when default is in specification' do
|
97
|
+
it 'returns specified default value' do
|
98
|
+
expect(subject.default).to eq default
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'when default is not specified' do
|
103
|
+
let(:spec) do
|
104
|
+
{
|
105
|
+
'type' => 'integer'
|
106
|
+
}
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'returns archetype default' do
|
110
|
+
expect(subject.default).to eq 0
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe '#description' do
|
116
|
+
context 'when description is in specification' do
|
117
|
+
it 'returns specified description value' do
|
118
|
+
expect(subject.description).to eq description
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'when default is not specified' do
|
123
|
+
let(:spec) do
|
124
|
+
{
|
125
|
+
'type' => 'integer'
|
126
|
+
}
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'returns empty string' do
|
130
|
+
expect(subject.description).to eq ''
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe '#type' do
|
136
|
+
context 'when type is in specification' do
|
137
|
+
it 'returns specified type value' do
|
138
|
+
expect(subject.type).to eq type
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context 'when default is not specified' do
|
143
|
+
let(:spec) do
|
144
|
+
{}
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'returns string by default' do
|
148
|
+
expect(subject.type).to eq 'string'
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe '#value' do
|
154
|
+
context 'when value is not specified' do
|
155
|
+
it 'returns default value' do
|
156
|
+
expect(subject.value).to eq default
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
context 'when value is a function call' do
|
161
|
+
let(:helper) { double }
|
162
|
+
let(:value) { '#upcase,foo' }
|
163
|
+
|
164
|
+
it 'returns result of function call' do
|
165
|
+
expect(subject.value).to eq 'FOO'
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
context 'when value has been set' do
|
170
|
+
let(:value) { 'some-value' }
|
171
|
+
|
172
|
+
it 'returns variable value' do
|
173
|
+
expect(subject.value).to eq value
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe '#value?' do
|
179
|
+
context 'when value is not set' do
|
180
|
+
let(:value) { nil }
|
181
|
+
|
182
|
+
it 'returns false' do
|
183
|
+
expect(subject.value?).to be false
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
let(:value) { 'some-value' }
|
188
|
+
|
189
|
+
context 'when value is set' do
|
190
|
+
it 'returns true' do
|
191
|
+
expect(subject.value?).to be true
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
describe '#validator' do
|
197
|
+
context 'when variable type is specified' do
|
198
|
+
let(:type) { 'integer' }
|
199
|
+
|
200
|
+
it 'returns validator for specified type' do
|
201
|
+
expect(subject.validator)
|
202
|
+
.to eq AppArchetype::Template::Variable::INTEGER_VALIDATOR
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
context 'when variable type is not specified' do
|
207
|
+
let(:type) { nil }
|
208
|
+
|
209
|
+
it 'returns string validator' do
|
210
|
+
expect(subject.validator)
|
211
|
+
.to eq AppArchetype::Template::Variable::STRING_VALIDATOR
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
describe '#valid?' do
|
217
|
+
context 'when validator returns true' do
|
218
|
+
let(:result) { true }
|
219
|
+
let(:validator) { double(call: result) }
|
220
|
+
|
221
|
+
before do
|
222
|
+
allow(subject).to receive(:validator)
|
223
|
+
.and_return(validator)
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'returns true' do
|
227
|
+
expect(subject.valid?('input')).to be true
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
context 'when validator returns false' do
|
232
|
+
let(:result) { false }
|
233
|
+
let(:validator) { double(call: result) }
|
234
|
+
|
235
|
+
before do
|
236
|
+
allow(subject).to receive(:validator)
|
237
|
+
.and_return(validator)
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'returns false' do
|
241
|
+
expect(subject.valid?('input')).to be false
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|