lucid 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/HISTORY.md +13 -0
  3. data/bin/lucid +1 -7
  4. data/lib/lucid/ast/doc_string.rb +1 -1
  5. data/lib/lucid/ast/step_invocation.rb +2 -2
  6. data/lib/lucid/cli/app.rb +6 -2
  7. data/lib/lucid/cli/configuration.rb +18 -5
  8. data/lib/lucid/cli/options.rb +56 -53
  9. data/lib/lucid/core_ext/instance_exec.rb +1 -2
  10. data/lib/lucid/core_ext/proc.rb +2 -2
  11. data/lib/lucid/errors.rb +3 -3
  12. data/lib/lucid/formatter/ansicolor.rb +20 -21
  13. data/lib/lucid/formatter/console.rb +1 -1
  14. data/lib/lucid/formatter/progress.rb +1 -1
  15. data/lib/lucid/generators/project.rb +1 -7
  16. data/lib/lucid/generators/project/browser-fluent.rb +0 -1
  17. data/lib/lucid/generators/project/events-fluent.rb +1 -4
  18. data/lib/lucid/interface_rb/matcher.rb +7 -7
  19. data/lib/lucid/interface_rb/rb_lucid.rb +2 -0
  20. data/lib/lucid/interface_rb/rb_step_definition.rb +5 -6
  21. data/lib/lucid/interface_rb/rb_world.rb +2 -3
  22. data/lib/lucid/platform.rb +3 -3
  23. data/lib/lucid/runtime/facade.rb +9 -11
  24. data/lib/lucid/runtime/orchestrator.rb +2 -3
  25. data/lib/lucid/runtime/results.rb +0 -2
  26. data/lib/lucid/spec_file.rb +1 -3
  27. data/spec/lucid/ansicolor_spec.rb +31 -0
  28. data/spec/lucid/app_spec.rb +73 -4
  29. data/spec/lucid/ast/background_spec.rb +128 -0
  30. data/spec/lucid/ast/doc_string_spec.rb +36 -0
  31. data/spec/lucid/ast/feature_spec.rb +66 -0
  32. data/spec/lucid/ast/outline_table_spec.rb +21 -0
  33. data/spec/lucid/ast/scenario_outline_spec.rb +81 -0
  34. data/spec/lucid/ast/specs_spec.rb +48 -0
  35. data/spec/lucid/ast/step_invocation_spec.rb +45 -0
  36. data/spec/lucid/ast/step_spec.rb +72 -0
  37. data/spec/lucid/ast/table_spec.rb +265 -0
  38. data/spec/lucid/ast/tdl_factory.rb +78 -0
  39. data/spec/lucid/ast/tdl_walker_spec.rb +21 -0
  40. data/spec/lucid/configuration_spec.rb +163 -8
  41. data/spec/lucid/duration_spec.rb +22 -0
  42. data/spec/lucid/facade_spec.rb +31 -0
  43. data/spec/lucid/matcher_spec.rb +127 -0
  44. data/spec/lucid/options_spec.rb +223 -3
  45. data/spec/lucid/orchestrator_spec.rb +117 -0
  46. data/spec/lucid/pending_spec.rb +45 -0
  47. data/spec/lucid/progress_spec.rb +34 -0
  48. data/spec/lucid/rb_step_definition_spec.rb +127 -0
  49. data/spec/lucid/rb_transform_spec.rb +24 -0
  50. data/spec/lucid/regexp_argument_matcher_spec.rb +19 -0
  51. data/spec/lucid/results_spec.rb +81 -0
  52. data/spec/lucid/runtime_spec.rb +1 -1
  53. data/spec/lucid/step_match_spec.rb +55 -0
  54. data/spec/spec_helper.rb +11 -5
  55. metadata +51 -7
  56. data/.ruby-gemset +0 -1
  57. data/.ruby-version +0 -1
  58. data/lib/lucid/generators/project/lucid-fluent.yml +0 -6
