cuke_slicer 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,22 @@
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/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
@@ -0,0 +1,7 @@
1
+ SimpleCov.start do
2
+ add_filter '/spec/'
3
+ add_filter '/features/'
4
+
5
+ #Ignore results that are older than 10 minutes
6
+ merge_timeout 600
7
+ end
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cuke_slicer.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Grange Insurance
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.
@@ -0,0 +1,53 @@
1
+ # CukeSlicer
2
+
3
+ The cuke_slicer gem provides an easy and programmatic way to divide a Cucumber test suite into granular test
4
+ cases that can then be dealt with on an individual basis. Often this means handing them off to a distributed
5
+ testing system in order to parallelize test execution.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'cuke_slicer'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install cuke_slicer
20
+
21
+ ## Usage
22
+
23
+ require 'cuke_slicer'
24
+
25
+
26
+ # Choose which part of your test suite that you want to slice up
27
+ test_directory = 'path/to/your_test_directory'
28
+
29
+ # Choose your slicing filters
30
+ filters = {excluded_tags: ['@tag1','@tag2'],
31
+ included_tags: '@tag3',
32
+ excluded_paths: 'foo',
33
+ included_paths: [/test_directory/]}
34
+
35
+ # Use the slicer to find all tests matching those filters
36
+ found_tests = CukeSlicer::Slicer.new.slice(test_directory, filters)
37
+
38
+
39
+ # Arrange the sliced pieces to suit your particular needs. In this case, we will dump them
40
+ # into a file that Cucumber can consume.
41
+
42
+ File.open('tests_to_run.txt', 'w') { |file| file.puts found_tests }
43
+
44
+ system('cucumber @tests_to_run.txt')
45
+
46
+
47
+ ## Contributing
48
+
49
+ 1. Fork it ( https://github.com/[my-github-username]/cuke_slicer/fork )
50
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
51
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
52
+ 4. Push to the branch (`git push origin my-new-feature`)
53
+ 5. Create a new Pull Request
@@ -0,0 +1,49 @@
1
+ require "bundler/gem_tasks"
2
+ require 'cucumber/rake/task'
3
+ require 'rspec/core/rake_task'
4
+
5
+
6
+ def set_cucumber_options(options)
7
+ ENV['CUCUMBER_OPTS'] = options
8
+ end
9
+
10
+ def combine_options(set_1, set_2)
11
+ set_2 ? "#{set_1} #{set_2}" : set_1
12
+ end
13
+
14
+
15
+ namespace 'cuke_slicer' do
16
+
17
+ task :clear_coverage do
18
+ puts 'Clearing old code coverage results...'
19
+
20
+ # Remove previous coverage results so that they don't get merged in the new results
21
+ code_coverage_directory = File.join(File.dirname(__FILE__), 'coverage')
22
+ FileUtils.remove_dir(code_coverage_directory, true) if File.exists?(code_coverage_directory)
23
+ end
24
+
25
+ namespace 'cucumber' do
26
+ desc 'Run all Cucumber tests for the gem'
27
+ task :tests, [:command_options] do |t, args|
28
+ set_cucumber_options(combine_options('-t ~@wip -t ~@off', args[:command_options]))
29
+ end
30
+ Cucumber::Rake::Task.new(:tests)
31
+ end
32
+
33
+ namespace 'rspec' do
34
+ desc 'Run all RSpec tests for the gem'
35
+ RSpec::Core::RakeTask.new(:specs, :command_options) do |t, args|
36
+ t.rspec_opts = combine_options('--tag ~wip', args[:command_options])
37
+ end
38
+ end
39
+
40
+ desc 'Run all tests for the gem'
41
+ task :test_everything, [:command_options] => :clear_coverage do |t, args|
42
+ Rake::Task['cuke_slicer:rspec:specs'].invoke(args[:command_options])
43
+ Rake::Task['cuke_slicer:cucumber:tests'].invoke(args[:command_options])
44
+ end
45
+
46
+ end
47
+
48
+
49
+ task :default => 'cuke_slicer:test_everything'
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cuke_slicer/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "cuke_slicer"
8
+ spec.version = CukeSlicer::VERSION
9
+ spec.authors = ["Eric Kessler"]
10
+ spec.email = ["morrow748@gmail.com"]
11
+ spec.summary = %q{A gem for extracting test cases from a Cucumber test suite.}
12
+ spec.description = spec.summary
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency "cuke_modeler"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.6"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec", '~> 3.0'
26
+ spec.add_development_dependency "cucumber"
27
+ spec.add_development_dependency "simplecov"
28
+ end
@@ -0,0 +1,106 @@
1
+ When(/^test cases are extracted from "([^"]*)"$/) do |target|
2
+ @output ||= {}
3
+ filters = {}
4
+
5
+ filters[:excluded_tags] = @excluded_tag_filters if @excluded_tag_filters
6
+ filters[:included_tags] = @included_tag_filters if @included_tag_filters
7
+ filters[:excluded_paths] = @excluded_path_filters if @excluded_path_filters
8
+ filters[:included_paths] = @included_path_filters if @included_path_filters
9
+
10
+ @output[target] = CukeSlicer::Slicer.new.slice("#{@default_file_directory}/#{target}", filters, &@custom_filter)
11
+ end
12
+
13
+ When(/^test cases are extracted from it$/) do
14
+ @output ||= {}
15
+ filters = {}
16
+ target = @targets.first
17
+
18
+ begin
19
+ @output[target] = CukeSlicer::Slicer.new.slice("#{@default_file_directory}/#{target}", filters)
20
+ rescue ArgumentError => e
21
+ @error_raised = e
22
+ end
23
+ end
24
+
25
+ When(/^test cases are extracted from them$/) do
26
+ @output ||= {}
27
+ filters = {}
28
+
29
+ @targets.each do |target|
30
+ @output[target] = CukeSlicer::Slicer.new.slice("#{@default_file_directory}/#{target}", filters)
31
+ end
32
+ end
33
+
34
+ When(/^test cases are extracted from "([^"]*)" using the following exclusive tag filters:$/) do |target, filters|
35
+ @output ||= {}
36
+ options = {}
37
+
38
+ options[:excluded_tags] = filters.raw.flatten.collect { |filter| process_filter(filter) }
39
+
40
+ @output[target] = CukeSlicer::Slicer.new.slice("#{@default_file_directory}/#{target}", options)
41
+ end
42
+
43
+ When(/^test cases are extracted from "([^"]*)" using the following inclusive tag filters:$/) do |target, filters|
44
+ @output ||= {}
45
+ options = {}
46
+
47
+ options[:included_tags] = filters.raw.flatten.collect { |filter| process_filter(filter) }
48
+
49
+ @output[target] = CukeSlicer::Slicer.new.slice("#{@default_file_directory}/#{target}", options)
50
+ end
51
+
52
+ When(/^test cases are extracted from "([^"]*)" using the following inclusive path filters:$/) do |target, filters|
53
+ @output ||= {}
54
+ options = {}
55
+
56
+ options[:included_paths] = filters.raw.flatten.collect { |filter| process_filter(filter) }
57
+
58
+ @output[target] = CukeSlicer::Slicer.new.slice("#{@default_file_directory}/#{target}", options)
59
+ end
60
+
61
+ When(/^test cases are extracted from "([^"]*)" using the following exclusive path filters:$/) do |target, filters|
62
+ @output ||= {}
63
+ options = {}
64
+
65
+ options[:excluded_paths] = filters.raw.flatten.collect { |filter| process_filter(filter) }
66
+
67
+ @output[target] = CukeSlicer::Slicer.new.slice("#{@default_file_directory}/#{target}", options)
68
+ end
69
+
70
+ When(/^test cases are extracted from "([^"]*)" using the following custom filter:$/) do |target, filter_block|
71
+ @output ||= {}
72
+
73
+ custom_filter = eval("Proc.new #{filter_block}")
74
+
75
+ @output[target] = CukeSlicer::Slicer.new.slice("#{@default_file_directory}/#{target}", &custom_filter)
76
+ end
77
+
78
+ When(/^test cases are extracted from "([^"]*)" using "([^"]*)"$/) do |target, included_tag_filters|
79
+ @output ||= {}
80
+ options = {}
81
+
82
+ options[:included_tags] = eval("[#{included_tag_filters}]")
83
+
84
+ @output[target] = CukeSlicer::Slicer.new.slice("#{@default_file_directory}/#{target}", options)
85
+ end
86
+
87
+ def process_filter(filter)
88
+ filter.sub!('path/to', @default_file_directory)
89
+ filter =~ /^\/.+\/$/ ? Regexp.new(filter.slice(1..-2)) : filter
90
+ end
91
+
92
+ When(/^it tries to extract test cases using an unknown filter type$/) do
93
+ begin
94
+ @slicer.slice(@default_file_directory, {unknown_filter: 'foo'})
95
+ rescue ArgumentError => e
96
+ @error_raised = e
97
+ end
98
+ end
99
+
100
+ When(/^it tries to extract test cases using an invalid filter$/) do
101
+ begin
102
+ @slicer.slice(@default_file_directory, {included_tags: 7})
103
+ rescue ArgumentError => e
104
+ @error_raised = e
105
+ end
106
+ end
@@ -0,0 +1,79 @@
1
+ Given(/^the following feature file(?: "([^"]*)")?:$/) do |file_name, file_text|
2
+ @test_directory ||= @default_file_directory
3
+ file_name ||= @default_feature_file_name
4
+
5
+ @targets ||= []
6
+ @targets << file_name
7
+
8
+ File.open("#{@test_directory}/#{file_name}", 'w') { |file| file.write(file_text) }
9
+ end
10
+
11
+ Given(/^the directory "([^"]*)"$/) do |directory_name|
12
+ @test_directory = "#{@default_file_directory}/#{directory_name}"
13
+
14
+ FileUtils.mkdir(@test_directory)
15
+ end
16
+
17
+ Given(/^the following tag filters:$/) do |filters|
18
+ filters.hashes.each do |filter|
19
+ case filter['filter type']
20
+ when 'excluded'
21
+ @excluded_tag_filters = filter['filter']
22
+ when 'included'
23
+ @included_tag_filters = filter['filter']
24
+ else
25
+ raise("Unknown filter type #{filter['filter type']}")
26
+ end
27
+ end
28
+ end
29
+
30
+ And(/^the following path filters:$/) do |filters|
31
+ @excluded_path_filters = []
32
+ @included_path_filters = []
33
+
34
+ filters.hashes.each do |filter|
35
+ case filter['filter type']
36
+ when 'excluded'
37
+ @excluded_path_filters << process_filter(filter['filter'])
38
+ when 'included'
39
+ @included_path_filters << process_filter(filter['filter'])
40
+ else
41
+ raise("Unknown filter type #{filter['filter type']}")
42
+ end
43
+ end
44
+ end
45
+
46
+ And(/^the following custom filter:$/) do |filter|
47
+ @custom_filter = eval("Proc.new #{filter}")
48
+ end
49
+
50
+ Given(/^the file "([^"]*)" does not exist$/) do |file_name|
51
+ @test_directory ||= @default_file_directory
52
+
53
+ @targets ||= []
54
+ @targets << file_name
55
+
56
+ file_path = "#{@test_directory}/#{file_name}"
57
+ FileUtils.rm(file_path) if File.exists?(file_path)
58
+ end
59
+
60
+ Given(/^the directory "([^"]*)" does not exist$/) do |directory_name|
61
+ @targets ||= []
62
+ @targets << directory_name
63
+
64
+ file_path = "#{@default_file_directory}/#{directory_name}"
65
+ FileUtils.remove_dir(file_path) if File.exists?(file_path)
66
+ end
67
+
68
+ And(/^the file "([^"]*)"$/) do |file_name|
69
+ @test_directory ||= @default_file_directory
70
+
71
+ @targets ||= []
72
+ @targets << file_name
73
+
74
+ File.open("#{@test_directory}/#{file_name}", 'w') { |file| file.write('') }
75
+ end
76
+
77
+ Given(/^a slicer$/) do
78
+ @slicer = CukeSlicer::Slicer.new
79
+ end
@@ -0,0 +1,47 @@
1
+ Then(/^the following test cases are found$/) do |expected_test_cases|
2
+ expected_test_cases = expected_test_cases.raw.flatten
3
+ expected_test_cases.collect! { |test_case| test_case.sub('path/to', @default_file_directory) }
4
+
5
+ found_test_cases = @output.values.flatten
6
+
7
+ expect(found_test_cases).to match_array(expected_test_cases)
8
+ end
9
+
10
+ Then(/^no test cases are found$/) do
11
+ expect(@output.values.flatten).to be_empty
12
+ end
13
+
14
+ Then(/^The following filter types are valid:$/) do |filter_types|
15
+ filter_types = filter_types.raw.flatten.collect { |filter| filter.to_sym }
16
+
17
+ expect(CukeSlicer::Slicer.known_filters).to match_array(filter_types)
18
+ end
19
+
20
+ Then(/^"([^"]*)" are found$/) do |test_cases|
21
+ expected_test_cases = test_cases.delete(' ').split(',')
22
+ expected_test_cases.collect! { |test_case| test_case.sub('path/to', @default_file_directory) }
23
+
24
+ found_test_cases = @output.values.flatten
25
+
26
+ expect(found_test_cases).to match_array(expected_test_cases)
27
+ end
28
+
29
+ Then(/^an error indicating that the (?:file|directory) does not exist will be triggered$/) do
30
+ expect(@error_raised).to_not be_nil
31
+ expect(@error_raised.message).to match(/file.*directory.*does not exist/i)
32
+ end
33
+
34
+ Then(/^an error indicating that the feature file is invalid will be triggered$/) do
35
+ expect(@error_raised).to_not be_nil
36
+ expect(@error_raised.message).to match(/syntax.*lexing/)
37
+ end
38
+
39
+ Then(/^an error indicating that the filter type is unknown will be triggered$/) do
40
+ expect(@error_raised).to_not be_nil
41
+ expect(@error_raised.message).to match(/unknown filter/i)
42
+ end
43
+
44
+ Then(/^an error indicating that the filter is invalid will be triggered$/) do
45
+ expect(@error_raised).to_not be_nil
46
+ expect(@error_raised.message).to match(/invalid filter/i)
47
+ end
@@ -0,0 +1,18 @@
1
+ require 'simplecov'
2
+ SimpleCov.command_name('cuke_slicer-cucumber_tests')
3
+
4
+
5
+ require 'cuke_slicer'
6
+
7
+
8
+ Before do
9
+ feature_directory = "#{File.dirname(__FILE__)}/.."
10
+ @default_file_directory = "#{feature_directory}/temp_files"
11
+ @default_feature_file_name = 'unnamed_feature.feature'
12
+
13
+ FileUtils.mkdir(@default_file_directory)
14
+ end
15
+
16
+ After do
17
+ FileUtils.remove_dir(@default_file_directory, true)
18
+ end