cucumber-json 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ examples/self_test/*
2
+ *.gem
3
+ pkg/*
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2010 Jesse Newland
4
+ Portions Copyright (c) 2008,2009 Aslak Hellesøy
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining
7
+ a copy of this software and associated documentation files (the
8
+ "Software"), to deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify, merge, publish,
10
+ distribute, sublicense, and/or sell copies of the Software, and to
11
+ permit persons to whom the Software is furnished to do so, subject to
12
+ the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ begin
2
+ require 'cucumber/rake/task'
3
+
4
+ Cucumber::Rake::Task.new do |t|
5
+ t.cucumber_opts = "--require features/"
6
+ end
7
+ rescue LoadError
8
+ end
9
+
10
+ require 'rubygems'
11
+ require 'rake'
12
+ $LOAD_PATH.unshift 'lib'
13
+ require 'cucumber/formatter/json/version'
14
+
15
+ require 'jeweler'
16
+ Jeweler::Tasks.new do |gem|
17
+ gem.version = Cucumber::Formatter::JSON::VERSION
18
+ gem.name = "cucumber-json"
19
+ gem.summary = %Q{A cucumber formatter that outputs JSON}
20
+ gem.description = %Q{A cucumber formatter that outputs JSON}
21
+ gem.email = "jnewland@gmail.com"
22
+ gem.homepage = "http://github.com/jnewland/cucumber-json"
23
+ gem.authors = ["Jesse Newland"]
24
+ gem.add_dependency "cucumber", "~> 0.6.3"
25
+ gem.add_dependency "json", "~> 1.2.1"
26
+ gem.test_files.include 'features/**/*'
27
+ gem.test_files.exclude 'examples/self_test/tmp/features'
28
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
29
+ end
30
+ Jeweler::GemcutterTasks.new
31
+
32
+ task :cucumber => :check_dependencies
33
+
34
+ task :default => :cucumber
data/Readme.md ADDED
@@ -0,0 +1,63 @@
1
+ cucumber-json
2
+ =============
3
+
4
+ A [Cucumber Output Formatter](http://wiki.github.com/aslakhellesoy/cucumber/custom-formatters)
5
+ that generates JSON.
6
+
7
+ Feature: JSON formatter
8
+ As a developer
9
+ I want to receive reports of failing cucumber features in a parsable format
10
+ In order to facilitace elegant continuous integration
11
+ In order to protect revenue
12
+
13
+ Installation
14
+ ------------
15
+
16
+ gem install cucumber-json
17
+
18
+ Usage
19
+ -----
20
+
21
+ In your project:
22
+
23
+ cucumber --format Cucumber::Formatter::JSON
24
+
25
+ Or, to output to a file:
26
+
27
+ cucumber --format Cucumber::Formatter::JSON --out path/to/filename
28
+
29
+ Parsing
30
+ -------
31
+
32
+ The JSON generated is a hash that has 3 keys:
33
+
34
+ * failing_features
35
+ * an array of all failing features, in a format similar to the default
36
+ cucumber format
37
+ * features
38
+ * an array of all features, in a format similar to the default cucumber
39
+ format
40
+ * status_counts
41
+ * a hash of statuses, and the number of steps with that status
42
+
43
+ Additional information could be added to this hash in the future; this is just
44
+ what I needed at the moment.
45
+
46
+ Example
47
+ -------
48
+
49
+ The output of this project's cucumber features have been run through the
50
+ `Cucumber::Formatter::JSON` formatter and included at `examples/features.json`.
51
+ This was generated like so:
52
+
53
+ cucumber -f Cucumber::Formatter::JSON --out examples/features.json
54
+
55
+ Author
56
+ ------
57
+
58
+ [Jesse Newland](http://twitter.com/jnewland)
59
+
60
+ License
61
+ -------
62
+
63
+ MIT, same license as Ruby. See `LICENSE` for more details
@@ -0,0 +1,62 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{cucumber-json}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Jesse Newland"]
12
+ s.date = %q{2010-05-19}
13
+ s.description = %q{A cucumber formatter that outputs JSON}
14
+ s.email = %q{jnewland@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "LICENSE",
21
+ "Rakefile",
22
+ "Readme.md",
23
+ "cucumber-json.gemspec",
24
+ "examples/features.json",
25
+ "features/formatter.feature",
26
+ "features/step_definitions/cucumber_steps.rb",
27
+ "features/step_definitions/custom_steps.rb",
28
+ "features/support/env.rb",
29
+ "lib/cucumber/formatter/json.rb",
30
+ "lib/cucumber/formatter/json/version.rb"
31
+ ]
32
+ s.homepage = %q{http://github.com/jnewland/cucumber-json}
33
+ s.rdoc_options = ["--charset=UTF-8"]
34
+ s.require_paths = ["lib"]
35
+ s.rubygems_version = %q{1.3.6}
36
+ s.summary = %q{A cucumber formatter that outputs JSON}
37
+ s.test_files = [
38
+ "features/formatter.feature",
39
+ "features/step_definitions",
40
+ "features/step_definitions/cucumber_steps.rb",
41
+ "features/step_definitions/custom_steps.rb",
42
+ "features/support",
43
+ "features/support/env.rb"
44
+ ]
45
+
46
+ if s.respond_to? :specification_version then
47
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
51
+ s.add_runtime_dependency(%q<cucumber>, ["~> 0.6.3"])
52
+ s.add_runtime_dependency(%q<json>, ["~> 1.2.1"])
53
+ else
54
+ s.add_dependency(%q<cucumber>, ["~> 0.6.3"])
55
+ s.add_dependency(%q<json>, ["~> 1.2.1"])
56
+ end
57
+ else
58
+ s.add_dependency(%q<cucumber>, ["~> 0.6.3"])
59
+ s.add_dependency(%q<json>, ["~> 1.2.1"])
60
+ end
61
+ end
62
+
@@ -0,0 +1 @@
1
+ {"failing_features":[],"features":[" Scenario:: One Failing Feature\n When I run cucumber -r ../../../lib -r features/step_definitions -f Cucumber::Formatter::JSON features/one_failure.feature\n Then the output should contain \"output['status_counts']['failed']\" set to \"1\"\n And the output should contain \"output['status_counts']['passed']\" set to \"1\"\n And the output should contain \"output['status_counts']['undefined']\" set to \"1\"\n And the output should contain \"output['status_counts']['pending']\" set to \"1\"\n And the output should contain the failing feature\n \"\"\"\n Scenario:: Failing\n Given failing # features/step_definitions/steps.rb:1\n FAIL (RuntimeError)\n ./features/step_definitions/steps.rb:2:in `/failing/'\n features/one_failure.feature:4:in `Given failing'\n\n \"\"\"\n"," Scenario:: Multiple Failing Features\n When I run cucumber -r ../../../lib -r features/step_definitions -f Cucumber::Formatter::JSON features/multiple_failures.feature\n Then the output should contain \"output['status_counts']['failed']\" set to \"3\"\n And the output should contain \"output['status_counts']['passed']\" set to \"1\"\n And the output should contain the failing feature\n \"\"\"\n Scenario:: Failing\n Given failing # features/step_definitions/steps.rb:1\n FAIL (RuntimeError)\n ./features/step_definitions/steps.rb:2:in `/failing/'\n features/multiple_failures.feature:4:in `Given failing'\n\n \"\"\"\n And the output should contain the failing feature\n \"\"\"\n Scenario:: Failing2\n Given failing # features/step_definitions/steps.rb:1\n FAIL (RuntimeError)\n ./features/step_definitions/steps.rb:2:in `/failing/'\n features/multiple_failures.feature:7:in `Given failing'\n\n \"\"\"\n And the output should contain the failing feature\n \"\"\"\n Scenario:: Failing3\n Given failing # features/step_definitions/steps.rb:1\n FAIL (RuntimeError)\n ./features/step_definitions/steps.rb:2:in `/failing/'\n features/multiple_failures.feature:10:in `Given failing'\n\n \"\"\"\n"," Scenario:: All Features Passing\n When I run cucumber -r ../../../lib -r features/step_definitions -f Cucumber::Formatter::JSON features/all_passing.feature\n Then the output should contain \"output['status_counts']['passed']\" set to \"2\"\n And the output should contain no failing features\n"],"status_counts":{"passed":35}}
@@ -0,0 +1,115 @@
1
+ Feature: JSON formatter
2
+ As a developer
3
+ I want to receive reports of failing cucumber features in a parsable format
4
+ In order to facilitace elegant continuous integration
5
+ In order to protect revenue
6
+
7
+ Background:
8
+ Given a standard Cucumber project directory structure
9
+ And a file named "features/step_definitions/steps.rb" with:
10
+ """
11
+ Given /failing/ do
12
+ raise 'FAIL'
13
+ end
14
+
15
+ Given /pending/ do
16
+ pending
17
+ end
18
+
19
+ Given /passing/ do
20
+ end
21
+ """
22
+ And a file named "features/one_failure.feature" with:
23
+ """
24
+ Feature: One Failure
25
+
26
+ Scenario: Failing
27
+ Given failing
28
+
29
+ Scenario: Missing
30
+ Given missing
31
+
32
+ Scenario: Pending
33
+ Given pending
34
+
35
+ Scenario: Passing
36
+ Given passing
37
+ """
38
+ And a file named "features/multiple_failures.feature" with:
39
+ """
40
+ Feature: Multiple Failures
41
+
42
+ Scenario: Failing
43
+ Given failing
44
+
45
+ Scenario: Failing2
46
+ Given failing
47
+
48
+ Scenario: Failing3
49
+ Given failing
50
+
51
+ Scenario: Passing
52
+ Given passing
53
+ """
54
+ And a file named "features/all_passing.feature" with:
55
+ """
56
+ Feature: All Passing
57
+
58
+ Scenario: Passing
59
+ Given passing
60
+
61
+ Scenario: Passing2
62
+ Given passing
63
+
64
+ """
65
+
66
+ Scenario: One Failing Feature
67
+ When I run cucumber -r ../../../lib -r features/step_definitions -f Cucumber::Formatter::JSON features/one_failure.feature
68
+ Then the output should contain "output['status_counts']['failed']" set to "1"
69
+ And the output should contain "output['status_counts']['passed']" set to "1"
70
+ And the output should contain "output['status_counts']['undefined']" set to "1"
71
+ And the output should contain "output['status_counts']['pending']" set to "1"
72
+ And the output should contain the failing feature
73
+ """
74
+ Scenario:: Failing
75
+ Given failing # features/step_definitions/steps.rb:1
76
+ FAIL (RuntimeError)
77
+ ./features/step_definitions/steps.rb:2:in `/failing/'
78
+ features/one_failure.feature:4:in `Given failing'
79
+
80
+ """
81
+ Scenario: Multiple Failing Features
82
+ When I run cucumber -r ../../../lib -r features/step_definitions -f Cucumber::Formatter::JSON features/multiple_failures.feature
83
+ Then the output should contain "output['status_counts']['failed']" set to "3"
84
+ And the output should contain "output['status_counts']['passed']" set to "1"
85
+ And the output should contain the failing feature
86
+ """
87
+ Scenario:: Failing
88
+ Given failing # features/step_definitions/steps.rb:1
89
+ FAIL (RuntimeError)
90
+ ./features/step_definitions/steps.rb:2:in `/failing/'
91
+ features/multiple_failures.feature:4:in `Given failing'
92
+
93
+ """
94
+ And the output should contain the failing feature
95
+ """
96
+ Scenario:: Failing2
97
+ Given failing # features/step_definitions/steps.rb:1
98
+ FAIL (RuntimeError)
99
+ ./features/step_definitions/steps.rb:2:in `/failing/'
100
+ features/multiple_failures.feature:7:in `Given failing'
101
+
102
+ """
103
+ And the output should contain the failing feature
104
+ """
105
+ Scenario:: Failing3
106
+ Given failing # features/step_definitions/steps.rb:1
107
+ FAIL (RuntimeError)
108
+ ./features/step_definitions/steps.rb:2:in `/failing/'
109
+ features/multiple_failures.feature:10:in `Given failing'
110
+
111
+ """
112
+ Scenario: All Features Passing
113
+ When I run cucumber -r ../../../lib -r features/step_definitions -f Cucumber::Formatter::JSON features/all_passing.feature
114
+ Then the output should contain "output['status_counts']['passed']" set to "2"
115
+ And the output should contain no failing features
@@ -0,0 +1,155 @@
1
+ # encoding: utf-8
2
+ require 'tempfile'
3
+
4
+ Given /^I am in (.*)$/ do |example_dir_relative_path|
5
+ @current_dir = examples_dir(example_dir_relative_path)
6
+ end
7
+
8
+ Given /^a standard Cucumber project directory structure$/ do
9
+ @current_dir = working_dir
10
+ in_current_dir do
11
+ FileUtils.rm_rf 'features' if File.directory?('features')
12
+ FileUtils.mkdir_p 'features/support'
13
+ FileUtils.mkdir 'features/step_definitions'
14
+ end
15
+ end
16
+
17
+ Given /^the (.*) directory is empty$/ do |directory|
18
+ in_current_dir do
19
+ FileUtils.remove_dir(directory) rescue nil
20
+ FileUtils.mkdir 'tmp'
21
+ end
22
+ end
23
+
24
+ Given /^a file named "([^"]*)"$/ do |file_name|
25
+ create_file(file_name, '')
26
+ end
27
+
28
+ Given /^a file named "([^"]*)" with:$/ do |file_name, file_content|
29
+ create_file(file_name, file_content)
30
+ end
31
+
32
+ Given /^the following profiles? (?:are|is) defined:$/ do |profiles|
33
+ create_file('cucumber.yml', profiles)
34
+ end
35
+
36
+ Given /^I am running spork in the background$/ do
37
+ run_spork_in_background
38
+ end
39
+
40
+ Given /^I am running spork in the background on port (\d+)$/ do |port|
41
+ run_spork_in_background(port.to_i)
42
+ end
43
+
44
+ Given /^I am not running (?:.*) in the background$/ do
45
+ # no-op
46
+ end
47
+
48
+ Given /^I have environment variable (\w+) set to "([^"]*)"$/ do |variable, value|
49
+ set_env_var(variable, value)
50
+ end
51
+
52
+ When /^I run cucumber (.*)$/ do |cucumber_opts|
53
+ run "#{Cucumber::RUBY_BINARY} -r rubygems #{Cucumber::BINARY} --no-color #{cucumber_opts} CUCUMBER_OUTPUT_ENCODING=UTF-8"
54
+ end
55
+
56
+ When /^I run rake (.*)$/ do |rake_opts|
57
+ run "rake #{rake_opts} --trace"
58
+ end
59
+
60
+ Then /^it should (fail|pass)$/ do |success|
61
+ if success == 'fail'
62
+ last_exit_status.should_not == 0
63
+ else
64
+ if last_exit_status != 0
65
+ raise "Failed with exit status #{last_exit_status}\nSTDOUT:\n#{last_stdout}\nSTDERR:\n#{last_stderr}"
66
+ end
67
+ end
68
+ end
69
+
70
+ Then /^it should (fail|pass) with$/ do |success, output|
71
+ last_stdout.should == output
72
+ Then("it should #{success}")
73
+ end
74
+
75
+ Then /^the output should contain$/ do |text|
76
+ last_stdout.should include(text)
77
+ end
78
+
79
+ Then /^the output should not contain$/ do |text|
80
+ last_stdout.should_not include(text)
81
+ end
82
+
83
+ Then /^the output should be$/ do |text|
84
+ last_stdout.should == text
85
+ end
86
+
87
+ Then /^"([^"]*)" should contain$/ do |file, text|
88
+ strip_duration(IO.read(file)).should == text
89
+ end
90
+
91
+ Then /^"([^"]*)" with junit duration "([^"]*)" should contain$/ do |actual_file, duration_replacement, text|
92
+ actual = IO.read(actual_file)
93
+ actual = replace_junit_duration(actual, duration_replacement)
94
+ actual = strip_ruby186_extra_trace(actual)
95
+ actual.should == text
96
+ end
97
+
98
+ Then /^"([^"]*)" should match "([^"]*)"$/ do |file, text|
99
+ File.open(file, Cucumber.file_mode('r')).read.should =~ Regexp.new(text)
100
+ end
101
+
102
+ Then /^"([^"]*)" should have the same contents as "([^"]*)"$/ do |actual_file, expected_file|
103
+ actual = IO.read(actual_file)
104
+ actual = replace_duration(actual, '0m30.005s')
105
+ # Comment out to replace expected file. Use with care!
106
+ # File.open(expected_file, "w") {|io| io.write(actual)}
107
+ actual.should == IO.read(expected_file)
108
+ end
109
+
110
+ Then /^STDERR should match$/ do |text|
111
+ last_stderr.should =~ /#{text}/
112
+ end
113
+
114
+ Then /^STDERR should not match$/ do |text|
115
+ last_stderr.should_not =~ /#{text}/
116
+ end
117
+
118
+ Then /^STDERR should be$/ do |text|
119
+ last_stderr.should == text
120
+ end
121
+
122
+ Then /^STDERR should be empty$/ do
123
+ last_stderr.should == ""
124
+ end
125
+
126
+ Then /^"([^"]*)" should exist$/ do |file|
127
+ File.exists?(file).should be_true
128
+ FileUtils.rm(file)
129
+ end
130
+
131
+ Then /^"([^"]*)" should not be required$/ do |file_name|
132
+ last_stdout.should_not include("* #{file_name}")
133
+ end
134
+
135
+ Then /^"([^"]*)" should be required$/ do |file_name|
136
+ last_stdout.should include("* #{file_name}")
137
+ end
138
+
139
+ Then /^exactly these files should be loaded:\s*(.*)$/ do |files|
140
+ last_stdout.scan(/^ \* (.*\.rb)$/).flatten.should == files.split(/,\s+/)
141
+ end
142
+
143
+ Then /^exactly these features should be ran:\s*(.*)$/ do |files|
144
+ last_stdout.scan(/^ \* (.*\.feature)$/).flatten.should == files.split(/,\s+/)
145
+ end
146
+
147
+ Then /^the (.*) profile should be used$/ do |profile|
148
+ last_stdout.should =~ /Using the #{profile} profile/
149
+ end
150
+
151
+ Then /^print output$/ do
152
+ puts last_stdout
153
+ end
154
+
155
+
@@ -0,0 +1,18 @@
1
+ require 'json'
2
+ Then /^the output should contain "([^"]*)" set to "([^"]*)"$/ do |variable, value|
3
+ Then 'STDERR should be empty'
4
+ output = JSON.parse(last_stdout)
5
+ eval(variable).to_s.should == value
6
+ end
7
+
8
+ Then /^the output should contain the failing feature$/ do |alert|
9
+ Then 'STDERR should be empty'
10
+ output = JSON.parse(last_stdout)
11
+ output['failing_features'].should include(alert)
12
+ end
13
+
14
+ Then /^the output should contain no failing features$/ do
15
+ Then 'STDERR should be empty'
16
+ output = JSON.parse(last_stdout)
17
+ output['failing_features'].should == []
18
+ end
@@ -0,0 +1,143 @@
1
+ require 'rubygems'
2
+ require 'tempfile'
3
+ begin
4
+ require 'rspec/expectations'
5
+ rescue LoadError
6
+ require 'spec/expectations'
7
+ end
8
+ require 'fileutils'
9
+ require 'forwardable'
10
+ require 'cucumber/formatter/unicode'
11
+
12
+ class CucumberWorld
13
+ extend Forwardable
14
+ def_delegators CucumberWorld, :examples_dir, :self_test_dir, :working_dir, :cucumber_lib_dir
15
+
16
+ def self.examples_dir(subdir=nil)
17
+ @examples_dir ||= File.expand_path(File.join(File.dirname(__FILE__), '../../examples'))
18
+ subdir ? File.join(@examples_dir, subdir) : @examples_dir
19
+ end
20
+
21
+ def self.self_test_dir
22
+ @self_test_dir ||= examples_dir('self_test')
23
+ end
24
+
25
+ def self.working_dir
26
+ @working_dir ||= examples_dir('self_test/tmp')
27
+ end
28
+
29
+ def cucumber_lib_dir
30
+ @cucumber_lib_dir ||= File.expand_path(File.join(File.dirname(__FILE__), '../../lib'))
31
+ end
32
+
33
+ def initialize
34
+ @current_dir = self_test_dir
35
+ end
36
+
37
+ private
38
+ attr_reader :last_exit_status, :last_stderr
39
+
40
+ # The last standard out, with the duration line taken out (unpredictable)
41
+ def last_stdout
42
+ strip_1_9_paths(strip_duration(@last_stdout))
43
+ end
44
+
45
+ def strip_duration(s)
46
+ s.gsub(/^\d+m\d+\.\d+s\n/m, "")
47
+ end
48
+
49
+ def strip_1_9_paths(s)
50
+ s.gsub(/#{Dir.pwd}\/examples\/self_test\/tmp/m, ".").gsub(/#{Dir.pwd}\/examples\/self_test/m, ".")
51
+ end
52
+
53
+ def replace_duration(s, replacement)
54
+ s.gsub(/\d+m\d+\.\d+s/m, replacement)
55
+ end
56
+
57
+ def replace_junit_duration(s, replacement)
58
+ s.gsub(/\d+\.\d\d+/m, replacement)
59
+ end
60
+
61
+ def strip_ruby186_extra_trace(s)
62
+ s.gsub(/^.*\.\/features\/step_definitions(.*)\n/, "")
63
+ end
64
+
65
+ def create_file(file_name, file_content)
66
+ file_content.gsub!("CUCUMBER_LIB", "'#{cucumber_lib_dir}'") # Some files, such as Rakefiles need to use the lib dir
67
+ in_current_dir do
68
+ FileUtils.mkdir_p(File.dirname(file_name)) unless File.directory?(File.dirname(file_name))
69
+ File.open(file_name, 'w') { |f| f << file_content }
70
+ end
71
+ end
72
+
73
+ def set_env_var(variable, value)
74
+ @original_env_vars ||= {}
75
+ @original_env_vars[variable] = ENV[variable]
76
+ ENV[variable] = value
77
+ end
78
+
79
+ def background_jobs
80
+ @background_jobs ||= []
81
+ end
82
+
83
+ def in_current_dir(&block)
84
+ Dir.chdir(@current_dir, &block)
85
+ end
86
+
87
+ def run(command)
88
+ stderr_file = Tempfile.new('cucumber')
89
+ stderr_file.close
90
+ in_current_dir do
91
+ mode = Cucumber::RUBY_1_9 ? {:external_encoding=>"UTF-8"} : 'r'
92
+ IO.popen("#{command} 2> #{stderr_file.path}", mode) do |io|
93
+ @last_stdout = io.read
94
+ end
95
+
96
+ @last_exit_status = $?.exitstatus
97
+ end
98
+ @last_stderr = IO.read(stderr_file.path)
99
+ end
100
+
101
+ def run_spork_in_background(port = nil)
102
+ require 'spork'
103
+
104
+ pid = fork
105
+ in_current_dir do
106
+ if pid
107
+ background_jobs << pid
108
+ else
109
+ # STDOUT.close
110
+ # STDERR.close
111
+ port_arg = port ? "-p #{port}" : ''
112
+ cmd = "#{Cucumber::RUBY_BINARY} -I #{Cucumber::LIBDIR} #{Spork::BINARY} cuc #{port_arg}"
113
+ exec cmd
114
+ end
115
+ end
116
+ sleep 1.0
117
+ end
118
+
119
+ def terminate_background_jobs
120
+ background_jobs.each do |pid|
121
+ Process.kill(Signal.list['TERM'], pid)
122
+ end
123
+ end
124
+
125
+ def restore_original_env_vars
126
+ @original_env_vars.each { |variable, value| ENV[variable] = value } if @original_env_vars
127
+ end
128
+
129
+ end
130
+
131
+ World do
132
+ CucumberWorld.new
133
+ end
134
+
135
+ Before do
136
+ FileUtils.rm_rf CucumberWorld.working_dir
137
+ FileUtils.mkdir CucumberWorld.working_dir
138
+ end
139
+
140
+ After do
141
+ terminate_background_jobs
142
+ restore_original_env_vars
143
+ end
@@ -0,0 +1,7 @@
1
+ module Cucumber
2
+ module Formatter
3
+ class JSON
4
+ VERSION = '0.0.1'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,241 @@
1
+ require 'json'
2
+ require 'cucumber/formatter/io'
3
+
4
+ module Cucumber
5
+ module Formatter
6
+ class JSON
7
+ include Io
8
+
9
+ FORMATS = Hash.new{|hash, format| hash[format] = method(format).to_proc}
10
+
11
+ def initialize(step_mother, path_or_io, options)
12
+ @io = ensure_io(path_or_io, "json")
13
+ @options = options
14
+ @status_counts = Hash.new{|h,k| h[k] = 0}
15
+ @indent = 0
16
+ @hash = {}
17
+ end
18
+
19
+ def before_examples(*args)
20
+ @header_row = true
21
+ end
22
+
23
+ def before_feature(feature)
24
+ @exceptions = []
25
+ @indent = 0
26
+ @feature = ''
27
+ end
28
+
29
+ def before_feature_element(feature_element)
30
+ @indent = 2
31
+ @element_exceptions = []
32
+ @feature = ""
33
+ @scenario_indent = 2
34
+ end
35
+
36
+ def before_background(background)
37
+ @indent = 2
38
+ @scenario_indent = 2
39
+ @in_background = true
40
+ end
41
+
42
+ def after_background(background)
43
+ @in_background = nil
44
+ end
45
+
46
+ def background_name(keyword, name, file_colon_line, source_indent)
47
+ print_feature_element_name(keyword, name, file_colon_line, source_indent)
48
+ end
49
+
50
+ def background_name(keyword, name, file_colon_line, source_indent)
51
+ print_feature_element_name(keyword, name, file_colon_line, source_indent)
52
+ end
53
+
54
+ def before_examples_array(examples_array)
55
+ @indent = 4
56
+ @visiting_first_example_name = true
57
+ end
58
+
59
+ def examples_name(keyword, name)
60
+ @feature << "\n" unless @visiting_first_example_name
61
+ @visiting_first_example_name = false
62
+ names = name.strip.empty? ? [name.strip] : name.split("\n")
63
+ @feature << " #{keyword}: #{names[0]}\n"
64
+ names[1..-1].each {|s| @feature << " #{s}\n" } unless names.empty?
65
+ @indent = 6
66
+ @scenario_indent = 6
67
+ end
68
+
69
+ def before_outline_table(outline_table)
70
+ @table = outline_table
71
+ end
72
+
73
+ def after_outline_table(outline_table)
74
+ @table = nil
75
+ @indent = 4
76
+ end
77
+
78
+ def scenario_name(keyword, name, file_colon_line, source_indent)
79
+ print_feature_element_name(keyword, name, file_colon_line, source_indent)
80
+ end
81
+
82
+ def before_step(step)
83
+ @current_step = step
84
+ @indent = 6
85
+ end
86
+
87
+ def before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
88
+ @hide_this_step = false
89
+ if exception
90
+ if @exceptions.include?(exception)
91
+ @hide_this_step = true
92
+ return
93
+ end
94
+ @element_exceptions << exception
95
+ @exceptions << exception
96
+ end
97
+ if status != :failed && @in_background ^ background
98
+ @hide_this_step = true
99
+ return
100
+ end
101
+ @status = status
102
+ end
103
+
104
+ def step_name(keyword, step_match, status, source_indent, background)
105
+ return if @hide_this_step
106
+ source_indent = nil unless @options[:source]
107
+ name_to_report = format_step(keyword, step_match, status, source_indent)
108
+ @feature << name_to_report.indent(@scenario_indent + 2)
109
+ @feature << "\n"
110
+ end
111
+
112
+ def py_string(string)
113
+ return if @hide_this_step
114
+ s = %{"""\n#{string}\n"""}.indent(@indent)
115
+ s = s.split("\n").map{|l| l =~ /^\s+$/ ? '' : l}.join("\n")
116
+ @feature << format_string(s, @current_step.status)
117
+ @feature << "\n"
118
+ end
119
+
120
+ def exception(exception, status)
121
+ return if @hide_this_step
122
+ print_exception(exception, status, @indent)
123
+ end
124
+
125
+ def before_multiline_arg(multiline_arg)
126
+ return if @options[:no_multiline] || @hide_this_step
127
+ @table = multiline_arg
128
+ end
129
+
130
+ def after_multiline_arg(multiline_arg)
131
+ @table = nil
132
+ end
133
+
134
+ def before_table_row(table_row)
135
+ return if !@table || @hide_this_step
136
+ @col_index = 0
137
+ @feature << ' |'.indent(@indent-2)
138
+ end
139
+
140
+ def after_table_cell(cell)
141
+ return unless @table
142
+ @col_index += 1
143
+ end
144
+
145
+ def table_cell_value(value, status)
146
+ return if !@table || @hide_this_step
147
+ status ||= @status || :passed
148
+ width = @table.col_width(@col_index)
149
+ cell_text = value.to_s || ''
150
+ padded = cell_text + (' ' * (width - cell_text.jlength))
151
+ prefix = cell_prefix(status)
152
+ @feature << ' ' + format_string("#{prefix}#{padded}", status) + ::Term::ANSIColor.reset(" |")
153
+ @feature << "\n"
154
+ end
155
+
156
+ # mine
157
+
158
+ def after_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
159
+ record_result(status, :step_match => step_match)
160
+ end
161
+
162
+ def after_table_row(table_row)
163
+ unless @header_row
164
+ record_result(table_row.status) if table_row.respond_to?(:status)
165
+ end
166
+ @header_row = false if @header_row
167
+ return if !@table || @hide_this_step
168
+ print_table_row_announcements
169
+ @feature << "\n"
170
+ if table_row.exception && !@exceptions.include?(table_row.exception)
171
+ print_exception(table_row.exception, table_row.status, @indent)
172
+ end
173
+ end
174
+
175
+ def after_features(steps)
176
+ @hash[:status_counts] = @status_counts
177
+ @io.print(@hash.to_json)
178
+ @io.flush
179
+ @io.close
180
+ end
181
+
182
+ def after_feature_element(element)
183
+ @hash[:features] ||= []
184
+ @hash[:features] << @feature
185
+ @hash[:failing_features] ||= []
186
+ if @element_exceptions.size > 0
187
+ @hash[:failing_features] << @feature
188
+ end
189
+ @feature = ''
190
+ end
191
+
192
+ private
193
+
194
+ def record_result(status, opts={})
195
+ step_match = opts[:step_match] || true
196
+ @status_counts[status] = @status_counts[status] + 1
197
+ end
198
+
199
+ def print_feature_element_name(keyword, name, file_colon_line, source_indent)
200
+ @feature << "\n" if @scenario_indent == 6
201
+ names = name.empty? ? [name] : name.split("\n")
202
+ line = "#{keyword}: #{names[0]}".indent(@scenario_indent)
203
+ @feature << line
204
+ @feature << "\n"
205
+ names[1..-1].each {|s| @feature << " #{s}\n"}
206
+ end
207
+
208
+ def print_exception(e, status, indent)
209
+ @feature << format_string("#{e.message} (#{e.class})\n#{e.backtrace.join("\n")}".indent(indent), status)
210
+ @feature << "\n"
211
+ end
212
+
213
+ def cell_prefix(status)
214
+ @prefixes[status]
215
+ end
216
+
217
+ def format_string(string, status)
218
+ string
219
+ end
220
+
221
+ def format_step(keyword, step_match, status, source_indent)
222
+ comment = if source_indent
223
+ c = (' # ' + step_match.file_colon_line).indent(source_indent)
224
+ format_string(c, :comment)
225
+ else
226
+ ''
227
+ end
228
+
229
+ if status == :passed
230
+ line = keyword + ' ' + step_match.format_args("%s")
231
+ format_string(line, status)
232
+ else
233
+ line = keyword + ' ' + step_match.format_args("%s") + comment
234
+ format_string(line, status)
235
+ end
236
+ end
237
+
238
+ end
239
+ end
240
+ end
241
+ require "#{File.dirname(__FILE__)}/json/version"
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cucumber-json
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Jesse Newland
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-05-19 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: cucumber
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ - 6
30
+ - 3
31
+ version: 0.6.3
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: json
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 1
43
+ - 2
44
+ - 1
45
+ version: 1.2.1
46
+ type: :runtime
47
+ version_requirements: *id002
48
+ description: A cucumber formatter that outputs JSON
49
+ email: jnewland@gmail.com
50
+ executables: []
51
+
52
+ extensions: []
53
+
54
+ extra_rdoc_files:
55
+ - LICENSE
56
+ files:
57
+ - .gitignore
58
+ - LICENSE
59
+ - Rakefile
60
+ - Readme.md
61
+ - cucumber-json.gemspec
62
+ - examples/features.json
63
+ - features/formatter.feature
64
+ - features/step_definitions/cucumber_steps.rb
65
+ - features/step_definitions/custom_steps.rb
66
+ - features/support/env.rb
67
+ - lib/cucumber/formatter/json.rb
68
+ - lib/cucumber/formatter/json/version.rb
69
+ has_rdoc: true
70
+ homepage: http://github.com/jnewland/cucumber-json
71
+ licenses: []
72
+
73
+ post_install_message:
74
+ rdoc_options:
75
+ - --charset=UTF-8
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ segments:
83
+ - 0
84
+ version: "0"
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ segments:
90
+ - 0
91
+ version: "0"
92
+ requirements: []
93
+
94
+ rubyforge_project:
95
+ rubygems_version: 1.3.6
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: A cucumber formatter that outputs JSON
99
+ test_files:
100
+ - features/formatter.feature
101
+ - features/step_definitions/cucumber_steps.rb
102
+ - features/step_definitions/custom_steps.rb
103
+ - features/support/env.rb