@@ -0,0 +1,22 @@
1
+ require_relative '../spec_helper'
2
+
3
+ module Lucid
4
+ module Formatter
5
+ describe Duration do
6
+ include Duration
7
+
8
+ it 'should format ms' do
9
+ format_duration(0.002103).should == '0m0.002s'
10
+ end
11
+
12
+ it 'should format m' do
13
+ format_duration(61.002503).should == '1m1.003s'
14
+ end
15
+
16
+ it 'should format h' do
17
+ format_duration(3661.002503).should == '61m1.003s'
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ module Lucid
4
+ describe Runtime::Facade do
5
+
6
+ let(:interface) {double('interface')}
7
+ subject { Runtime::Orchestrator.new(interface,{}) }
8
+ let(:facade) { Runtime::Facade.new(subject, interface) }
9
+
10
+ it 'should produce AST::Table by #table' do
11
+ facade.table( %{
12
+ | study | phase |
13
+ | test-01 | I |
14
+ | test-02 | II |
15
+ } ).should be_kind_of(AST::Table)
16
+ end
17
+
18
+ it 'should produce AST::DocString by #doc_string with default content-type' do
19
+ str = facade.doc_string('TEST')
20
+ str.should be_kind_of(AST::DocString)
21
+ str.content_type.should eq('')
22
+ end
23
+
24
+ it 'should produce AST::DocString by #doc_string with ruby content-type' do
25
+ str = facade.doc_string('TEST','ruby')
26
+ str.should be_kind_of(AST::DocString)
27
+ str.content_type.should eq('ruby')
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,127 @@
1
+ require_relative '../spec_helper'
2
+
3
+ module Lucid
4
+ module InterfaceRb
5
+ describe Matcher do
6
+
7
+ before do
8
+ @pattern = 'There is a missing step'
9
+ @multiline_argument_class = nil
10
+ end
11
+
12
+ let(:code_keyword) { 'Given' }
13
+
14
+ let(:matcher) do
15
+ matcher_class.new(code_keyword, @pattern, @multiline_argument_class)
16
+ end
17
+
18
+ def unindent(s)
19
+ s.split("\n")[1..-2].join("\n").indent(-10)
20
+ end
21
+
22
+ describe Matcher::Regexp do
23
+ let(:matcher_class) { Matcher::Regexp }
24
+ let(:matcher_text) { matcher.to_s }
25
+
26
+ it 'should wrap matcher patterns in parentheses' do
27
+ @pattern = 'A "string" with 4 spaces'
28
+
29
+ matcher_text.should == unindent(%{
30
+ Given (/^A "(.*?)" with (\\d+) spaces$/) do |arg1, arg2|
31
+ pending
32
+ end
33
+ })
34
+ end
35
+
36
+ it 'should recognize numbers in name and make an according regexp' do
37
+ @pattern = 'There are 4 spaces'
38
+
39
+ matcher_text.should == unindent(%{
40
+ Given (/^There are (\\d+) spaces$/) do |arg1|
41
+ pending
42
+ end
43
+ })
44
+ end
45
+
46
+ it 'should recognise a mix of ints, strings and a table' do
47
+ @pattern = 'There are 9 "lucid" tests in 20 "categories"'
48
+ @multiline_argument_class = Lucid::AST::Table
49
+
50
+ matcher_text.should == unindent(%{
51
+ Given (/^There are (\\d+) "(.*?)" tests in (\\d+) "(.*?)"$/) do |arg1, arg2, arg3, arg4, table|
52
+ # table is a Lucid::AST::Table
53
+ pending
54
+ end
55
+ })
56
+ end
57
+
58
+ it "should recognize quotes in name and make according regexp" do
59
+ @pattern = 'A "lucid" test'
60
+
61
+ matcher_text.should == unindent(%{
62
+ Given (/^A "(.*?)" test$/) do |arg1|
63
+ pending
64
+ end
65
+ })
66
+ end
67
+
68
+ it 'should recognize several quoted words in name and make according regexp and args' do
69
+ @pattern = 'A "first" and "second" arg'
70
+
71
+ matcher_text.should == unindent(%{
72
+ Given (/^A "(.*?)" and "(.*?)" arg$/) do |arg1, arg2|
73
+ pending
74
+ end
75
+ })
76
+ end
77
+
78
+ it 'should not use quote group when there are no quotes' do
79
+ @pattern = 'A first arg'
80
+
81
+ matcher_text.should == unindent(%{
82
+ Given (/^A first arg$/) do
83
+ pending
84
+ end
85
+ })
86
+ end
87
+
88
+ it 'should be helpful with tables' do
89
+ @pattern = 'A "first" arg'
90
+ @multiline_argument_class = Lucid::AST::Table
91
+
92
+ matcher_text.should == unindent(%{
93
+ Given (/^A "(.*?)" arg$/) do |arg1, table|
94
+ # table is a Lucid::AST::Table
95
+ pending
96
+ end
97
+ })
98
+ end
99
+ end
100
+
101
+ describe Matcher::Classic do
102
+ let(:matcher_class) { Matcher::Classic }
103
+
104
+ it 'renders matcher as unwrapped regular expression' do
105
+ matcher.to_s.should eql unindent(%{
106
+ Given /^There is a missing step$/ do
107
+ pending
108
+ end
109
+ })
110
+ end
111
+ end
112
+
113
+ describe Matcher::Percent do
114
+ let(:matcher_class) { Matcher::Percent }
115
+
116
+ it 'renders matcher as percent-style regular expression' do
117
+ matcher.to_s.should eql unindent(%{
118
+ Given %r{^There is a missing step$} do
119
+ pending
120
+ end
121
+ })
122
+ end
123
+ end
124
+
125
+ end
126
+ end
127
+ end
@@ -1,4 +1,5 @@
1
- require_relative '../spec_helper'
1
+ require 'spec_helper'
2
+ require 'lucid/cli/options'
2
3
 
