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,14 @@
1
+ require 'lucid/formatter/usage'
2
+
3
+ module Lucid
4
+ module Formatter
5
+ class Stepdefs < Usage
6
+ def print_steps(stepdef_key)
7
+ end
8
+
9
+ def max_step_length
10
+ 0
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,49 @@
1
+ module Lucid
2
+ module Formatter
3
+ # The formatter used for <tt>--format steps</tt>
4
+ class Steps
5
+
6
+ def initialize(runtime, path_or_io, options)
7
+ @io = ensure_io(path_or_io, "steps")
8
+ @options = options
9
+ @step_definition_files = collect_steps(runtime)
10
+ end
11
+
12
+ def after_features(features)
13
+ print_summary
14
+ end
15
+
16
+ private
17
+
18
+ def print_summary
19
+ count = 0
20
+ @step_definition_files.keys.sort.each do |step_definition_file|
21
+ @io.puts step_definition_file
22
+
23
+ sources = @step_definition_files[step_definition_file]
24
+ source_indent = source_indent(sources)
25
+ sources.sort.each do |file_colon_line, regexp_source|
26
+ @io.print regexp_source.indent(2)
27
+ @io.print " # #{file_colon_line}".indent(source_indent - regexp_source.unpack('U*').length)
28
+ @io.puts
29
+ end
30
+ @io.puts
31
+ count += sources.size
32
+ end
33
+ @io.puts "#{count} step definition(s) in #{@step_definition_files.size} source file(s)."
34
+ end
35
+
36
+ def collect_steps(runtime)
37
+ runtime.step_definitions.inject({}) do |step_definitions, step_definition|
38
+ step_definitions[step_definition.file] ||= []
39
+ step_definitions[step_definition.file] << [ step_definition.file_colon_line, step_definition.regexp_source ]
40
+ step_definitions
41
+ end
42
+ end
43
+
44
+ def source_indent(sources)
45
+ sources.map { |file_colon_line, regexp| regexp.size }.max + 1
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,35 @@
1
+ module Lucid
2
+ module Formatter
3
+ module Summary
4
+
5
+ def scenario_summary(runtime, &block)
6
+ scenarios_proc = lambda{|status| runtime.scenarios(status)}
7
+ dump_count(runtime.scenarios.length, "scenario") + dump_status_counts(scenarios_proc, &block)
8
+ end
9
+
10
+ def step_summary(runtime, &block)
11
+ steps_proc = lambda{|status| runtime.steps(status)}
12
+ dump_count(runtime.steps.length, "step") + dump_status_counts(steps_proc, &block)
13
+ end
14
+
15
+ private
16
+
17
+ def dump_status_counts(find_elements_proc)
18
+ counts = [:failed, :skipped, :undefined, :pending, :passed].map do |status|
19
+ elements = find_elements_proc.call(status)
20
+ elements.any? ? yield("#{elements.length} #{status.to_s}", status) : nil
21
+ end.compact
22
+ if counts.any?
23
+ " (#{counts.join(', ')})"
24
+ else
25
+ ""
26
+ end
27
+ end
28
+
29
+ def dump_count(count, what, state=nil)
30
+ [count, state, "#{what}#{count == 1 ? '' : 's'}"].compact.join(" ")
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,53 @@
1
+ # Require this file if you need Unicode support.
2
+ # Tips for improvement - esp. ruby 1.9: http://www.ruby-forum.com/topic/184730
3
+ require 'lucid/platform'
4
+ require 'lucid/formatter/ansicolor'
5
+
6
+ if Lucid::WINDOWS
7
+ if ENV['LUCID_OUTPUT_ENCODING']
8
+ Lucid::CODEPAGE = ENV['LUCID_OUTPUT_ENCODING']
9
+ elsif `cmd /c chcp` =~ /(\d+)/
10
+ if [65000, 65001].include? $1.to_i
11
+ Lucid::CODEPAGE = 'UTF-8'
12
+ ENV['ANSICON_API'] = 'ruby'
13
+ else
14
+ Lucid::CODEPAGE = "cp#{$1.to_i}"
15
+ end
16
+ else
17
+ Lucid::CODEPAGE = "cp1252"
18
+ STDERR.puts("WARNING: Unable to detect your output codepage; assuming it is 1252. You may have to chcp 1252 or SET LUCID_OUTPUT_ENCODING=cp1252.")
19
+ end
20
+
21
+ module Lucid
22
+ # @private
23
+ module WindowsOutput
24
+ def self.extended(o)
25
+ o.instance_eval do
26
+
27
+ def lucid_preprocess_output(*a)
28
+ begin
29
+ a.map{|arg| arg.to_s.encode(Encoding.default_external)}
30
+ rescue Encoding::UndefinedConversionError => e
31
+ STDERR.lucid_puts("WARNING: #{e.message}")
32
+ a
33
+ end
34
+ end
35
+
36
+ alias lucid_print print
37
+ def print(*a)
38
+ lucid_print(*lucid_preprocess_output(*a))
39
+ end
40
+
41
+ alias lucid_puts puts
42
+ def puts(*a)
43
+ lucid_puts(*lucid_preprocess_output(*a))
44
+ end
45
+ end
46
+ end
47
+
48
+ Kernel.extend(self)
49
+ STDOUT.extend(self)
50
+ STDERR.extend(self)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,132 @@
1
+ require 'lucid/formatter/progress'
2
+ require 'lucid/step_definition_light'
3
+
4
+ module Lucid
5
+ module Formatter
6
+ class Usage < Progress
7
+ include Console
8
+
9
+ class StepDefKey < StepDefinitionLight
10
+ attr_accessor :mean_duration, :status
11
+ end
12
+
13
+ def initialize(runtime, path_or_io, options)
14
+ @runtime = runtime
15
+ @io = ensure_io(path_or_io, "usage")
16
+ @options = options
17
+ @stepdef_to_match = Hash.new{|h,stepdef_key| h[stepdef_key] = []}
18
+ end
19
+
20
+ def before_features(features)
21
+ print_profile_information
22
+ end
23
+
24
+ def before_step(step)
25
+ @step = step
26
+ @start_time = Time.now
27
+ end
28
+
29
+ def before_step_result(*args)
30
+ @duration = Time.now - @start_time
31
+ end
32
+
33
+ def after_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
34
+ step_definition = step_match.step_definition
35
+ unless step_definition.nil? # nil if it's from a scenario outline
36
+ stepdef_key = StepDefKey.new(step_definition.regexp_source, step_definition.file_colon_line)
37
+
38
+ @stepdef_to_match[stepdef_key] << {
39
+ :keyword => keyword,
40
+ :step_match => step_match,
41
+ :status => status,
42
+ :file_colon_line => @step.file_colon_line,
43
+ :duration => @duration
44
+ }
45
+ end
46
+ super
47
+ end
48
+
49
+ def print_summary(features)
50
+ add_unused_stepdefs
51
+ aggregate_info
52
+
53
+ if @options[:dry_run]
54
+ keys = @stepdef_to_match.keys.sort {|a,b| a.regexp_source <=> b.regexp_source}
55
+ else
56
+ keys = @stepdef_to_match.keys.sort {|a,b| a.mean_duration <=> b.mean_duration}.reverse
57
+ end
58
+
59
+ keys.each do |stepdef_key|
60
+ print_step_definition(stepdef_key)
61
+
62
+ if @stepdef_to_match[stepdef_key].any?
63
+ print_steps(stepdef_key)
64
+ else
65
+ @io.puts(" " + format_string("NOT MATCHED BY ANY STEPS", :failed))
66
+ end
67
+ end
68
+ @io.puts
69
+ super
70
+ end
71
+
72
+ def print_step_definition(stepdef_key)
73
+ @io.print format_string(sprintf("%.7f", stepdef_key.mean_duration), :skipped) + " " unless @options[:dry_run]
74
+ @io.print format_string(stepdef_key.regexp_source, stepdef_key.status)
75
+ if @options[:source]
76
+ indent = max_length - stepdef_key.regexp_source.unpack('U*').length
77
+ line_comment = " # #{stepdef_key.file_colon_line}".indent(indent)
78
+ @io.print(format_string(line_comment, :comment))
79
+ end
80
+ @io.puts
81
+ end
82
+
83
+ def print_steps(stepdef_key)
84
+ @stepdef_to_match[stepdef_key].each do |step|
85
+ @io.print " "
86
+ @io.print format_string(sprintf("%.7f", step[:duration]), :skipped) + " " unless @options[:dry_run]
87
+ @io.print format_step(step[:keyword], step[:step_match], step[:status], nil)
88
+ if @options[:source]
89
+ indent = max_length - (step[:keyword].unpack('U*').length + step[:step_match].format_args.unpack('U*').length)
90
+ line_comment = " # #{step[:file_colon_line]}".indent(indent)
91
+ @io.print(format_string(line_comment, :comment))
92
+ end
93
+ @io.puts
94
+ end
95
+ end
96
+
97
+ def max_length
98
+ [max_stepdef_length, max_step_length].compact.max
99
+ end
100
+
101
+ def max_stepdef_length
102
+ @stepdef_to_match.keys.flatten.map{|key| key.regexp_source.unpack('U*').length}.max
103
+ end
104
+
105
+ def max_step_length
106
+ @stepdef_to_match.values.to_a.flatten.map do |step|
107
+ step[:keyword].unpack('U*').length + step[:step_match].format_args.unpack('U*').length
108
+ end.max
109
+ end
110
+
111
+ def aggregate_info
112
+ @stepdef_to_match.each do |key, steps|
113
+ if steps.empty?
114
+ key.status = :skipped
115
+ key.mean_duration = 0
116
+ else
117
+ key.status = AST::StepInvocation.worst_status(steps.map{|step| step[:status]})
118
+ total_duration = steps.inject(0) {|sum, step| step[:duration] + sum}
119
+ key.mean_duration = total_duration / steps.length
120
+ end
121
+ end
122
+ end
123
+
124
+ def add_unused_stepdefs
125
+ @runtime.unmatched_step_definitions.each do |step_definition|
126
+ stepdef_key = StepDefKey.new(step_definition.regexp_source, step_definition.file_colon_line)
127
+ @stepdef_to_match[stepdef_key] = []
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,21 @@
1
+ require 'thor'
2
+ require 'lucid/generators/project'
3
+
4
+ module Lucid
5
+ class Generator < Thor
6
+ desc "project NAME", "Create a new project."
7
+
8
+ #method_option :browser, aliases: "-b", type: :boolean, desc: "Use for browser-based testing."
9
+ method_option :driver, aliases: "-d", type: :string, required: false, desc: "Framework driver to use. (Default value is 'symbiont'.)"
10
+
11
+ def project(name)
12
+ puts "Name of project: #{name}"
13
+
14
+ driver = options[:driver].nil? ? 'symbiont' : options[:driver]
15
+ #browser = options[:browser] == true ? 'true' : 'false'
16
+
17
+ #Lucid::Generators::Project.start([name, browser, driver])
18
+ Lucid::Generators::Project.start([name, driver])
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,70 @@
1
+ require 'thor/group'
2
+
3
+ module Lucid
4
+ module Generators
5
+ class Project < Thor::Group
6
+ include Thor::Actions
7
+
8
+ argument :name, type: :string, desc: "Name of the project."
9
+ argument :driver, type: :string, desc: "Framework driver to use."
10
+
11
+ desc "Generates a project structure."
12
+
13
+ def self.source_root
14
+ File.dirname(__FILE__) + "/project"
15
+ end
16
+
17
+ def spit_back_values
18
+ puts "Create project '#{name}' using #{driver}."
19
+ end
20
+
21
+ def create_project_directory
22
+ empty_directory(name)
23
+ end
24
+
25
+ def create_project_structure
26
+ empty_directory("#{name}/specs")
27
+ empty_directory("#{name}/common")
28
+ empty_directory("#{name}/common/helpers")
29
+ empty_directory("#{name}/common/support")
30
+ empty_directory("#{name}/common/config")
31
+ empty_directory("#{name}/common/data")
32
+ empty_directory("#{name}/steps")
33
+ empty_directory("#{name}/pages")
34
+ end
35
+
36
+ def copy_errors
37
+ copy_file "errors.rb", "#{name}/common/support/errors.rb"
38
+ end
39
+
40
+ def copy_browser
41
+ if driver.downcase == 'symbiont'
42
+ copy_file "browser-symbiont.rb", "#{name}/common/support/browser.rb"
43
+ end
44
+ end
45
+
46
+ def copy_driver
47
+ if driver.downcase == 'symbiont'
48
+ copy_file "driver-symbiont.rb", "#{name}/common/support/driver.rb"
49
+ end
50
+ end
51
+
52
+ def copy_events
53
+ if driver.downcase == 'symbiont'
54
+ copy_file "events-symbiont.rb", "#{name}/common/support/events.rb"
55
+ end
56
+ end
57
+
58
+ def copy_gemfile
59
+ template "Gemfile.tt", "#{name}/Gemfile"
60
+ end
61
+
62
+ def copy_lucid_yml
63
+ if driver.downcase == 'symbiont'
64
+ copy_file "lucid-symbiont.yml", "#{name}/lucid.yml"
65
+ end
66
+ end
67
+
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'lucid'
4
+ <% if driver.downcase == 'symbiont' -%>gem 'symbiont'<% end -%>
5
+ gem 'syntax'
6
+ gem 'rspec'
@@ -0,0 +1,24 @@
1
+ module Symbiont
2
+ module Browser
3
+
4
+ @@browser = false
5
+
6
+ def self.start
7
+ unless @@browser
8
+ target = ENV['BROWSER']
9
+ @@browser = watir_browser(target)
10
+ end
11
+ @@browser
12
+ end
13
+
14
+ def self.stop
15
+ @@browser.quit if @@browser
16
+ end
17
+
18
+ private
19
+
20
+ def self.watir_browser(target)
21
+ Watir::Browser.new(target.to_sym)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,4 @@
1
+ require 'symbiont'
2
+ require 'symbiont/factory'
3
+
4
+ Domain(Symbiont::Factory)
@@ -0,0 +1,26 @@
1
+ class InvalidDataConditionError < StandardError
2
+ end
3
+
4
+ class NecessaryDataNotAvailableError < StandardError
5
+ end
6
+
7
+ class NecessaryDataAlreadyAvailableError < StandardError
8
+ end
9
+
10
+ class NotSpecificEnoughDataError < StandardError
11
+ end
12
+
13
+ class PossibleDataContextError < StandardError
14
+ end
15
+
16
+ class ContextCannotBeFulfilledError < StandardError
17
+ end
18
+
19
+ class DataValidationError < StandardError
20
+ end
21
+
22
+ class UnexpectedDataFoundError < StandardError
23
+ end
24
+
25
+ class TestDataNotFoundError < StandardError
26
+ end