howitzer 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +3 -1
  4. data/.ruby-gemset +1 -0
  5. data/.travis.yml +4 -1
  6. data/.yardopts +5 -0
  7. data/CHANGELOG.md +23 -1
  8. data/CONTRIBUTING.md +14 -0
  9. data/GETTING_STARTED.md +283 -183
  10. data/Gemfile +3 -2
  11. data/LICENSE +1 -1
  12. data/README.md +93 -39
  13. data/Rakefile +4 -0
  14. data/bin/howitzer +34 -5
  15. data/features/cli_help.feature +3 -2
  16. data/features/cli_new.feature +1 -1
  17. data/features/cli_unknown.feature +1 -1
  18. data/features/cli_update.feature +84 -0
  19. data/features/step_definitions/common_steps.rb +9 -1
  20. data/generators/base_generator.rb +30 -15
  21. data/generators/config/config_generator.rb +7 -7
  22. data/generators/config/templates/custom.yml +1 -0
  23. data/generators/config/templates/default.yml +35 -5
  24. data/generators/cucumber/templates/env.rb +2 -2
  25. data/generators/cucumber/templates/transformers.rb +3 -1
  26. data/generators/root/templates/Gemfile +5 -3
  27. data/generators/root/templates/Rakefile +2 -0
  28. data/generators/rspec/templates/example_spec.rb +3 -3
  29. data/generators/rspec/templates/spec_helper.rb +6 -7
  30. data/howitzer.gemspec +15 -15
  31. data/lib/howitzer/capybara/settings.rb +125 -49
  32. data/lib/howitzer/helpers.rb +161 -94
  33. data/lib/howitzer/mailgun/client.rb +1 -1
  34. data/lib/howitzer/tasks/framework.rake +3 -0
  35. data/lib/howitzer/utils.rb +1 -1
  36. data/lib/howitzer/utils/locator_store.rb +1 -1
  37. data/lib/howitzer/utils/log.rb +1 -1
  38. data/lib/howitzer/utils/page_validator.rb +1 -1
  39. data/lib/howitzer/version.rb +1 -1
  40. data/lib/howitzer/web_page.rb +11 -11
  41. data/spec/spec_helper.rb +25 -22
  42. data/spec/support/generator_helper.rb +8 -1
  43. data/spec/unit/generators/base_generator_spec.rb +242 -0
  44. data/spec/unit/generators/config_generator_spec.rb +34 -0
  45. data/spec/unit/generators/cucumber_generator_spec.rb +45 -0
  46. data/spec/unit/generators/emails_generator_spec.rb +31 -0
  47. data/spec/unit/generators/pages_generator_spec.rb +33 -0
  48. data/spec/unit/generators/root_generator_spec.rb +35 -0
  49. data/spec/unit/generators/rspec_generator_spec.rb +36 -0
  50. data/spec/unit/generators/tasks_generator_spec.rb +31 -0
  51. data/spec/unit/lib/capybara/dsl_ex_spec.rb +11 -11
  52. data/spec/unit/lib/capybara/settings_spec.rb +336 -58
  53. data/spec/unit/lib/email_spec.rb +17 -17
  54. data/spec/unit/lib/helpers_spec.rb +699 -315
  55. data/spec/unit/lib/mailgun/client_spec.rb +9 -9
  56. data/spec/unit/lib/mailgun/connector_spec.rb +20 -20
  57. data/spec/unit/lib/mailgun/response_spec.rb +9 -9
  58. data/spec/unit/lib/settings_spec.rb +6 -6
  59. data/spec/unit/lib/utils/data_generator/data_storage_spec.rb +31 -31
  60. data/spec/unit/lib/utils/data_generator/gen_spec.rb +20 -20
  61. data/spec/unit/lib/utils/locator_store_spec.rb +39 -39
  62. data/spec/unit/lib/utils/log_spec.rb +42 -42
  63. data/spec/unit/lib/utils/page_validator_spec.rb +69 -70
  64. data/spec/unit/lib/web_page_spec.rb +91 -69
  65. data/spec/unit/version_spec.rb +3 -3
  66. metadata +100 -78
  67. data/spec/unit/generators/generators_spec.rb +0 -175