3
4
  module Lucid
4
5
  module CLI
@@ -23,6 +24,13 @@ module Lucid
23
24
  def prep_args(args)
24
25
  args.is_a?(Array) ? args : args.split(' ')
25
26
  end
27
+
28
+ def with_this_configuration(info)
29
+ Dir.stub(:glob).with('{,.config/,config/}lucid{.yml,.yaml}').and_return(['lucid.yml'])
30
+ File.stub(:exist?).and_return(true)
31
+ lucid_yml = info.is_a?(Hash) ? info.to_yaml : info
32
+ IO.stub(:read).with('lucid.yml').and_return(lucid_yml)
33
+ end
26
34
 
27
35
  describe 'parsing options' do
28
36
 
@@ -37,7 +45,7 @@ module Lucid
37
45
  end
38
46
 
39
47
  context '--version' do
40
- it "should display Lucid's version" do
48
+ it 'should display Lucid version' do
41
49
  after_parsing('--version') do
42
50
  output_stream.string.should =~ /#{Lucid::VERSION}/
43
51
  end
@@ -55,6 +63,20 @@ module Lucid
55
63
  end
56
64
  end
57
65
  end
66
+
67
+ context '--i18n' do
68
+ context "with LANG specified as 'help'" do
69
+ it 'lists all known languages' do
70
+ during_parsing '--i18n help' do
71
+ Kernel.should_receive(:exit)
72
+ end
73
+ end
74
+
75
+ it 'exits the program' do
76
+ during_parsing('--i18n help') { Kernel.should_receive(:exit) }
77
+ end
78
+ end
79
+ end
58
80
 
59
81
  context '-r or --require' do
60
82
  it 'should collect all specified files into an array' do
@@ -85,7 +107,7 @@ module Lucid
85
107
 
86
108
  context '-b or --backtrace' do
87
109
  it 'should use a full backtrace during Lucid execution' do
88
- during_parsing("-b") do
110
+ during_parsing('-b') do
89
111
  Lucid.should_receive(:use_full_backtrace=).with(true)
90
112
  end
91
113
  end
@@ -119,6 +141,204 @@ module Lucid
119
141
  end
120
142
  end
121
143
 
