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,36 @@
1
+ AfterConfiguration do |config|
2
+ puts("Specs are being executed from: #{config.spec_location}")
3
+ end
4
+
5
+ Before('~@practice') do
6
+ @browser = Symbiont::Browser.start
7
+ end
8
+
9
+ AfterStep('@pause') do
10
+ print "Press ENTER to continue..."
11
+ STDIN.getc
12
+ end
13
+
14
+ After do |scenario|
15
+ if scenario.failed?
16
+ Dir::mkdir('results') if not File.directory?('results')
17
+ screenshot = "./results/FAILED_#{scenario.name.gsub(' ','_').gsub(/[^0-9A-Za-z_]/, '')}.png"
18
+
19
+ if @browser
20
+ # This way attempts to save the screenshot as a file.
21
+ #@browser.driver.save_screenshot(screenshot)
22
+
23
+ # This way the image is encoded into the results.
24
+ encoded_img = @browser.driver.screenshot_as(:base64)
25
+ embed("data:image/png;base64,#{encoded_img}", 'image/png')
26
+ end
27
+
28
+ # This is an alternative way to embed.
29
+ #embed screenshot, 'image/png'
30
+ end
31
+ Symbiont::Browser.stop
32
+ end
33
+
34
+ at_exit do
35
+ Symbiont::Browser.stop
36
+ end
@@ -0,0 +1,6 @@
1
+ <% browser = "BROWSER=firefox" %>
2
+ <% std_opts = "-r common -r pages -r steps" %>
3
+ <% rpt_opts = "--format html --out output/specs-report.html" %>
4
+
5
+ default: <%= std_opts %>
6
+ report: <%= std_opts %> <%= rpt_opts %>
@@ -0,0 +1,8 @@
1
+ module Lucid
2
+ # This module defines the API for programming language support in Lucid.
3
+ # While Lucid itself is written in Ruby, any programming language can
4
+ # be supported by implementing this API. Each language implementation
5
+ # must manage its own events and must execute them at appropriate times.
6
+ module Interface
7
+ end
8
+ end
@@ -0,0 +1,125 @@
1
+ require 'lucid/step_match'
2
+ require 'lucid/step_definition_light'
3
+
4
+ module Lucid
5
+ module Interface
6
+ module InterfaceMethods
7
+ def around(scenario)
8
+ execute_around(scenario) do
9
+ yield
10
+ end
11
+ end
12
+
13
+ def before(scenario)
14
+ begin_scenario(scenario)
15
+ execute_before(scenario)
16
+ end
17
+
18
+ def after(scenario)
19
+ execute_after(scenario)
20
+ end_scenario
21
+ end
22
+
23
+ def after_configuration(configuration)
24
+ hooks[:after_configuration].each do |hook|
25
+ hook.invoke('AfterConfiguration', configuration)
26
+ end
27
+ end
28
+
29
+ def execute_after_step(scenario)
30
+ hooks_for(:after_step, scenario).each do |hook|
31
+ invoke(hook, 'AfterStep', scenario, false)
32
+ end
33
+ end
34
+
35
+ def execute_transforms(args)
36
+ args.map do |arg|
37
+ matching_transform = transforms.detect {|transform| transform.match(arg) }
38
+ matching_transform ? matching_transform.invoke(arg) : arg
39
+ end
40
+ end
41
+
42
+ def add_hook(phase, hook)
43
+ hooks[phase.to_sym] << hook
44
+ hook
45
+ end
46
+
47
+ def clear_hooks
48
+ @hooks = nil
49
+ end
50
+
51
+ def add_transform(transform)
52
+ transforms.unshift transform
53
+ transform
54
+ end
55
+
56
+ def hooks_for(phase, scenario) #:nodoc:
57
+ hooks[phase.to_sym].select{|hook| scenario.accept_hook?(hook)}
58
+ end
59
+
60
+ def unmatched_step_definitions
61
+ available_step_definition_hash.keys - invoked_step_definition_hash.keys
62
+ end
63
+
64
+ def available_step_definition(regexp_source, file_colon_line)
65
+ available_step_definition_hash[StepDefinitionLight.new(regexp_source, file_colon_line)] = nil
66
+ end
67
+
68
+ def invoked_step_definition(regexp_source, file_colon_line)
69
+ invoked_step_definition_hash[StepDefinitionLight.new(regexp_source, file_colon_line)] = nil
70
+ end
71
+
72
+ private
73
+
74
+ def available_step_definition_hash
75
+ @available_step_definition_hash ||= {}
76
+ end
77
+
78
+ def invoked_step_definition_hash
79
+ @invoked_step_definition_hash ||= {}
80
+ end
81
+
82
+ def hooks
83
+ @hooks ||= Hash.new{|h,k| h[k] = []}
84
+ end
85
+
86
+ def transforms
87
+ @transforms ||= []
88
+ end
89
+
90
+ def execute_around(scenario, &block)
91
+ hooks_for(:around, scenario).reverse.inject(block) do |blk, hook|
92
+ proc do
93
+ invoke(hook, 'Around', scenario, true) do
94
+ blk.call(scenario)
95
+ end
96
+ end
97
+ end.call
98
+ end
99
+
100
+ def execute_before(scenario)
101
+ hooks_for(:before, scenario).each do |hook|
102
+ invoke(hook, 'Before', scenario, true)
103
+ end
104
+ end
105
+
106
+ def execute_after(scenario)
107
+ hooks_for(:after, scenario).reverse_each do |hook|
108
+ invoke(hook, 'After', scenario, true)
109
+ end
110
+ end
111
+
112
+ def invoke(hook, location, scenario, exception_fails_scenario, &block)
113
+ begin
114
+ hook.invoke(location, scenario, &block)
115
+ rescue Exception => exception
116
+ if exception_fails_scenario
117
+ scenario.fail!(exception)
118
+ else
119
+ raise
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,108 @@
1
+ module Lucid
2
+ module InterfaceRb
3
+ module Matcher
4
+
5
+ ARGUMENT_PATTERNS = ['"(.*?)"', '(\d+)']
6
+
7
+ class BaseMatcher
8
+
9
+ def initialize(code_keyword, pattern, multiline_argument_class)
10
+ @number_of_arguments = 0
11
+ @code_keyword = code_keyword
12
+ @pattern = replace_and_count_capturing_groups(pattern)
13
+ @multiline_argument_class = multiline_argument_class
14
+ end
15
+
16
+ def to_s
17
+ "#{step} #{do_block}"
18
+ end
19
+
20
+ def step
21
+ "#{code_keyword}#{typed_pattern}"
22
+ end
23
+
24
+ def self.cli_option_string(type)
25
+ "%-7s: %-28s Example: %s" % [type, description, example]
26
+ end
27
+
28
+ private
29
+
30
+ attr_reader :code_keyword, :pattern, :multiline_argument_class, :number_of_arguments
31
+
32
+ def replace_and_count_capturing_groups(pattern)
33
+ modified_pattern = ::Regexp.escape(pattern).gsub('\ ', ' ').gsub('/', '\/')
34
+
35
+ ARGUMENT_PATTERNS.each do |argument_pattern|
36
+ modified_pattern.gsub!(::Regexp.new(argument_pattern), argument_pattern)
37
+ @number_of_arguments += modified_pattern.scan(argument_pattern).length
38
+ end
39
+
40
+ modified_pattern
41
+ end
42
+
43
+ def do_block
44
+ do_block = ""
45
+ do_block << "do#{arguments}\n"
46
+ do_block << multiline_comment if multiline_argument_class?
47
+ do_block << " pending\n"
48
+ do_block << "end"
49
+ do_block
50
+ end
51
+
52
+ def arguments
53
+ block_args = (0...number_of_arguments).map { |n| "arg#{n+1}" }
54
+
55
+ if multiline_argument_class
56
+ block_args << multiline_argument_class.default_arg_name
57
+ end
58
+
59
+ block_args.empty? ? "" : " |#{block_args.join(", ")}|"
60
+ end
61
+
62
+ def multiline_comment
63
+ " # #{multiline_argument_class.default_arg_name} is a #{multiline_argument_class.to_s}\n"
64
+ end
65
+
66
+ def multiline_argument_class?
67
+ multiline_argument_class == AST::Table
68
+ end
69
+
70
+ def self.example
71
+ new("Given", "some phrase", nil).step
72
+ end
73
+
74
+ end
75
+
76
+ class Regexp < BaseMatcher
77
+ def typed_pattern
78
+ " (/^#{pattern}$/)"
79
+ end
80
+
81
+ def self.description
82
+ "Matchers with parentheses."
83
+ end
84
+ end
85
+
86
+ class Classic < BaseMatcher
87
+ def typed_pattern
88
+ " /^#{pattern}$/"
89
+ end
90
+
91
+ def self.description
92
+ "Matchers without parentheses."
93
+ end
94
+ end
95
+
96
+ class Percent < BaseMatcher
97
+ def typed_pattern
98
+ " %r{^#{pattern}$}"
99
+ end
100
+
101
+ def self.description
102
+ "Matchers with delimited regexp."
103
+ end
104
+ end
105
+
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,18 @@
1
+ module Lucid
2
+ module InterfaceRb
3
+ # Wrapper for Before, After and AfterStep hooks
4
+ class RbHook
5
+ attr_reader :tag_expressions
6
+
7
+ def initialize(rb_language, tag_expressions, proc)
8
+ @rb_language = rb_language
9
+ @tag_expressions = tag_expressions
10
+ @proc = proc
11
+ end
12
+
13
+ def invoke(location, argument, &block)
14
+ @rb_language.current_domain.lucid_instance_exec(false, location, *[argument, block].compact, &@proc)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,190 @@
1
+ require 'lucid/core_ext/instance_exec'
2
+ require 'lucid/interface_rb/rb_lucid'
3
+ require 'lucid/interface_rb/rb_world'
4
+ require 'lucid/interface_rb/rb_step_definition'
5
+ require 'lucid/interface_rb/rb_hook'
6
+ require 'lucid/interface_rb/rb_transform'
7
+ require 'lucid/interface_rb/matcher'
8
+
9
+ begin
10
+ require 'rspec/expectations'
11
+ rescue LoadError
12
+ begin
13
+ require 'spec/expectations'
14
+ require 'spec/runner/differs/default'
15
+ require 'ostruct'
16
+ rescue LoadError
17
+ require 'test/unit/assertions'
18
+ end
19
+ end
20
+
21
+ module Lucid
22
+ module InterfaceRb
23
+ class NilDomain < StandardError
24
+ def initialize
25
+ super("Domain procs should never return nil")
26
+ end
27
+ end
28
+
29
+ # Raised if there are 2 or more Domain blocks.
30
+ class MultipleDomain < StandardError
31
+ def initialize(first_proc, second_proc)
32
+ message = "You can only pass a proc to #Domain once, but it's happening\n"
33
+ message << "in two places:\n\n"
34
+ message << first_proc.backtrace_line('Domain') << "\n"
35
+ message << second_proc.backtrace_line('Domain') << "\n\n"
36
+ message << "Use Ruby modules instead to extend your worlds. See the Lucid::InterfaceRb::RbLucid#Domain RDoc\n"
37
+ super(message)
38
+ end
39
+ end
40
+
41
+ # This module is the Ruby implementation of the TDL API.
42
+ class RbLanguage
43
+ include Interface::InterfaceMethods
44
+ attr_reader :current_domain, :step_definitions
45
+
46
+ # Get the expressions of various I18n translations of TDL keywords.
47
+ # In this case the TDL is based on Gherkin.
48
+ Gherkin::I18n.code_keywords.each do |adverb|
49
+ RbLucid.alias_adverb(adverb)
50
+ end
51
+
52
+ def initialize(runtime)
53
+ @runtime = runtime
54
+ @step_definitions = []
55
+ RbLucid.rb_language = self
56
+ @domain_proc = @domain_modules = nil
57
+ @assertions_module = find_best_assertions_module
58
+ end
59
+
60
+ def find_best_assertions_module
61
+ begin
62
+ ::RSpec::Matchers
63
+ rescue NameError
64
+ # RSpec >=1.2.4
65
+ begin
66
+ options = OpenStruct.new(:diff_format => :unified, :context_lines => 3)
67
+ Spec::Expectations.differ = Spec::Expectations::Differs::Default.new(options)
68
+ ::Spec::Matchers
69
+ rescue NameError
70
+ ::Test::Unit::Assertions
71
+ end
72
+ end
73
+ end
74
+
75
+ def step_matches(name_to_match, name_to_format)
76
+ @step_definitions.map do |step_definition|
77
+ if(arguments = step_definition.arguments_from(name_to_match))
78
+ StepMatch.new(step_definition, name_to_match, name_to_format, arguments)
79
+ else
80
+ nil
81
+ end
82
+ end.compact
83
+ end
84
+
85
+ def matcher_text(code_keyword, step_name, multiline_arg_class, matcher_type = :regexp)
86
+ matcher_class = typed_matcher_class(matcher_type)
87
+ matcher_class.new(code_keyword, step_name, multiline_arg_class).to_s
88
+ end
89
+
90
+ def begin_rb_scenario(scenario)
91
+ create_domain
92
+ extend_domain
93
+ connect_domain(scenario)
94
+ end
95
+
96
+ def register_rb_hook(phase, tag_expressions, proc)
97
+ add_hook(phase, RbHook.new(self, tag_expressions, proc))
98
+ end
99
+
100
+ def register_rb_transform(regexp, proc)
101
+ add_transform(RbTransform.new(self, regexp, proc))
102
+ end
103
+
104
+ def register_rb_step_definition(regexp, proc_or_sym, options)
105
+ step_definition = RbStepDefinition.new(self, regexp, proc_or_sym, options)
106
+ @step_definitions << step_definition
107
+ step_definition
108
+ end
109
+
110
+ def build_rb_world_factory(domain_modules, proc)
111
+ if(proc)
112
+ raise MultipleDomain.new(@domain_proc, proc) if @domain_proc
113
+ @domain_proc = proc
114
+ end
115
+ @domain_modules ||= []
116
+ @domain_modules += domain_modules
117
+ end
118
+
119
+ def load_code_file(code_file)
120
+ # This is what will allow self.add_step_definition, self.add_hook,
121
+ # and self.add_transform to be called from RbLucid.
122
+ load File.expand_path(code_file)
123
+ end
124
+
125
+ protected
126
+
127
+ def begin_scenario(scenario)
128
+ begin_rb_scenario(scenario)
129
+ end
130
+
131
+ def end_scenario
132
+ @current_domain = nil
133
+ end
134
+
135
+ private
136
+
137
+ def create_domain
138
+ if(@domain_proc)
139
+ @current_domain = @domain_proc.call
140
+ check_nil(@current_domain, @domain_proc)
141
+ else
142
+ @current_domain = Object.new
143
+ end
144
+ end
145
+
146
+ def extend_domain
147
+ @current_domain.extend(RbDomain)
148
+ @current_domain.extend(@assertions_module)
149
+ (@domain_modules || []).each do |mod|
150
+ @current_domain.extend(mod)
151
+ end
152
+ end
153
+
154
+ def connect_domain(scenario)
155
+ @current_domain.__lucid_runtime = @runtime
156
+ @current_domain.__natural_language = scenario.language
157
+ end
158
+
159
+ def check_nil(o, proc)
160
+ if o.nil?
161
+ begin
162
+ raise NilDomain.new
163
+ rescue NilDomain => e
164
+ e.backtrace.clear
165
+ e.backtrace.push(proc.backtrace_line("Domain"))
166
+ raise e
167
+ end
168
+ else
169
+ o
170
+ end
171
+ end
172
+
173
+ MATCHER_TYPES = {
174
+ :regexp => Matcher::Regexp,
175
+ :classic => Matcher::Classic,
176
+ :percent => Matcher::Percent
177
+ }
178
+
179
+ def typed_matcher_class(type)
180
+ MATCHER_TYPES.fetch(type || :regexp)
181
+ end
182
+
183
+ def self.cli_matcher_type_options
184
+ MATCHER_TYPES.keys.sort_by(&:to_s).map do |type|
185
+ MATCHER_TYPES[type].cli_option_string(type)
186
+ end
187
+ end
188
+ end
189
+ end
190
+ end