@@ -1,3 +1,6 @@
1
+ require 'fileutils'
2
+ require_relative '../../generators/base_generator'
3
+
1
4
  module GeneratorHelper
2
5
  def file_tree_info(root)
3
6
  Dir["#{root}/**/*"].sort_by{|name| name.sub(root, '') }.map do |name|
@@ -10,4 +13,8 @@ module GeneratorHelper
10
13
  def template_file_size(root_directory, file)
11
14
  File.size(File.join(generators_path, root_directory, 'templates', file))
12
15
  end
13
- end
16
+ end
17
+
18
+ Howitzer::BaseGenerator.logger = StringIO.new
19
+ Howitzer::BaseGenerator.destination = Dir.mktmpdir
20
+ Dir[File.join(generators_path, '**', '*_generator.rb')].each{ |f| require f }
@@ -0,0 +1,242 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Howitzer::BaseGenerator do
4
+ let(:output) { StringIO.new }
5
+ let(:destination) { Dir.mktmpdir }
6
+
7
+ describe '.logger' do
8
+ subject { described_class.logger }
9
+ before { described_class.instance_variable_set('@logger', output) }
10
+ it { is_expected.to eq(output) }
11
+ end
12
+
13
+ describe '.logger=' do
14
+ subject { described_class.instance_variable_get('@logger') }
15
+ before { described_class.logger = output }
16
+ it { is_expected.to eq(output) }
17
+ end
18
+
19
+ describe '.destination' do
20
+ subject { described_class.destination }
21
+ before { described_class.instance_variable_set('@destination', destination) }
22
+ it { is_expected.to eq(destination) }
23
+ end
24
+
25
+ describe '.destination=' do
26
+ subject { described_class.instance_variable_get('@destination') }
27
+ before { described_class.destination = destination }
28
+ it { is_expected.to eq(destination) }
29
+ end
30
+
31
+ describe 'constructor' do
32
+ let(:list1) { double(:list1) }
33
+ let(:list2) { double(:list2) }
34
+ subject { described_class.new }
35
+ before do
36
+ expect_any_instance_of(described_class).to receive(:print_banner).with(no_args).once
37
+ allow_any_instance_of(described_class).to receive(:manifest) do
38
+ {
39
+ files: list1,
40
+ templates: list2,
41
+ unknown: nil
42
+ }
43
+ end
44
+ end
45
+ it do
46
+ expect_any_instance_of(described_class).to receive(:copy_files).with(list1).once
47
+ expect_any_instance_of(described_class).to receive(:copy_templates).with(list2).once
48
+ subject
49
+ end
50
+ end
51
+
52
+ describe '#manifest' do
53
+ subject { described_class.new.manifest }
54
+ before { allow_any_instance_of(described_class).to receive(:initialize) { nil } }
55
+ it { is_expected.to be_nil }
56
+ end
57
+
58
+ describe '#banner' do
59
+ subject { described_class.new.send(:banner) }
60
+ before { allow_any_instance_of(described_class).to receive(:initialize) { nil } }
61
+ it { is_expected.to be_nil }
62
+ end
63
+
64
+ describe '#logger' do
65
+ subject { described_class.new.send(:logger) }
66
+ before { allow_any_instance_of(described_class).to receive(:initialize) { nil } }
67
+ context 'when not specified' do
68
+ before { described_class.instance_variable_set('@logger', nil) }
69
+ it { is_expected.to eq($stdout) }
70
+ end
71
+ context 'when custom' do
72
+ let(:output) { StringIO.new }
73
+ before { described_class.instance_variable_set('@logger', output) }
74
+ it { is_expected.to eq(output) }
75
+ end
76
+ end
77
+
78
+ describe '#destination' do
79
+ subject { described_class.new.send(:destination) }
80
+ before do
81
+ allow_any_instance_of(described_class).to receive(:initialize) { nil }
82
+ allow(described_class).to receive(:destination) { '/' }
83
+ end
84
+ it { is_expected.to eq('/') }
85
+ end
86
+
87
+ describe '#copy_files' do
88
+ let(:list) { [ {source: 'example.txt'} ] }
89
+ let(:source_path) { '/example_path/example.txt' }
90
+ let(:generator) { described_class.new }
91
+ subject { generator.send(:copy_files, list) }
92
+ before do
93
+ allow_any_instance_of(described_class).to receive(:initialize) { nil }
94
+ allow(generator).to receive(:source_path).with(list.first[:source]) { source_path }
95
+ end
96
+ after { subject }
97
+ context 'when source_file exists' do
98
+ before { allow(File).to receive(:exists?).with(source_path) { true } }
99
+ it { expect(generator).to receive(:copy_with_path).with(list.first).once }
100
+ end
101
+ context 'when source_file missing' do
102
+ before { allow(File).to receive(:exists?).with(source_path) { false } }
103
+ it { expect(generator).to receive(:puts_error).with("File '/example_path/example.txt' was not found.").once }
104
+ end
105
+ end
106
+
107
+ describe '#copy_templates' do
108
+ subject { described_class.new.send(:copy_templates, nil) }
109
+ before { allow_any_instance_of(described_class).to receive(:initialize) { nil } }
110
+ it { is_expected.to be_nil }
111
+ end
112
+
113
+ describe '#print_banner' do
114
+ let(:generator) { described_class.new }
115
+ subject { generator.send(:print_banner) }
116
+ before do
117
+ allow_any_instance_of(described_class).to receive(:initialize) { nil }
118
+ allow(generator).to receive(:banner) { banner }
119
+ end
120
+ after { subject }
121
+ context 'when banner present' do
122
+ let(:banner) { 'banner' }
123
+ it { expect(described_class.logger).to receive(:puts).with(banner).once }
124
+ end
125
+ context 'when banner blank' do
126
+ let(:banner) { '' }
127
+ it { expect(described_class.logger).not_to receive(:puts) }
128
+ end
129
+ end
130
+
131
+ describe '#print_info' do
132
+ subject { described_class.new.send(:print_info, 'data') }
133
+ before { allow_any_instance_of(described_class).to receive(:initialize) { nil } }
134
+ after { subject }
135
+ it { expect(described_class.logger).to receive(:print).with(' data')}
136
+ end
137
+
138
+ describe '#puts_info' do
139
+ subject { described_class.new.send(:puts_info, 'data') }
140
+ before { allow_any_instance_of(described_class).to receive(:initialize) { nil } }
141
+ after { subject }
142
+ it { expect(described_class.logger).to receive(:puts).with(' data')}
143
+ end
144
+
145
+ describe '#puts_error' do
146
+ subject { described_class.new.send(:puts_error, 'data') }
147
+ before { allow_any_instance_of(described_class).to receive(:initialize) { nil } }
148
+ after { subject }
149
+ it { expect(described_class.logger).to receive(:puts).with(' ERROR: data')}
150
+ end
151
+
152
+ describe '#source_path' do
153
+ subject { described_class.new.send(:source_path, 'example.txt') }
154
+ before do
155
+ allow_any_instance_of(described_class).to receive(:initialize) { nil }
156
+ allow(File).to receive(:dirname) { '/' }
157
+ end
158
+ it { is_expected.to eq('/base/templates/example.txt') }
159
+ end
160
+
161
+ describe '#dest_path' do
162
+ subject { described_class.new.send(:dest_path, 'example.txt') }
163
+ before { allow_any_instance_of(described_class).to receive(:initialize) { nil } }
164
+ it { is_expected.to include('/example.txt') }
165
+ end
166
+
167
+ describe '#copy_with_path' do
168
+ let(:generator) { described_class.new }
169
+ let(:data) { {source: 's.txt', destination: 'd.txt'} }
170
+ let(:src) { '/path/to/s.txt' }
171
+ let(:dst) { '/path/to/d.txt' }
172
+ subject { generator.send(:copy_with_path, data) }
173
+ before do
174
+ allow_any_instance_of(described_class).to receive(:initialize) { nil }
175
+ allow(generator).to receive(:source_path).with('s.txt') { src }
176
+ allow(generator).to receive(:dest_path).with('d.txt') { dst }
177
+ allow(FileUtils).to receive(:mkdir_p).with('/path/to') { true }
178
+ end
179
+ after { subject }
180
+ context 'when destination file present' do
181
+ before { allow(File).to receive(:exists?).with(dst) { true } }
182
+ context 'when identical with source file' do
183
+ before { allow(FileUtils).to receive(:identical?).with(src, dst) { true } }
184
+ it { expect(generator).to receive(:puts_info).with("Identical 'd.txt' file").once }
185
+ end
186
+ context 'when not identical with source file' do
187
+ before do
188
+ allow(FileUtils).to receive(:identical?).with(src, dst) { false }
189
+ expect(generator).to receive(:puts_info).with("Conflict with 'd.txt' file")
190
+ expect(generator).to receive(:print_info).with(" Overwrite 'd.txt' file? [Yn]:")
191
+ end
192
+ context 'when user typed Y' do
193
+ before { allow(generator).to receive(:gets) { 'Y' } }
194
+ it do
195
+ expect(FileUtils).to receive(:cp).with(src, dst) {nil}.once
196
+ expect(generator).to receive(:puts_info).with(" Forced 'd.txt' file")
197
+ end
198
+ end
199
+ context 'when user typed y' do
200
+ before { allow(generator).to receive(:gets) { 'y' } }
201
+ it do
202
+ expect(FileUtils).to receive(:cp).with(src, dst) {nil}.once
203
+ expect(generator).to receive(:puts_info).with(" Forced 'd.txt' file")
204
+ end
205
+ end
206
+ context 'when user typed N' do
207
+ before { allow(generator).to receive(:gets) { 'N' } }
208
+ it do
209
+ expect(generator).to receive(:puts_info).with(" Skipped 'd.txt' file")
210
+ expect(FileUtils).not_to receive(:cp)
211
+ end
212
+ end
213
+ context 'when user typed n' do
214
+ before { allow(generator).to receive(:gets) { 'n' } }
215
+ it do
216
+ expect(generator).to receive(:puts_info).with(" Skipped 'd.txt' file")
217
+ expect(FileUtils).not_to receive(:cp)
218
+ end
219
+ end
220
+ context 'when user typed hello' do
221
+ before { allow(generator).to receive(:gets) { 'hello' } }
222
+ it do
223
+ expect(generator).not_to receive(:puts_info)
224
+ expect(FileUtils).not_to receive(:cp)
225
+ end
226
+ end
227
+ end
228
+ end
229
+ context 'when destination file missing' do
230
+ before { allow(File).to receive(:exists?).with(dst) { false } }
231
+ it do
232
+ expect(generator).to receive(:puts_info).with("Added 'd.txt' file")
233
+ expect(FileUtils).to receive(:cp).with(src, dst).once
234
+ end
235
+ end
236
+ context 'when exception happened' do
237
+ before { allow(FileUtils).to receive(:mkdir_p).and_raise(StandardError.new('Some error')) }
238
+ it { expect(generator).to receive(:puts_error).with("Impossible to create 'd.txt' file. Reason: Some error")}
239
+ end
240
+ end
241
+
242
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Generators' do
4
+ let(:destination) { Howitzer::BaseGenerator.destination }
5
+ let(:output) { StringIO.new }
6
+ subject { file_tree_info(destination) }
7
+ before do
8
+ Howitzer::BaseGenerator.logger = output
9
+ generator_name.new
10
+ end
11
+ after { FileUtils.rm_r(destination) }
12
+
13
+ describe 'ConfigGenerator' do
14
+ let(:generator_name) { Howitzer::ConfigGenerator }
15
+ let(:expected_result) do
16
+ [
17
+ {:name=> '/config', :is_directory=>true},
18
+ {:name=> '/config/custom.yml', :is_directory=>false, :size=>template_file_size('config', 'custom.yml')},
19
+ {:name=> '/config/default.yml', :is_directory=>false, :size=>template_file_size('config', 'default.yml')}
20
+ ]
21
+ end
22
+
23
+ it { is_expected.to eql(expected_result) }
24
+ describe 'output' do
25
+ let(:expected_output) do
26
+ " * Config files generation ...
27
+ Added 'config/custom.yml' file
28
+ Added 'config/default.yml' file\n"
29
+ end
30
+ subject { output.string }
31
+ it { is_expected.to eql(expected_output) }
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Generators' do
4
+ let(:destination) { Howitzer::BaseGenerator.destination }
5
+ let(:output) { StringIO.new }
6
+ subject { file_tree_info(destination) }
7
+ before do
8
+ Howitzer::BaseGenerator.logger = output
9
+ generator_name.new
10
+ end
11
+ after { FileUtils.rm_r(destination) }
12
+
13
+ describe 'CucumberGenerator' do
14
+ let(:generator_name) { Howitzer::CucumberGenerator }
15
+ let(:expected_result) do
16
+ [
17
+ {:name=> '/config', :is_directory=>true},
18
+ {:name=> '/config/cucumber.yml', :is_directory=>false, :size=>template_file_size('cucumber', 'cucumber.yml')},
19
+ {:name=> '/features', :is_directory=>true},
20
+ {:name=> '/features/example.feature', :is_directory=>false, :size=>template_file_size('cucumber', 'example.feature')},
21
+ {:name=> '/features/step_definitions', :is_directory=>true},
22
+ {:name=> '/features/step_definitions/common_steps.rb', :is_directory=>false, :size=>template_file_size('cucumber', 'common_steps.rb')},
23
+ {:name=> '/features/support', :is_directory=>true},
24
+ {:name=> '/features/support/env.rb', :is_directory=>false, :size=>template_file_size('cucumber', 'env.rb')},
25
+ {:name=> '/features/support/transformers.rb', :is_directory=>false, :size=>template_file_size('cucumber', 'transformers.rb')},
26
+ {:name=> '/tasks', :is_directory=>true},
27
+ {:name=> '/tasks/cucumber.rake', :is_directory=>false, :size=>template_file_size('cucumber', 'cucumber.rake')}
28
+ ]
29
+ end
30
+ it { is_expected.to eql(expected_result) }
31
+ describe 'output' do
32
+ let(:expected_output) do
33
+ " * Cucumber integration to the framework ...
34
+ Added 'features/step_definitions/common_steps.rb' file
35
+ Added 'features/support/env.rb' file
36
+ Added 'features/support/transformers.rb' file
37
+ Added 'features/example.feature' file
38
+ Added 'tasks/cucumber.rake' file
39
+ Added 'config/cucumber.yml' file\n"
40
+ end
41
+ subject { output.string }
42
+ it { is_expected.to eql(expected_output) }
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Generators' do
4
+ let(:destination) { Howitzer::BaseGenerator.destination }
5
+ let(:output) { StringIO.new }
6
+ subject { file_tree_info(destination) }
7
+ before do
8
+ Howitzer::BaseGenerator.logger = output
9
+ generator_name.new
10
+ end
11
+ after { FileUtils.rm_r(destination) }
12
+
13
+ describe 'EmailsGenerator' do
14
+ let(:generator_name) { Howitzer::EmailsGenerator }
15
+ let(:expected_result) do
16
+ [
17
+ {:name=> '/emails', :is_directory=>true},
18
+ {:name=> '/emails/example_email.rb', :is_directory=>false, :size=>template_file_size('emails', 'example_email.rb')}
19
+ ]
20
+ end
21
+ it { is_expected.to eql(expected_result) }
22
+ describe 'output' do
23
+ let(:expected_output) do
24
+ " * Email example generation ...
25
+ Added '/emails/example_email.rb' file\n"
26
+ end
27
+ subject { output.string }
28
+ it { is_expected.to eql(expected_output) }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Generators' do
4
+ let(:destination) { Howitzer::BaseGenerator.destination }
5
+ let(:output) { StringIO.new }
6
+ subject { file_tree_info(destination) }
7
+ before do
8
+ Howitzer::BaseGenerator.logger = output
9
+ generator_name.new
10
+ end
11
+ after { FileUtils.rm_r(destination) }
12
+
13
+ describe 'PagesGenerator' do
14
+ let(:generator_name) { Howitzer::PagesGenerator }
15
+ let(:expected_result) do
16
+ [
17
+ {:name=> '/pages', :is_directory=>true},
18
+ {:name=> '/pages/example_menu.rb', :is_directory=>false, :size=>template_file_size('pages', 'example_menu.rb')},
19
+ {:name=> '/pages/example_page.rb', :is_directory=>false, :size=>template_file_size('pages', 'example_page.rb')}
20
+ ]
21
+ end
22
+ it { is_expected.to eql(expected_result) }
23
+ describe 'output' do
24
+ let(:expected_output) do
25
+ " * PageOriented pattern structure generation ...
26
+ Added 'pages/example_page.rb' file
27
+ Added 'pages/example_menu.rb' file\n"
28
+ end
29
+ subject { output.string }
30
+ it { is_expected.to eql(expected_output) }
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Generators' do
4
+ let(:destination) { Howitzer::BaseGenerator.destination }
5
+ let(:output) { StringIO.new }
6
+ subject { file_tree_info(destination) }
7
+ before do
8
+ Howitzer::BaseGenerator.logger = output
9
+ generator_name.new
10
+ end
11
+ after { FileUtils.rm_r(destination) }
12
+
13
+ describe 'RootGenerator' do
14
+ let(:generator_name) { Howitzer::RootGenerator }
15
+ let(:expected_result) do
16
+ [
17
+ {:name=> '/Gemfile', :is_directory=>false, :size=>template_file_size('root', 'Gemfile')},
18
+ {:name=> '/Rakefile', :is_directory=>false, :size=>template_file_size('root', 'Rakefile')},
19
+ {:name=> '/boot.rb', :is_directory=>false, :size=>template_file_size('root', 'boot.rb')}
20
+ ]
21
+ end
22
+ it { is_expected.to eql(expected_result) }
23
+ describe 'output' do
24
+ let(:expected_output) do
25
+ " * Root files generation ...
26
+ Added '.gitignore' file
27
+ Added 'Gemfile' file
28
+ Added 'Rakefile' file
29
+ Added 'boot.rb' file\n"
30
+ end
31
+ subject { output.string }
32
+ it { is_expected.to eql(expected_output) }
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Generators' do
4
+ let(:destination) { Howitzer::BaseGenerator.destination }
5
+ let(:output) { StringIO.new }
6
+ subject { file_tree_info(destination) }
7
+ before do
8
+ Howitzer::BaseGenerator.logger = output
9
+ generator_name.new
10
+ end
11
+ after { FileUtils.rm_r(destination) }
12
+
13
+ describe 'RSpecGenerator' do
14
+ let(:generator_name) { Howitzer::RspecGenerator }
15
+ let(:expected_result) do
16
+ [
17
+ {:name=> '/spec', :is_directory=>true},
18
+ {:name=> '/spec/example_spec.rb', :is_directory=>false, :size=>template_file_size('rspec', 'example_spec.rb')},
19
+ {:name=> '/spec/spec_helper.rb', :is_directory=>false, :size=>template_file_size('rspec', 'spec_helper.rb')},
20
+ {:name=> '/tasks', :is_directory=>true},
21
+ {:name=> '/tasks/rspec.rake', :is_directory=>false, :size=>template_file_size('rspec', 'rspec.rake')}
22
+ ]
23
+ end
24
+ it { is_expected.to eql(expected_result) }
25
+ describe 'output' do
26
+ let(:expected_output) do
27
+ " * RSpec integration to the framework ...
28
+ Added 'spec/spec_helper.rb' file
29
+ Added 'spec/example_spec.rb' file
30
+ Added 'tasks/rspec.rake' file\n"
31
+ end
32
+ subject { output.string }
33
+ it { is_expected.to eql(expected_output) }
34
+ end
35
+ end
36
+ end