144
+ context '-P or --no-profile' do
145
+ it 'disables profiles' do
146
+ with_this_configuration({'default' => '-v --require code_file.rb'})
147
+
148
+ after_parsing('-P --require other_code_file.rb') do
149
+ options[:require].should == ['other_code_file.rb']
150
+ end
151
+ end
152
+
153
+ it 'notifies the user that the profiles are being disabled' do
154
+ with_this_configuration({'default' => '-v'})
155
+
156
+ after_parsing('--no-profile --require other_code_file.rb') do
157
+ output_stream.string.should =~ /Disabling profiles.../
158
+ end
159
+ end
160
+ end
161
+
162
+ context '-p PROFILE or --profile PROFILE' do
163
+ it 'respects --quiet when defined in the profile' do
164
+ with_this_configuration('test' => '-q')
165
+
166
+ options.parse(%w[-p test])
167
+ options[:matchers].should be_false
168
+ options[:source].should be_false
169
+ end
170
+
171
+ it 'uses the default profile passed in during initialization if none is specified by the user' do
172
+ with_this_configuration({'default' => '--require test_helper'})
173
+
174
+ options = Options.new(output_stream, error_stream, :default_profile => 'default')
175
+ options.parse(%w{--format progress})
176
+ options[:require].should include('test_helper')
177
+ end
178
+
179
+ it 'merges all unique values from both the command line and the profile' do
180
+ with_this_configuration('test' => %w[--verbose])
181
+
182
+ options.parse(%w[--wip --profile test])
183
+ options[:wip].should be_true
184
+ options[:verbose].should be_true
185
+ end
186
+
187
+ it 'gives precedence to the original options spec source path' do
188
+ with_this_configuration('test' => %w[specs])
189
+
190
+ options.parse(%w[test.spec -p test])
191
+ options[:spec_source].should == %w[test.spec]
192
+ end
193
+
194
+ it 'combines the require files of both' do
195
+ with_this_configuration('bar' => %w[--require specs -r helper.rb])
196
+
197
+ options.parse(%w[--require test.rb -p bar])
198
+ options[:require].should == %w[test.rb specs helper.rb]
199
+ end
200
+
201
+ it 'combines the tag names of both' do
202
+ with_this_configuration('test' => %w[-t @smoke])
203
+
204
+ options.parse(%w[--tags @wip -p test])
205
+ options[:tag_expressions].should == ['@wip', '@smoke']
206
+ end
207
+
208
+ it 'only takes the paths from the original options, and disregards the profiles' do
209
+ with_this_configuration('test' => %w[specs])
210
+
211
+ options.parse(%w[test.spec -p test])
212
+ options[:spec_source].should == ['test.spec']
213
+ end
214
+
215
+ it 'uses the paths from the profile when none are specified originally' do
216
+ with_this_configuration('test' => %w[test.spec])
217
+
218
+ options.parse(%w[-p test])
219
+ options[:spec_source].should == ['test.spec']
220
+ end
221
+
222
+ it 'combines environment variables from the profile but gives precedence to command line args' do
223
+ with_this_configuration('test' => %w[BROWSER=firefox DRIVER=mechanize])
224
+
225
+ options.parse(%w[-p test DRIVER=watir CI=jenkins])
226
+ options[:env_vars].should == {'CI' => 'jenkins', 'BROWSER' => 'firefox', 'DRIVER' => 'watir'}
227
+ end
228
+
229
+ it 'disregards STDOUT formatter defined in profile when another is passed in via command line' do
230
+ with_this_configuration({'test' => %w[--format standard]})
231
+
232
+ options.parse(%w{--format progress --profile test})
233
+ options[:formats].should == [['progress', output_stream]]
234
+ end
235
+
236
+ it 'includes any non-STDOUT formatters from the profile' do
237
+ with_this_configuration({'report' => %w[--format html -o results.html]})
238
+
239
+ options.parse(%w{--format progress --profile report})
240
+ options[:formats].should == [['progress', output_stream], ['html', 'results.html']]
241
+ end
242
+
243
+ it 'does not include STDOUT formatters from the profile if there is a STDOUT formatter in command line' do
244
+ with_this_configuration({'report' => %w[--format html -o results.html --format standard]})
245
+
246
+ options.parse(%w{--format progress --profile report})
247
+ options[:formats].should == [['progress', output_stream], ['html', 'results.html']]
248
+ end
249
+
250
+ it 'includes any STDOUT formatters from the profile if no STDOUT formatter was specified in command line' do
251
+ with_this_configuration({'report' => %w[--format html]})
252
+
253
+ options.parse(%w{--format rerun -o rerun.txt --profile report})
254
+ options[:formats].should == [['html', output_stream], ['rerun', 'rerun.txt']]
255
+ end
256
+
257
+ it 'assumes all of the formatters defined in the profile when none are specified on command line' do
258
+ with_this_configuration({'report' => %w[--format progress --format html -o results.html]})
259
+
260
+ options.parse(%w{--profile report})
261
+ options[:formats].should == [['progress', output_stream], ['html', 'results.html']]
262
+ end
263
+
264
+ it 'only reads lucid.yml once' do
265
+ original_parse_count = $lucid_yml_read_count
266
+ $lucid_yml_read_count = 0
267
+
268
+ begin
269
+ with_this_configuration(<<-END
270
+ <% $lucid_yml_read_count += 1 %>
271
+ default: --format standard
272
+ END
273
+ )
274
+ options = Options.new(output_stream, error_stream, :default_profile => 'default')
275
+ options.parse(%w(-f progress))
276
+
277
+ $lucid_yml_read_count.should == 1
278
+ ensure
279
+ $lucid_yml_read_count = original_parse_count
280
+ end
281
+ end
282
+ end
283
+
284
+ context '-P or --no-profile' do
285
+ it 'disables profiles' do
286
+ with_this_configuration({'default' => '-v --require file_specified_in_default_profile.rb'})
287
+
288
+ after_parsing('-P --require test_helper.rb') do
289
+ options[:require].should == ['test_helper.rb']
290
+ end
291
+ end
292
+
293
+ it 'notifies the user that the profiles are being disabled' do
294
+ with_this_configuration({'default' => '-v'})
295
+
296
+ after_parsing('--no-profile --require test_helper.rb') do
297
+ output_stream.string.should =~ /Disabling profiles.../
298
+ end
299
+ end
300
+ end
301
+
302
+ context '--matcher-type' do
303
+ it 'parses the matcher type argument' do
304
+ after_parsing('--matcher-type classic') do
305
+ options[:matcher_type].should eql :classic
306
+ end
307
+ end
308
+ end
309
+
310
+ it 'assigns any extra arguments as paths to specs' do
311
+ after_parsing('-f pretty test.spec other_specs') do
312
+ options[:spec_source].should == ['test.spec', 'other_specs']
313
+ end
314
+ end
315
+
316
+ it 'does not mistake environment variables as spec paths' do
317
+ after_parsing('test.spec ENV=ci') do
318
+ options[:spec_source].should == ['test.spec']
319
+ end
320
+ end
321
+
322
+ describe 'dry-run' do
323
+ it 'should have the default value for matchers' do
324
+ with_this_configuration({'test' => %w[--dry-run]})
325
+ options.parse(%w{--dry-run})
326
+ options[:matchers].should == true
327
+ end
328
+
329
+ it 'should set matchers to false when no-matchers is provided after dry-run' do
330
+ with_this_configuration({'test' => %w[--dry-run --no-snippets]})
331
+ options.parse(%w{--dry-run --no-matchers})
332
+ options[:matchers].should == false
333
+ end
334
+
335
+ it 'should set matchers to false when no-matchers is provided before dry-run' do
336
+ with_this_configuration({'test' => %w[--no-snippet --dry-run]})
337
+ options.parse(%w{--no-matchers --dry-run})
338
+ options[:matchers].should == false
339
+ end
340
+ end
341
+
122
342
  end
123
343
 
124
344
  end
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+
3
+ module Lucid
4
+ describe Runtime::Orchestrator do
5
+ let(:options) { {} }
6
+ let(:interface) { double('interface') }
7
+ subject { Runtime::Orchestrator.new(interface, options) }
8
+
9
+ let(:dsl) do
10
+ @rb = subject.load_code_language('rb')
11
+ Object.new.extend(InterfaceRb::RbLucid)
12
+ end
13
+
14
+ it 'should format step names' do
15
+ dsl.Given(/it (.*) in (.*)/) { |what, month| }
16
+ dsl.Given(/some other phrase/) { |what, month| }
17
+
18
+ format = subject.step_match('it works in lucid').format_args('[%s]')
19
+ format.should == 'it [works] in [lucid]'
20
+ end
21
+
22
+ it 'should cache step match results' do
23
+ dsl.Given(/it (.*) in (.*)/) { |what, month| }
24
+ step_match = subject.step_match('it works in lucid')
25
+ @rb.should_not_receive :step_matches
26
+ second_step_match = subject.step_match('it works in lucid')
27
+ step_match.should equal(second_step_match)
28
+ end
29
+
30
+
31
+ describe 'resolving test definition matches' do
32
+ it 'should raise Undefined error when no test definitions match' do
33
+ lambda do
34
+ subject.step_match('Simple Lucid Test')
35
+ end.should raise_error(Undefined)
36
+ end
37
+
38
+ it 'should raise Ambiguous error with guess hint when multiple test definitions match' do
39
+ expected_error = %{Ambiguous match of "Simple Lucid Test":
40
+
41
+ spec/lucid/orchestrator_spec.rb:\\d+:in `/Simple (.*) Test/'
42
+ spec/lucid/orchestrator_spec.rb:\\d+:in `/Simple Lucid (.*)/'
43
+
44
+ You can run again with --guess to make Lucid be a little more smart about it.
45
+ }
46
+ dsl.Given(/Simple (.*) Test/) {|app|}
47
+ dsl.Given(/Simple Lucid (.*)/) {|action|}
48
+
49
+ lambda do
50
+ subject.step_match("Simple Lucid Test")
51
+ end.should raise_error(Ambiguous, /#{expected_error}/)
52
+ end
53
+
54
+ describe 'when --guess is used' do
55
+ let(:options) { {:guess => true} }
56
+
57
+ it 'should not show --guess hint' do
58
+ expected_error = %{Ambiguous match of "Simple lucid test":
59
+
60
+ spec/lucid/orchestrator_spec.rb:\\d+:in `/Simple (.*)/'
61
+ spec/lucid/orchestrator_spec.rb:\\d+:in `/Simple (.*)/'
62
+
63
+ }
64
+ dsl.Given(/Simple (.*)/) {|phrase|}
65
+ dsl.Given(/Simple (.*)/) {|phrase|}
66
+
67
+ lambda do
68
+ subject.step_match('Simple lucid test')
69
+ end.should raise_error(Ambiguous, /#{expected_error}/)
70
+ end
71
+
72
+ it 'should pick right test definition when an equal number of capture groups' do
73
+ right = dsl.Given(/Simple (.*) test/) {|app|}
74
+ wrong = dsl.Given(/Simple (.*)/) {|phrase|}
75
+
76
+ subject.step_match('Simple lucid test').step_definition.should == right
77
+ end
78
+
79
+ it 'should pick right test definition when an unequal number of capture groups' do
80
+ right = dsl.Given(/Simple (.*) test ran (.*)/) {|app|}
81
+ wrong = dsl.Given(/Simple (.*)/) {|phrase|}
82
+
83
+ subject.step_match('Simple lucid test ran well').step_definition.should == right
84
+ end
85
+
86
+ it 'should pick most specific test definition when an unequal number of capture groups' do
87
+ general = dsl.Given(/Simple (.*) test ran (.*)/) {|app|}
88
+ specific = dsl.Given(/Simple lucid test ran well/) do; end
89
+ more_specific = dsl.Given(/^Simple lucid test ran well$/) do; end
90
+
91
+ subject.step_match('Simple lucid test ran well').step_definition.should == more_specific
92
+ end
93
+
94
+ it 'should not raise Ambiguous error when multiple test definitions match' do
95
+ dsl.Given(/Simple (.*) test/) {|app|}
96
+ dsl.Given(/Simple (.*)/) {|phrase|}
97
+
98
+ lambda do
99
+ subject.step_match('Simple lucid test')
100
+ end.should_not raise_error
101
+ end
102
+
103
+ it 'should not raise NoMethodError when guessing from multiple test definitions with nil fields' do
104
+ dsl.Given(/Simple (.*) test( cannot run well)?/) {|app, status|}
105
+ dsl.Given(/Simple (.*)?/) {|phrase|}
106
+
107
+ lambda do
108
+ subject.step_match('Simple lucid test')
109
+ end.should_not raise_error
110
+ end
111
+
112
+ end
113
+
114
+ end
115
+
116
+ end
117
+ end