multicuke 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/results
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'cucumber'
4
+ gem 'rspec'
5
+ gem 'nokogiri'
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 simcap
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Multicuke
2
+
3
+ Run your cucumber test suite faster. Run one cucumber process per features directory.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'multicuke'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install multicuke
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
data/lib/multicuke.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "multicuke/version"
2
+ require "multicuke/runner"
3
+
4
+ module Multicuke
5
+ # Your code goes here...
6
+ end
@@ -0,0 +1,119 @@
1
+ require 'fileutils'
2
+ require 'builder'
3
+ require 'nokogiri'
4
+ require 'ostruct'
5
+
6
+ module Multicuke
7
+
8
+ class Runner
9
+
10
+ attr_accessor :features_dir_path
11
+ attr_accessor :output_dir_name
12
+ attr_accessor :output_path
13
+ attr_accessor :excluded_dirs, :reports_path, :dry_run
14
+
15
+ def initialize
16
+ yield self if block_given?
17
+
18
+ @dry_run = false if dry_run.nil?
19
+ @output_dir_name = "cucumber_reports" unless output_dir_name
20
+ @output_path = "" unless output_path
21
+ @excluded_dirs = [] unless excluded_dirs
22
+ @reports_path = File.join(output_path, output_dir_name)
23
+ end
24
+
25
+ def start
26
+ FileUtils.mkdir_p reports_path
27
+ index_file_path = File.join(reports_path, "index.html")
28
+ index_file = File.new(index_file_path, "w")
29
+
30
+ unless dry_run
31
+ features_group.each_key { |features_group_name|
32
+ report_file_path = File.join(reports_path, "#{features_group_name}.html")
33
+ feature_full_path = File.join(features_dir_path, "#{features_group_name}")
34
+ fork {
35
+ command = "bundle exec cucumber #{feature_full_path} -r #{features_dir_path} --format html --out #{report_file_path}"
36
+ p "RUNNING #{command}"
37
+ system command
38
+ }
39
+
40
+ p Process.waitall
41
+ }
42
+ end
43
+
44
+ features_group.each_key { |features_group_name|
45
+ feature_file = File.join(reports_path, "#{features_group_name}.html")
46
+ File.open(feature_file) { |file|
47
+ content = file.read
48
+ duration_match = content.match(/Finished in\s+<\w+>(.*?)</)
49
+ duration = duration_match ? duration_match.captures.first : ""
50
+ scenarios_match = content.match(/\d+ scenarios? \((.*?)\)/)
51
+ scenarios = scenarios_match ? scenarios_match.captures.first : ""
52
+ steps_match = content.match(/\d+ steps? \((.*?)\)/)
53
+ steps = steps_match ? steps_match.captures.first : ""
54
+ failed = (scenarios.include?"failed") || (steps.include?"failed")
55
+
56
+ features_group[features_group_name] = OpenStruct.new(:scenarios => scenarios, :steps => steps, :duration => duration, :failed? => failed)
57
+ } if File.exists?(feature_file)
58
+ }
59
+
60
+ b = Builder::XmlMarkup.new :target => index_file, :indent => 2
61
+ b.html {
62
+ b.head {
63
+ b.title("Cucumber reports")
64
+ b.style(css_content)
65
+ }
66
+ b.body {
67
+ b.h2("Features")
68
+ b.ul {
69
+ features_group.each { |name, feature|
70
+ b.li(:class => (feature.failed? ? "failed" : "success")) {
71
+ b.a(name, :href => "#{name}.html")
72
+ b.span("[#{feature.duration}]", :class => "duration")
73
+ b.span("Scenarios: #{feature.scenarios}, Steps: #{feature.steps}", :class => "result")
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+
80
+ index_file.close
81
+ end
82
+
83
+ private
84
+
85
+ def css_content
86
+ <<-CSS
87
+ body {font-family: "Lucida Grande", Helvetica, sans-serif; margin: 2em 8em 2em 8em;}
88
+ ul {list-style-type: square;}
89
+ li {margin: 1em 0 1em 0;}
90
+ li span {float: right; margin-left: 1em; padding: 0 0.3em;}
91
+ li.failed span.result{background: #DC6E6E;}
92
+ li.success span.result{background: #C1E799;}
93
+ span.duration {color: #999999;}
94
+ CSS
95
+ end
96
+
97
+ def match_excluded_dirs(path)
98
+ path.match(Regexp.new(excluded_dirs.join("|")))
99
+ end
100
+
101
+ def features_group
102
+ @features_group ||= find_features_group
103
+ end
104
+
105
+ def find_features_group
106
+ @features_group = {}
107
+ Dir.glob(File.join(features_dir_path, "*")).reject{ |path|
108
+ File.file?(path) || match_excluded_dirs(path)
109
+ }.map { |feature_path|
110
+ File.basename(feature_path)
111
+ }.each { |feature_name|
112
+ @features_group[feature_name] = OpenStruct.new(:scenarios => nil, :steps => nil, :duration => nil, :failed? => false)
113
+ }
114
+ @features_group
115
+ end
116
+
117
+ end
118
+
119
+ end
@@ -0,0 +1,3 @@
1
+ module Multicuke
2
+ VERSION = "0.0.1"
3
+ end
data/multicuke.gemspec ADDED
@@ -0,0 +1,16 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/multicuke/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Simon Caplette"]
6
+ gem.description = %q{Run your features faster}
7
+ gem.summary = %q{Run one cucumber process per features directory}
8
+ gem.homepage = "https://github.com/simcap/multicuke"
9
+
10
+ gem.files = `git ls-files`.split($\)
11
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
12
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
13
+ gem.name = "multicuke"
14
+ gem.require_paths = ["lib"]
15
+ gem.version = Multicuke::VERSION
16
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ module Multicuke
4
+
5
+ describe "Reporting" do
6
+
7
+ after(:each) do
8
+ FileUtils.rm_r(Dir.glob("#{RESULTS_DIR_PATH}/*"), :force => true)
9
+ end
10
+
11
+ it "generates index file in output folder" do
12
+ runner = Multicuke::Runner.new do |r|
13
+ r.features_dir_path = File.expand_path("../features", __FILE__)
14
+ r.output_dir_name = "cuke_reports"
15
+ r.dry_run = true
16
+ r.output_path = RESULTS_DIR_PATH
17
+ end
18
+
19
+ File.should_not exist("#{RESULTS_DIR_PATH}/cuke_reports")
20
+
21
+ runner.start
22
+
23
+ File.should exist("#{RESULTS_DIR_PATH}/cuke_reports/index.html")
24
+ end
25
+
26
+ it "write link to each features on index file" do
27
+ runner = Multicuke::Runner.new do |r|
28
+ r.features_dir_path = File.expand_path("../features", __FILE__)
29
+ r.excluded_dirs = ["steps_definition"]
30
+ r.dry_run = true
31
+ r.output_path = RESULTS_DIR_PATH
32
+ end
33
+
34
+ runner.start
35
+
36
+ File.open("#{RESULTS_DIR_PATH}/cucumber_reports/index.html") { |file|
37
+ content = file.read
38
+ content.should match /.*Cucumber reports.*/
39
+ content.should match /.*<a href="addition.html">addition<\/a>.*/
40
+ content.should match /.*<a href="substraction.html">substraction<\/a>.*/
41
+ content.should match /.*<a href="division.html">division<\/a>.*/
42
+ content.should match /.*<a href="multiplication.html">multiplication<\/a>.*/
43
+ content.should_not match /.*steps_definition.*/
44
+ }
45
+ end
46
+
47
+ end
48
+
49
+ end
@@ -0,0 +1,7 @@
1
+ Feature: Addition
2
+
3
+ Scenario: Add 2 numbers
4
+ Given a first number 1
5
+ And a second number 2
6
+ When I add them
7
+ Then I get 3
@@ -0,0 +1,7 @@
1
+ Feature: Addition going wrong
2
+
3
+ Scenario: Add 2 numbers
4
+ Given a first number 1
5
+ And a second number 2
6
+ When I add them
7
+ Then I get 4
@@ -0,0 +1,7 @@
1
+ Feature: Division
2
+
3
+ Scenario: Divide 2 numbers
4
+ Given a first number 10
5
+ And a second number 2
6
+ When I divide them
7
+ Then I get 5
@@ -0,0 +1 @@
1
+ Feature: Empty feature
@@ -0,0 +1,7 @@
1
+ Feature: Multiplication
2
+
3
+ Scenario: Multiply 2 numbers
4
+ Given a first number 3
5
+ And a second number 4
6
+ When I multiply them
7
+ Then I get 12
@@ -0,0 +1 @@
1
+ # random file to pollute entries
@@ -0,0 +1,27 @@
1
+ Given(/^a first number (\d+)$/) do |first_number|
2
+ @first_operand = first_number.to_i
3
+ end
4
+
5
+ Given(/^a second number (\d+)$/) do |second_number|
6
+ @second_operand = second_number.to_i
7
+ end
8
+
9
+ When(/^I add them$/) do
10
+ @result = @first_operand + @second_operand
11
+ end
12
+
13
+ When(/^I divide them$/) do
14
+ @result = @first_operand / @second_operand
15
+ end
16
+
17
+ When(/^I multiply them$/) do
18
+ @result = @first_operand * @second_operand
19
+ end
20
+
21
+ When(/^I substract them$/) do
22
+ @result = @first_operand - @second_operand
23
+ end
24
+
25
+ Then(/^I get (\d+)$/) do |expected_result|
26
+ expected_result.to_i.should == @result
27
+ end
@@ -0,0 +1,7 @@
1
+ Feature: Substraction
2
+
3
+ Scenario: Substract 2 numbers
4
+ Given a first number 3
5
+ And a second number 1
6
+ When I substract them
7
+ Then I get 2
data/spec/fork_spec.rb ADDED
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ module Multicuke
4
+
5
+ describe "Forking" do
6
+
7
+ it "generates test results files" do
8
+ runner = Multicuke::Runner.new do |r|
9
+ r.features_dir_path = File.expand_path("../features", __FILE__)
10
+ r.excluded_dirs = ["steps_definition"]
11
+ r.output_path = RESULTS_DIR_PATH
12
+ end
13
+
14
+ runner.start
15
+
16
+ File.should exist("#{RESULTS_DIR_PATH}/cucumber_reports/addition.html")
17
+ File.should exist("#{RESULTS_DIR_PATH}/cucumber_reports/division.html")
18
+ File.should exist("#{RESULTS_DIR_PATH}/cucumber_reports/multiplication.html")
19
+ File.should exist("#{RESULTS_DIR_PATH}/cucumber_reports/substraction.html")
20
+
21
+ File.open("#{RESULTS_DIR_PATH}/cucumber_reports/index.html") { |file|
22
+ content = file.read
23
+ content.should match /.*Scenarios: 1 failed, Steps: 1 failed, 3 passed.*/i
24
+ }
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ module Multicuke
4
+
5
+ describe Runner do
6
+ it "initializes with provided configuration" do
7
+ runner = Multicuke::Runner.new do |r|
8
+ r.features_dir_path = "my_feature_path"
9
+ r.output_dir_name = "my_reports"
10
+ r.output_path = "my_output_path"
11
+ r.dry_run = true
12
+ r.excluded_dirs = ["my_first_dir", "my_second_dir"]
13
+ end
14
+
15
+ runner.features_dir_path.should == "my_feature_path"
16
+ runner.output_dir_name.should == "my_reports"
17
+ runner.output_path.should == "my_output_path"
18
+ runner.dry_run.should be_true
19
+ runner.reports_path.should == "my_output_path/my_reports"
20
+ runner.excluded_dirs.should include("my_first_dir", "my_second_dir")
21
+ end
22
+
23
+ it "initializes with default values" do
24
+ runner = Multicuke::Runner.new
25
+
26
+ runner.output_dir_name.should == "cucumber_reports"
27
+ runner.output_path.should == ""
28
+ runner.dry_run.should be_false
29
+ runner.excluded_dirs.should be_empty
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,4 @@
1
+ require File.expand_path '../../lib/multicuke', __FILE__
2
+ require 'fileutils'
3
+
4
+ RESULTS_DIR_PATH = File.expand_path '../results', __FILE__
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: multicuke
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Simon Caplette
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-30 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Run your features faster
15
+ email:
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - .gitignore
21
+ - Gemfile
22
+ - LICENSE
23
+ - README.md
24
+ - Rakefile
25
+ - lib/multicuke.rb
26
+ - lib/multicuke/runner.rb
27
+ - lib/multicuke/version.rb
28
+ - multicuke.gemspec
29
+ - spec/dryrun_spec.rb
30
+ - spec/features/addition/add_numbers.feature
31
+ - spec/features/bad_addition/bad_addition.feature
32
+ - spec/features/division/divide_numbers.feature
33
+ - spec/features/empty/empty_file.feature
34
+ - spec/features/multiplication/multiply_numbers.feature
35
+ - spec/features/random_file.rb
36
+ - spec/features/steps_definition/step_definitions.rb
37
+ - spec/features/substraction/substract_numbers.feature
38
+ - spec/fork_spec.rb
39
+ - spec/runner_spec.rb
40
+ - spec/spec_helper.rb
41
+ homepage: https://github.com/simcap/multicuke
42
+ licenses: []
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubyforge_project:
61
+ rubygems_version: 1.8.24
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: Run one cucumber process per features directory
65
+ test_files:
66
+ - spec/dryrun_spec.rb
67
+ - spec/features/addition/add_numbers.feature
68
+ - spec/features/bad_addition/bad_addition.feature
69
+ - spec/features/division/divide_numbers.feature
70
+ - spec/features/empty/empty_file.feature
71
+ - spec/features/multiplication/multiply_numbers.feature
72
+ - spec/features/random_file.rb
73
+ - spec/features/steps_definition/step_definitions.rb
74
+ - spec/features/substraction/substract_numbers.feature
75
+ - spec/fork_spec.rb
76
+ - spec/runner_spec.rb
77
+ - spec/spec_helper.rb
78
+ has_rdoc: