lucid 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. data/.gitignore +30 -10
  2. data/.rspec +1 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +15 -0
  6. data/Gemfile +4 -2
  7. data/HISTORY.md +22 -0
  8. data/{LICENSE.txt → LICENSE} +6 -3
  9. data/README.md +22 -8
  10. data/Rakefile +2 -1
  11. data/bin/lucid +10 -10
  12. data/bin/lucid-gen +4 -0
  13. data/lib/autotest/discover.rb +11 -0
  14. data/lib/autotest/lucid.rb +6 -0
  15. data/lib/autotest/lucid_mixin.rb +135 -0
  16. data/lib/autotest/lucid_rails.rb +6 -0
  17. data/lib/autotest/lucid_rails_rspec.rb +6 -0
  18. data/lib/autotest/lucid_rails_rspec2.rb +6 -0
  19. data/lib/autotest/lucid_rspec.rb +6 -0
  20. data/lib/autotest/lucid_rspec2.rb +6 -0
  21. data/lib/lucid.rb +32 -1
  22. data/lib/lucid/ast.rb +20 -0
  23. data/lib/lucid/ast/background.rb +116 -0
  24. data/lib/lucid/ast/comment.rb +24 -0
  25. data/lib/lucid/ast/doc_string.rb +44 -0
  26. data/lib/lucid/ast/empty_background.rb +33 -0
  27. data/lib/lucid/ast/examples.rb +49 -0
  28. data/lib/lucid/ast/feature.rb +99 -0
  29. data/lib/lucid/ast/has_steps.rb +74 -0
  30. data/lib/lucid/ast/location.rb +41 -0
  31. data/lib/lucid/ast/multiline_argument.rb +31 -0
  32. data/lib/lucid/ast/names.rb +13 -0
  33. data/lib/lucid/ast/outline_table.rb +194 -0
  34. data/lib/lucid/ast/scenario.rb +103 -0
  35. data/lib/lucid/ast/scenario_outline.rb +144 -0
  36. data/lib/lucid/ast/specs.rb +38 -0
  37. data/lib/lucid/ast/step.rb +122 -0
  38. data/lib/lucid/ast/step_collection.rb +92 -0
  39. data/lib/lucid/ast/step_invocation.rb +196 -0
  40. data/lib/lucid/ast/table.rb +730 -0
  41. data/lib/lucid/ast/tags.rb +28 -0
  42. data/lib/lucid/ast/tdl_walker.rb +195 -0
  43. data/lib/lucid/cli/app.rb +78 -0
  44. data/lib/lucid/cli/configuration.rb +261 -0
  45. data/lib/lucid/cli/options.rb +463 -0
  46. data/lib/lucid/cli/profile.rb +101 -0
  47. data/lib/lucid/configuration.rb +53 -0
  48. data/lib/lucid/core_ext/disable_autorunners.rb +15 -0
  49. data/lib/lucid/core_ext/instance_exec.rb +70 -0
  50. data/lib/lucid/core_ext/proc.rb +36 -0
  51. data/lib/lucid/core_ext/string.rb +9 -0
  52. data/lib/lucid/errors.rb +40 -0
  53. data/lib/lucid/factory.rb +43 -0
  54. data/lib/lucid/formatter/ansicolor.rb +168 -0
  55. data/lib/lucid/formatter/console.rb +218 -0
  56. data/lib/lucid/formatter/debug.rb +33 -0
  57. data/lib/lucid/formatter/duration.rb +11 -0
  58. data/lib/lucid/formatter/gherkin_formatter_adapter.rb +94 -0
  59. data/lib/lucid/formatter/gpretty.rb +24 -0
  60. data/lib/lucid/formatter/html.rb +610 -0
  61. data/lib/lucid/formatter/interceptor.rb +66 -0
  62. data/lib/lucid/formatter/io.rb +31 -0
  63. data/lib/lucid/formatter/jquery-min.js +154 -0
  64. data/lib/lucid/formatter/json.rb +19 -0
  65. data/lib/lucid/formatter/json_pretty.rb +10 -0
  66. data/lib/lucid/formatter/junit.rb +177 -0
  67. data/lib/lucid/formatter/lucid.css +283 -0
  68. data/lib/lucid/formatter/lucid.sass +244 -0
  69. data/lib/lucid/formatter/ordered_xml_markup.rb +24 -0
  70. data/lib/lucid/formatter/progress.rb +95 -0
  71. data/lib/lucid/formatter/rerun.rb +91 -0
  72. data/lib/lucid/formatter/standard.rb +235 -0
  73. data/lib/lucid/formatter/stepdefs.rb +14 -0
  74. data/lib/lucid/formatter/steps.rb +49 -0
  75. data/lib/lucid/formatter/summary.rb +35 -0
  76. data/lib/lucid/formatter/unicode.rb +53 -0
  77. data/lib/lucid/formatter/usage.rb +132 -0
  78. data/lib/lucid/generator.rb +21 -0
  79. data/lib/lucid/generators/project.rb +70 -0
  80. data/lib/lucid/generators/project/Gemfile.tt +6 -0
  81. data/lib/lucid/generators/project/browser-symbiont.rb +24 -0
  82. data/lib/lucid/generators/project/driver-symbiont.rb +4 -0
  83. data/lib/lucid/generators/project/errors.rb +26 -0
  84. data/lib/lucid/generators/project/events-symbiont.rb +36 -0
  85. data/lib/lucid/generators/project/lucid-symbiont.yml +6 -0
  86. data/lib/lucid/interface.rb +8 -0
  87. data/lib/lucid/interface_methods.rb +125 -0
  88. data/lib/lucid/interface_rb/matcher.rb +108 -0
  89. data/lib/lucid/interface_rb/rb_hook.rb +18 -0
  90. data/lib/lucid/interface_rb/rb_language.rb +190 -0
  91. data/lib/lucid/interface_rb/rb_lucid.rb +119 -0
  92. data/lib/lucid/interface_rb/rb_step_definition.rb +122 -0
  93. data/lib/lucid/interface_rb/rb_transform.rb +57 -0
  94. data/lib/lucid/interface_rb/rb_world.rb +136 -0
  95. data/lib/lucid/interface_rb/regexp_argument_matcher.rb +21 -0
  96. data/lib/lucid/load_path.rb +13 -0
  97. data/lib/lucid/parser.rb +2 -126
  98. data/lib/lucid/platform.rb +27 -0
  99. data/lib/lucid/rspec/allow_doubles.rb +20 -0
  100. data/lib/lucid/rspec/disallow_options.rb +27 -0
  101. data/lib/lucid/runtime.rb +200 -0
  102. data/lib/lucid/runtime/facade.rb +60 -0
  103. data/lib/lucid/runtime/interface_io.rb +60 -0
  104. data/lib/lucid/runtime/orchestrator.rb +218 -0
  105. data/lib/lucid/runtime/results.rb +64 -0
  106. data/lib/lucid/runtime/specs_loader.rb +79 -0
  107. data/lib/lucid/spec_file.rb +112 -0
  108. data/lib/lucid/step_definition_light.rb +20 -0
  109. data/lib/lucid/step_definitions.rb +13 -0
  110. data/lib/lucid/step_match.rb +99 -0
  111. data/lib/lucid/tdl_builder.rb +282 -0
  112. data/lib/lucid/term/ansicolor.rb +118 -0
  113. data/lib/lucid/unit.rb +11 -0
  114. data/lib/lucid/wire_support/configuration.rb +38 -0
  115. data/lib/lucid/wire_support/connection.rb +61 -0
  116. data/lib/lucid/wire_support/request_handler.rb +32 -0
  117. data/lib/lucid/wire_support/wire_exception.rb +32 -0
  118. data/lib/lucid/wire_support/wire_language.rb +54 -0
  119. data/lib/lucid/wire_support/wire_packet.rb +34 -0
  120. data/lib/lucid/wire_support/wire_protocol.rb +43 -0
  121. data/lib/lucid/wire_support/wire_protocol/requests.rb +125 -0
  122. data/lib/lucid/wire_support/wire_step_definition.rb +26 -0
  123. data/lucid.gemspec +25 -14
  124. metadata +220 -12
  125. data/lib/lucid/app.rb +0 -103
  126. data/lib/lucid/options.rb +0 -168
  127. data/lib/lucid/version.rb +0 -3
  128. data/lucid.yml +0 -8
