lucid 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +2 -0
  3. data/HISTORY.md +8 -0
  4. data/LICENSE +3 -0
  5. data/README.md +11 -2
  6. data/Rakefile +10 -1
  7. data/lib/autotest/discover.rb +5 -5
  8. data/lib/autotest/lucid_mixin.rb +34 -35
  9. data/lib/lucid/ast/table.rb +5 -4
  10. data/lib/lucid/cli/configuration.rb +0 -6
  11. data/lib/lucid/cli/options.rb +3 -12
  12. data/lib/lucid/formatter/condensed.rb +46 -0
  13. data/lib/lucid/formatter/html.rb +9 -3
  14. data/lib/lucid/formatter/junit.rb +6 -8
  15. data/lib/lucid/formatter/standard.rb +1 -7
  16. data/lib/lucid/generators/project/events-symbiont.rb +1 -1
  17. data/lib/lucid/platform.rb +1 -1
  18. data/lib/lucid/runtime.rb +1 -1
  19. data/lib/lucid/sequence.rb +5 -0
  20. data/lib/lucid/sequence/sequence_errors.rb +64 -0
  21. data/lib/lucid/sequence/sequence_group.rb +35 -0
  22. data/lib/lucid/sequence/sequence_phrase.rb +166 -0
  23. data/lib/lucid/sequence/sequence_steps.rb +20 -0
  24. data/lib/lucid/sequence/sequence_support.rb +26 -0
  25. data/lib/lucid/sequence/sequence_template.rb +354 -0
  26. data/lib/lucid/spec_file.rb +3 -1
  27. data/lib/lucid/step_match.rb +1 -1
  28. data/lib/lucid/wire_support/wire_packet.rb +1 -1
  29. data/lucid.gemspec +11 -9
  30. data/spec/lucid/app_spec.rb +42 -0
  31. data/spec/lucid/configuration_spec.rb +112 -0
  32. data/spec/lucid/sequences/sequence_conditional_spec.rb +74 -0
  33. data/spec/lucid/sequences/sequence_group_spec.rb +55 -0
  34. data/spec/lucid/sequences/sequence_phrase_spec.rb +122 -0
  35. data/spec/lucid/sequences/sequence_placeholder_spec.rb +56 -0
  36. data/spec/lucid/sequences/sequence_section_spec.rb +61 -0
  37. data/spec/lucid/sequences/sequence_support_spec.rb +65 -0
  38. data/spec/lucid/sequences/sequence_template_spec.rb +298 -0
  39. data/spec/spec_helper.rb +13 -0
  40. metadata +86 -54
  41. data/.rspec +0 -1
@@ -73,7 +73,9 @@ module Lucid
73
73
  if @path == "specs"
74
74
  STDOUT.puts ["\nYou don't have a 'specs' directory. This is the default specification",
75
75
  "directory that Lucid will use if one is not specified. So either create",
76
- "that directory or specify where your test repository is located."].join("\n")
76
+ "that directory or specify where your test repository is located.\n\n"].join("\n")
77
+ #e.message << "."
78
+ raise e
77
79
  else
78
80
  STDOUT.puts ["\nThere is no '#{@path}' directory. Since that is what you specified as",
79
81
  "your spec repository, this directory must be present."].join("\n")
@@ -12,7 +12,7 @@ module Lucid
12
12
  end
13
13
 
14
14
  def args
15
- @step_arguments.map{|g| g.val}
15
+ @step_arguments.map{|g| g.val.freeze}
16
16
  end
17
17
 
18
18
  def name
@@ -23,7 +23,7 @@ module Lucid
23
23
  def to_json
24
24
  packet = [@message]
25
25
  packet << @params if @params
26
- packet.to_json
26
+ MultiJson.dump(packet)
27
27
  end
28
28
 
29
29
  def handle_with(handler)
data/lucid.gemspec CHANGED
@@ -8,22 +8,24 @@ Gem::Specification.new do |gem|
8
8
  gem.name = 'lucid'
9
9
  gem.version = Lucid::VERSION
10
10
  gem.authors = ["Jeff Nyman"]
