cucumber-json 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,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