@@ -0,0 +1,38 @@
1
+ module Lucid
2
+ module AST
3
+ class Specs #:nodoc:
4
+ include Enumerable
5
+
6
+ attr_reader :duration
7
+
8
+ def initialize
9
+ @features = []
10
+ end
11
+
12
+ def [](index)
13
+ @features[index]
14
+ end
15
+
16
+ def each(&proc)
17
+ @features.each(&proc)
18
+ end
19
+
20
+ def add_feature(feature)
21
+ @features << feature
22
+ end
23
+
24
+ def accept(visitor)
25
+ return if Lucid.wants_to_quit
26
+ start = Time.now
27
+ self.each do |feature|
28
+ visitor.visit_feature(feature)
29
+ end
30
+ @duration = Time.now - start
31
+ end
32
+
33
+ def step_count
34
+ @features.inject(0) { |total, feature| total += feature.step_count }
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,122 @@
1
+ require 'lucid/core_ext/string'
2
+ require 'lucid/step_match'
3
+ require 'lucid/ast/location'
4
+
5
+ module Lucid
6
+ module AST
7
+ class Step #:nodoc:
8
+ include HasLocation
9
+
10
+ attr_reader :keyword, :name, :language
11
+ attr_writer :step_collection, :options
12
+ attr_accessor :feature_element, :exception, :multiline_arg
13
+
14
+ INDENT = 2
15
+
16
+ def initialize(language, location, keyword, name, multiline_arg=nil)
17
+ @language, @location, @keyword, @name, @multiline_arg = language, location, keyword, name, multiline_arg
18
+ @language || raise("Language is required!")
19
+ end
20
+
21
+ attr_reader :gherkin_statement
22
+ def gherkin_statement(statement=nil)
23
+ @gherkin_statement ||= statement
24
+ end
25
+
26
+ def background?
27
+ false
28
+ end
29
+
30
+ def status
31
+ # Step always has status skipped, because Step is always in a ScenarioOutline
32
+ :skipped
33
+ end
34
+
35
+ def step_invocation
36
+ StepInvocation.new(self, name, @multiline_arg, [])
37
+ end
38
+
39
+ def step_invocation_from_cells(cells)
40
+ matched_cells = matched_cells(cells)
41
+
42
+ delimited_arguments = delimit_argument_names(cells.to_hash)
43
+ name = replace_name_arguments(delimited_arguments)
44
+ multiline_arg = @multiline_arg.nil? ? nil : @multiline_arg.arguments_replaced(delimited_arguments)
45
+
46
+ StepInvocation.new(self, name, multiline_arg, matched_cells)
47
+ end
48
+
49
+ def accept(visitor)
50
+ return if Lucid.wants_to_quit
51
+ # The only time a Step is visited is when it is in a ScenarioOutline.
52
+ # Otherwise it's always StepInvocation that gets visited instead.
53
+ visit_step_result(visitor, first_match(visitor), @multiline_arg, :skipped, nil, nil)
54
+ end
55
+
56
+ def visit_step_result(visitor, step_match, multiline_arg, status, exception, background)
57
+ visitor.visit_step_result(keyword, step_match, @multiline_arg, status, exception, source_indent, background, file_colon_line)
58
+ end
59
+
60
+ def first_match(visitor)
61
+ # The feature_element is always a ScenarioOutline in this case.
62
+ feature_element.each_example_row do |cells|
63
+ argument_hash = cells.to_hash
64
+ delimited_arguments = delimit_argument_names(argument_hash)
65
+ name_to_match = replace_name_arguments(delimited_arguments)
66
+ step_match = visitor.runtime.step_match(name_to_match, name) rescue nil
67
+ return step_match if step_match
68
+ end
69
+ NoStepMatch.new(self, name)
70
+ end
71
+
72
+ def to_sexp
73
+ [:step, line, keyword, name, (@multiline_arg.nil? ? nil : @multiline_arg.to_sexp)].compact
74
+ end
75
+
76
+ def source_indent
77
+ feature_element.source_indent(text_length)
78
+ end
79
+
80
+ def text_length(name=name)
81
+ INDENT + INDENT + keyword.unpack('U*').length + name.unpack('U*').length
82
+ end
83
+
84
+ def backtrace_line
85
+ @backtrace_line ||= feature_element.backtrace_line("#{keyword}#{name}", line) unless feature_element.nil?
86
+ end
87
+
88
+ def dom_id
89
+ @dom_id ||= file_colon_line.gsub(/\//, '_').gsub(/\./, '_').gsub(/:/, '_')
90
+ end
91
+
92
+ private
93
+
94
+ def matched_cells(cells)
95
+ col_index = 0
96
+ cells.select do |cell|
97
+ header_cell = cell.table.header_cell(col_index)
98
+ col_index += 1
99
+ delimited = delimited(header_cell.value)
100
+ name.index(delimited) || (@multiline_arg && @multiline_arg.has_text?(delimited))
101
+ end
102
+ end
103
+
104
+ def delimit_argument_names(argument_hash)
105
+ argument_hash.inject({}) { |h,(name,value)| h[delimited(name)] = value; h }
106
+ end
107
+
108
+ def delimited(s)
109
+ "<#{s}>"
110
+ end
111
+
112
+ def replace_name_arguments(argument_hash)
113
+ name_with_arguments_replaced = name
114
+ argument_hash.each do |key, value|
115
+ value ||= ''
116
+ name_with_arguments_replaced = name_with_arguments_replaced.gsub(key, value)
117
+ end
118
+ name_with_arguments_replaced
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,92 @@
1
+ module Lucid
2
+ module AST
3
+ # This class holds an array of Step or StepDefinition.
4
+ class StepCollection #:nodoc:
5
+ include Enumerable
6
+
7
+ def initialize(steps)
8
+ @steps = steps
9
+ @steps.each{|step| step.step_collection = self}
10
+ end
11
+
12
+ def inspect
13
+ @steps.map { |s| [s.class, s.object_id] }.join(', ')
14
+ end
15
+
16
+ def accept(visitor)
17
+ return if Lucid.wants_to_quit
18
+ @steps.each do |step|
19
+ visitor.visit_step(step)
20
+ end
21
+ end
22
+
23
+ def step_invocations(background = false)
24
+ StepCollection.new(@steps.map{ |step|
25
+ i = step.step_invocation
26
+ i.background = background
27
+ i
28
+ })
29
+ end
30
+
31
+ def skip_invoke!
32
+ @steps.each{|step_invocation| step_invocation.skip_invoke!}
33
+ end
34
+
35
+ def step_invocations_from_cells(cells)
36
+ @steps.map{|step| step.step_invocation_from_cells(cells)}
37
+ end
38
+
39
+ def +(step_invocations)
40
+ dup(step_invocations)
41
+ end
42
+
43
+ # Duplicates this instance and adds +step_invocations+ to the end
44
+ def dup(step_invocations = [])
45
+ StepCollection.new(@steps + step_invocations)
46
+ end
47
+
48
+ def each(&proc)
49
+ @steps.each(&proc)
50
+ end
51
+
52
+ def previous_step(step)
53
+ i = @steps.index(step) || -1
54
+ @steps[i-1]
55
+ end
56
+
57
+ def empty?
58
+ @steps.empty?
59
+ end
60
+
61
+ def max_line_length(feature_element)
62
+ lengths = (@steps + [feature_element]).map{|e| e.text_length}
63
+ lengths.max
64
+ end
65
+
66
+ def exception
67
+ @exception ||= ((failed = @steps.detect {|step| step.exception}) && failed.exception)
68
+ end
69
+
70
+ def failed?
71
+ status == :failed
72
+ end
73
+
74
+ def passed?
75
+ status == :passed
76
+ end
77
+
78
+ def status
79
+ @steps.each{|step_invocation| return step_invocation.status if step_invocation.status != :passed}
80
+ :passed
81
+ end
82
+
83
+ def length
84
+ @steps.length
85
+ end
86
+
87
+ def to_sexp
88
+ @steps.map{|step| step.to_sexp}
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,196 @@
1
+ require 'lucid/errors'
2
+ require 'lucid/step_match'
3
+ require 'lucid/ast/table'
4
+ require 'gherkin/rubify'
5
+
6
+ module Lucid
7
+ module AST
8
+ class StepInvocation #:nodoc:
9
+ include Gherkin::Rubify
10
+
11
+ attr_writer :step_collection, :background
12
+ attr_reader :name, :matched_cells, :status, :reported_exception
13
+ attr_accessor :exception
14
+
15
+ class << self
16
+ SEVERITY = [:passed, :undefined, :pending, :skipped, :failed]
17
+ def worst_status(statuses)
18
+ SEVERITY[statuses.map{|status| SEVERITY.index(status)}.max]
19
+ end
20
+ end
21
+
22
+ def initialize(step, name, multiline_arg, matched_cells)
23
+ @step, @name, @multiline_arg, @matched_cells = step, name, multiline_arg, matched_cells
24
+ status!(:skipped)
25
+ @skip_invoke = @exception = @step_match = @different_table = @reported_exception = @background = nil
26
+ end
27
+
28
+ def background?
29
+ @background
30
+ end
31
+
32
+ def skip_invoke!
33
+ @skip_invoke = true
34
+ end
35
+
36
+ def accept(visitor)
37
+ return if Lucid.wants_to_quit
38
+ invoke(visitor.runtime, visitor.configuration)
39
+ visit_step_result(visitor)
40
+ end
41
+
42
+ def visit_step_result(visitor)
43
+ visitor.visit_step_result(
44
+ keyword,
45
+ @step_match,
46
+ (@different_table || @multiline_arg),
47
+ @status,
48
+ @reported_exception,
49
+ source_indent,
50
+ @background,
51
+ file_colon_line
52
+ )
53
+ end
54
+
55
+ def invoke(runtime, configuration)
56
+ find_step_match!(runtime, configuration)
57
+ unless @skip_invoke || configuration.dry_run? || @exception || @step_collection.exception
58
+ @skip_invoke = true
59
+ begin
60
+ @step_match.invoke(@multiline_arg)
61
+ runtime.after_step
62
+ status!(:passed)
63
+ rescue Pending => e
64
+ failed(configuration, e, false)
65
+ status!(:pending)
66
+ rescue Undefined => e
67
+ failed(configuration, e, false)
68
+ status!(:undefined)
69
+ rescue Lucid::AST::Table::Different => e
70
+ @different_table = e.table
71
+ failed(configuration, e, false)
72
+ status!(:failed)
73
+ rescue Exception => e
74
+ failed(configuration, e, false)
75
+ status!(:failed)
76
+ end
77
+ end
78
+ end
79
+
80
+ def find_step_match!(runtime, configuration)
81
+ return if @step_match
82
+ begin
83
+ @step_match = runtime.step_match(@name)
84
+ rescue Undefined => e
85
+ failed(configuration, e, true)
86
+ status!(:undefined)
87
+ @step_match = NoStepMatch.new(@step, @name)
88
+ rescue Ambiguous => e
89
+ failed(configuration, e, false)
90
+ status!(:failed)
91
+ @step_match = NoStepMatch.new(@step, @name)
92
+ end
93
+ runtime.step_visited(self)
94
+ end
95
+
96
+ def failed(configuration, e, clear_backtrace)
97
+ e.set_backtrace([]) if e.backtrace.nil? || clear_backtrace
98
+ e.backtrace << @step.backtrace_line unless @step.backtrace_line.nil?
99
+ e = filter_backtrace(e)
100
+ @exception = e
101
+ if(configuration.strict? || !(Undefined === e) || e.nested?)
102
+ @reported_exception = e
103
+ else
104
+ @reported_exception = nil
105
+ end
106
+ end
107
+
108
+ BACKTRACE_FILTER_PATTERNS = [/vendor\/rails|lib\/lucid|bin\/lucid:|lib\/rspec|gems\/|minitest|test\/unit/]
109
+
110
+ if(Lucid::JRUBY)
111
+ BACKTRACE_FILTER_PATTERNS << /org\/jruby/
112
+ end
113
+
114
+ PWD_PATTERN = /#{Regexp.escape(Dir.pwd)}\//m
115
+
116
+ def filter_backtrace(e)
117
+ return e if Lucid.use_full_backtrace
118
+ e.backtrace.each{|line| line.gsub!(PWD_PATTERN, "./")}
119
+
120
+ filtered = (e.backtrace || []).reject do |line|
121
+ BACKTRACE_FILTER_PATTERNS.detect { |p| line =~ p }
122
+ end
123
+
124
+ if ENV['LUCID_TRUNCATE_OUTPUT']
125
+ # Strip off file locations
126
+ filtered = filtered.map do |line|
127
+ line =~ /(.*):in `/ ? $1 : line
128
+ end
129
+ end
130
+
131
+ e.set_backtrace(filtered)
132
+ e
133
+ end
134
+
135
+ def status!(status)
136
+ @status = status
137
+ @matched_cells.each do |cell|
138
+ cell.status = status
139
+ end
140
+ end
141
+
142
+ def previous
143
+ @step_collection.previous_step(self)
144
+ end
145
+
146
+ def actual_keyword
147
+ repeat_keywords = rubify([language.keywords('but'), language.keywords('and')]).flatten.uniq.reject{|kw| kw == '* '}
148
+ if repeat_keywords.index(@step.keyword) && previous
149
+ previous.actual_keyword
150
+ else
151
+ keyword == '* ' ? language.code_keywords.first : keyword
152
+ end
153
+ end
154
+
155
+ def source_indent
156
+ @step.feature_element.source_indent(text_length)
157
+ end
158
+
159
+ def text_length
160
+ @step.text_length(@name)
161
+ end
162
+
163
+ def keyword
164
+ @step.keyword
165
+ end
166
+
167
+ def multiline_arg
168
+ @step.multiline_arg
169
+ end
170
+
171
+ def file_colon_line
172
+ @step.file_colon_line
173
+ end
174
+
175
+ def dom_id
176
+ @step.dom_id
177
+ end
178
+
179
+ def backtrace_line
180
+ @step.backtrace_line
181
+ end
182
+
183
+ def language
184
+ @step.language || raise("Language is required on #{@step}")
185
+ end
186
+
187
+ def gherkin_statement
188
+ @step.gherkin_statement
189
+ end
190
+
191
+ def to_sexp
192
+ [:step_invocation, @step.line, @step.keyword, @name, (@multiline_arg.nil? ? nil : @multiline_arg.to_sexp)].compact
193
+ end
194
+ end
195
+ end
196
+ end