11
- gem.description = "Test Description Language Execution Engine"
11
+ gem.description = 'Test Description Language Execution Engine'
12
12
  gem.summary = "lucid-#{gem.version}"
13
- gem.email = ["jeffnyman@gmail.com"]
14
- gem.license = "MIT"
15
- gem.homepage = "https://github.com/jnyman/lucid"
13
+ gem.email = ['jeffnyman@gmail.com']
14
+ gem.license = 'MIT'
15
+ gem.homepage = 'https://github.com/jnyman/lucid'
16
16
  gem.platform = Gem::Platform::RUBY
17
17
 
18
- gem.required_ruby_version = ">= 1.9.3"
19
- gem.rubygems_version = ">= 1.6.1"
18
+ gem.required_ruby_version = '>= 1.9.3'
19
+ gem.rubygems_version = '>= 1.6.1'
20
20
 
21
- gem.add_runtime_dependency 'rake', '>= 10.0.4'
22
21
  gem.add_runtime_dependency 'thor', '>= 0.18.1'
23
22
  gem.add_runtime_dependency 'builder', '>= 2.1.2'
24
23
  gem.add_runtime_dependency 'diff-lcs', '>= 1.1.3'
25
- gem.add_runtime_dependency 'gherkin', '~> 2.12.0'
26
- gem.add_runtime_dependency 'multi_json', '~> 1.7.5'
24
+ gem.add_runtime_dependency 'gherkin', '>= 2.12.0'
25
+ gem.add_runtime_dependency 'multi_json', '>= 1.8.0', '< 2.0'
26
+
27
+ gem.add_development_dependency 'rspec', '>= 2.14'
28
+ gem.add_development_dependency 'simplecov', '>= 0.7.1'
27
29
 
28
30
  gem.post_install_message = %{
29
31
  (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)
@@ -0,0 +1,42 @@
1
+ require_relative '../spec_helper'
2
+
3
+ module Lucid
4
+ module CLI
5
+ describe App do
6
+
7
+ let(:args) { [] }
8
+ let(:stdin) { StringIO.new }
9
+ let(:stdout) { StringIO.new }
10
+ let(:stderr) { StringIO.new }
11
+ let(:kernel) { double(:kernel) }
12
+ subject { App.new(args, stdin, stdout, stderr, kernel) }
13
+
14
+ describe "start" do
15
+ context "passed a runtime" do
16
+ let(:runtime) { double('runtime').as_null_object }
17
+
18
+ def do_start
19
+ subject.start(runtime)
20
+ end
21
+
22
+ it "configures the runtime" do
23
+ configuration = double('Configuration').as_null_object
24
+ Configuration.stub(:new => configuration)
25
+ runtime.should_receive(:configure).with(configuration)
26
+ kernel.should_receive(:exit).with(1)
27
+ do_start
28
+ end
29
+
30
+ it "uses that runtime for running and reporting results" do
31
+ results = double('results', :failure? => true)
32
+ runtime.should_receive(:run)
33
+ runtime.stub(:results).and_return(results)
34
+ kernel.should_receive(:exit).with(1)
35
+ do_start
36
+ end
37
+ end
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,112 @@
1
+ require_relative '../spec_helper'
2
+
3
+ module Lucid
4
+ module CLI
5
+ describe Configuration do
6
+
7
+ module ExposeOptions
8
+ attr_reader :options
9
+ end
10
+
11
+ def config
12
+ @config ||= Configuration.new(@out = StringIO.new, @error = StringIO.new).extend(ExposeOptions)
13
+ end
14
+
15
+ def with_these_files(*files)
16
+ File.stub(:directory?).and_return(true)
17
+ File.stub(:file?).and_return(true)
18
+ Dir.stub(:[]).and_return(files)
19
+ end
20
+
21
+ def with_this_configuration_file(info)
22
+ File.stub(:exist?).and_return(true)
23
+ profile_file = info.is_a?(Hash) ? info.to_yaml : info
24
+ IO.stub(:read).with('lucid.yml').and_return(profile_file)
25
+ end
26
+
27
+ it 'should require driver.rb files first' do
28
+ with_these_files('/common/support/browser.rb', '/common/support/driver.rb')
29
+ config.parse(%w{--require /common})
30
+
31
+ config.library_context.should == %w(
32
+ /common/support/driver.rb
33
+ /common/support/browser.rb
34
+ )
35
+ end
36
+
37
+ it 'should not require driver.rb files when a dry run is attempted' do
38
+ with_these_files('/common/support/browser.rb', '/common/support/driver.rb')
39
+ config.parse(%w{--require /common --dry-run})
40
+
41
+ config.library_context.should == %w(
42
+ /common/support/browser.rb
43
+ )
44
+ end
45
+
46
+ it 'should require files in default definition locations' do
47
+ with_these_files('/pages/page.rb', '/steps/steps.rb')
48
+ config.parse(%w{--require /specs})
49
+
50
+ config.definition_context.should == %w(
51
+ /pages/page.rb
52
+ /steps/steps.rb
53
+ )
54
+ end
55
+
56
+ it 'should be able to exclude files based on a specific reference' do
57
+ with_these_files('/common/support/browser.rb', '/common/support/driver.rb')
58
+ config.parse(%w{--require /common --exclude browser.rb})
59
+
60
+ config.spec_requires.should == %w(
61
+ /common/support/driver.rb
62
+ )
63
+ end
64
+
65
+ it 'should be able to exclude files based on a general pattern' do
66
+ with_these_files('/steps/tester.rb', '/steps/tested.rb', '/steps/testing.rb', '/steps/quality.rb')
67
+ config.parse(%w{--require /steps --exclude test(er|ed) --exclude quality})
68
+
69
+ config.spec_requires.should == %w(
70
+ /steps/testing.rb
71
+ )
72
+ end
73
+
74
+ it 'should be able to use a --dry-run option' do
75
+ config.parse(%w{--dry-run})
76
+ config.options[:dry_run].should be_true
77
+ end
78
+
79
+ it 'should be able to use a --no-source option' do
80
+ config.parse(%w{--no-source})
81
+ config.options[:source].should be_false
82
+ end
83
+
84
+ it 'should be able to use a --no-matchers option' do
85
+ config.parse(%w{--no-matchers})
86
+ config.options[:matchers].should be_false
87
+ end
88
+
89
+ it 'should be able to use a --quiet option' do
90
+ config.parse(%w{--quiet})
91
+ config.options[:source].should be_false
92
+ config.options[:matchers].should be_false
93
+ end
94
+
95
+ it 'should be able to use a --verbose option' do
96
+ config.parse(%w{--verbose})
97
+ config.options[:verbose].should be_true
98
+ end
99
+
100
+ it 'should be able to use an --out option' do
101
+ config.parse(%w{--out report.txt})
102
+ config.formats.should == [%w(standard report.txt)]
103
+ end
104
+
105
+ it 'should be able to use multiple --out options' do
106
+ config.parse(%w{--format standard --out report1.txt --out report2.txt})
107
+ config.formats.should == [%w(standard report2.txt)]
108
+ end
109
+
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,74 @@
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/lucid/sequence/sequence_template'
3
+
4
+ module Sequence
5
+ module SequenceTemplate
6
+
7
+ describe ConditionalSection do
8
+
9
+ context 'establishing a conditional section' do
10
+ it 'should be created with a variable name and a boolean' do
11
+ expect { ConditionalSection.new('testing', false) }.not_to raise_error
12
+ expect { ConditionalSection.new('testing', true) }.not_to raise_error
13
+ end
14
+
15
+ it 'should know whether to generated based on the existence of an actual value' do
16
+ [false, true].each do |existence|
17
+ instance = ConditionalSection.new('testing', existence)
18
+ expect(instance.existence).to eq(existence)
19
+ end
20
+ end
21
+ end
22
+
23
+ context 'generating a conditional section' do
24
+ let(:example_child_elements) do
25
+ [ StaticText.new('Test '),
26
+ Placeholder.new('content'),
27
+ EOLine.new
28
+ ]
29
+ end
30
+
31
+ subject { ConditionalSection.new('testing', true) }
32
+
33
+ it 'should know its original source text' do
34
+ expect(subject.to_s).to eq('<?testing>')
35
+ end
36
+
37
+ it 'should generate the children when conditions are met' do
38
+ example_child_elements.each { |child| subject.add_child(child) }
39
+
40
+ locals = { 'content' => 'found', 'testing' => 'exists' }
41
+ generated_text = subject.output(Object.new, locals)
42
+ expected_text = "Test found\n"
43
+ expect(generated_text).to eq(expected_text)
44
+ end
45
+
46
+ it 'should generate the children even when value does not exist' do
47
+ instance = ConditionalSection.new('testing', false)
48
+ example_child_elements.each { |child| instance.add_child(child) }
49
+ locals = { 'content' => 'found' }
50
+ generated_text = instance.output(Object.new, locals)
51
+ expected_text = "Test found\n"
52
+ expect(generated_text).to eq(expected_text)
53
+ end
54
+
55
+ it "should generate nothing when conditions are not met" do
56
+ example_child_elements.each { |child| subject.add_child(child) }
57
+
58
+ locals = { 'content' => 'found' }
59
+ generated_text = subject.output(Object.new, locals)
60
+ expect(generated_text).to eq('')
61
+
62
+ instance = ConditionalSection.new('testing', false)
63
+ example_child_elements.each { |child| instance.add_child(child) }
64
+
65
+ locals = { 'content' => 'found', 'testing' => 'exists' }
66
+ generated_text = instance.output(Object.new, locals)
67
+ expect(generated_text).to eq('')
68
+ end
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,55 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ require_relative '../../../lib/lucid/sequence/sequence_group'
4
+
5
+ module Sequence
6
+ describe SequenceGroup do
7
+
8
+ let(:singleton) { SequenceGroup.instance() }
9
+
10
+ context 'starting state' do
11
+ it 'should be empty' do
12
+ expect(singleton.sequence_steps).to be_empty
13
+ end
14
+ end
15
+
16
+ context 'basic operation' do
17
+ let(:example_steps) do
18
+ example = <<-EXAMPLE
19
+ Given the login page
20
+ When the username is "<username>"
21
+ And the password is "<password>"
22
+ And login is clicked
23
+ EXAMPLE
24
+ end
25
+
26
+ it 'should accept the addition of a new sequence phrase' do
27
+ phrase = '[enter credentials]'
28
+ args = [phrase, example_steps, true]
29
+ expect { singleton.add_sequence(*args) }.not_to raise_error
30
+ expect(singleton).to have(1).sequence_steps
31
+ end
32
+
33
+ it 'should not accept the addition of an existing sequence phrase' do
34
+ phrase = '[enter credentials]'
35
+ args = [phrase, example_steps, true]
36
+ msg = "A sequence with phrase '[enter credentials]' already exists."
37
+ expect { singleton.add_sequence(*args) }.to raise_error(Sequence::DuplicateSequenceError, msg)
38
+ end
39
+
40
+ it 'should return the steps of a sequence phrase' do
41
+ phrase = '[enter credentials]'
42
+ input_values = [['username', 'jnyman'], ['password', 'thx1138']]
43
+ generated = singleton.generate_steps(phrase, input_values)
44
+ expected = <<-EXAMPLE
45
+ Given the login page
46
+ When the username is "jnyman"
47
+ And the password is "thx1138"
48
+ And login is clicked
49
+ EXAMPLE
50
+ expect(generated).to eq(expected)
51
+ end
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,122 @@
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/lucid/sequence/sequence_phrase'
3
+
4
+ module Sequence
5
+
6
+ describe SequencePhrase do
7
+ let(:example_phrase) { 'enter login credentials as <username>' }
8
+
9
+ let(:example_template) do
10
+ example = <<-EXAMPLE
11
+ Given the login page
12
+ When the username is "<username>"
13
+ And the password is "<password>"
14
+ And login is clicked
15
+ EXAMPLE
16
+ end
17
+
18
+ subject { SequencePhrase.new(example_phrase, example_template, true) }
19
+
20
+ context 'sequence phrase generation' do
21
+ it 'should be created with a phrase, steps and a data table indicator' do
22
+ expect { SequencePhrase.new(example_phrase, example_template, true) }.not_to raise_error
23
+ end
24
+
25
+ it 'should indicate that a step argument can never be assigned a value via the phrase' do
26
+ msg = "The step parameter 'password' does not appear in the phrase."
27
+ expect { SequencePhrase.new(example_phrase, example_template, false) }.to raise_error(Sequence::UnreachableStepParameter, msg)
28
+ end
29
+
30
+ it 'should indicate when an argument in the phrase never occurs in any steps' do
31
+ phrase = 'enter credentials as <tester>'
32
+ msg = "The phrase parameter 'tester' does not appear in any step."
33
+ expect { SequencePhrase.new(phrase, example_template, true) }.to raise_error(Sequence::UselessPhraseParameter, msg)
34
+ end
35
+
36
+ it 'should have a sequence key' do
37
+ expect(subject.key).to eq('enter_login_credentials_as_X_T')
38
+ end
39
+
40
+ it 'should establish the placeholders from the sequence phrase' do
41
+ expect(subject.phrase_params).to eq(%w[username])
42
+ end
43
+
44
+ it 'should know the placeholders from the phrase and generated template' do
45
+ expect(subject.values).to eq(%w[username password])
46
+ end
47
+ end
48
+
49
+ context 'sequence phrase execution' do
50
+
51
+ let(:phrase_instance) { %Q|enter credentials as "jnyman"| }
52
+
53
+ it 'should generate the steps' do
54
+ text = subject.expand(phrase_instance, [ %w(password thx1138) ])
55
+ expectation = <<-EXAMPLE
56
+ Given the login page
57
+ When the username is "jnyman"
58
+ And the password is "thx1138"
59
+ And login is clicked
60
+ EXAMPLE
61
+
62
+ expect(text).to eq(expectation)
63
+ end
64
+
65
+ it 'should generate steps even when a step argument has no value' do
66
+ text = subject.expand(phrase_instance, [ ])
67
+ expectation = <<-EXAMPLE
68
+ Given the login page
69
+ When the username is "jnyman"
70
+ And the password is ""
71
+ And login is clicked
72
+ EXAMPLE
73
+
74
+ expect(text).to eq(expectation)
75
+ end
76
+
77
+ it 'should unescape any double-quotes for phrase arguments' do
78
+ specific_phrase = %q|enter credentials as "jnyman\""|
79
+ text = subject.expand(specific_phrase, [ %w(password thx1138) ])
80
+ expectation = <<-EXAMPLE
81
+ Given the login page
82
+ When the username is "jnyman""
83
+ And the password is "thx1138"
84
+ And login is clicked
85
+ EXAMPLE
86
+
87
+ expect(text).to eq(expectation)
88
+ end
89
+
90
+ it 'should indicate when an unknown variable is used' do
91
+ error_message = "Unknown sequence step parameter 'unknown'."
92
+ args = [ %w(unknown anything) ]
93
+ expect { subject.expand(phrase_instance, args) }.to raise_error(UnknownParameterError, error_message)
94
+ end
95
+
96
+ it 'should indicate when an argument gets a value from a phrase and a table' do
97
+ phrase = %Q|enter credentials as "jnyman"|
98
+ msg = "The sequence parameter 'username' has value 'jnyman' and 'tester'."
99
+ args = [ %w(username tester), %w(password thx1138) ]
100
+ expect { subject.expand(phrase, args) }.to raise_error(AmbiguousParameterValue, msg)
101
+ end
102
+
103
+ it 'should expand any built-in variables' do
104
+ phrase = 'do nothing useful'
105
+ quoted_steps = <<-EXAMPLE
106
+ Given the following films:
107
+ <quotes>
108
+ Iron Man 3
109
+ World War Z
110
+ <quotes>
111
+ EXAMPLE
112
+
113
+ instance = SequencePhrase.new(phrase, quoted_steps, true)
114
+ actual = instance.expand(phrase, [])
115
+ expected = quoted_steps.gsub(/<quotes>/, '"""')
116
+ expect(actual).to eq(expected)
117
+ end
118
+ end
119
+
120
+ end
121
+
122
+ end