sspec-core 3.8.0
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.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.yardopts +8 -0
- data/Changelog.md +2232 -0
- data/LICENSE.md +26 -0
- data/README.md +384 -0
- data/exe/rspec +4 -0
- data/lib/rspec/autorun.rb +3 -0
- data/lib/rspec/core.rb +185 -0
- data/lib/rspec/core/backtrace_formatter.rb +65 -0
- data/lib/rspec/core/bisect/coordinator.rb +62 -0
- data/lib/rspec/core/bisect/example_minimizer.rb +173 -0
- data/lib/rspec/core/bisect/fork_runner.rb +134 -0
- data/lib/rspec/core/bisect/server.rb +61 -0
- data/lib/rspec/core/bisect/shell_command.rb +126 -0
- data/lib/rspec/core/bisect/shell_runner.rb +73 -0
- data/lib/rspec/core/bisect/utilities.rb +58 -0
- data/lib/rspec/core/configuration.rb +2289 -0
- data/lib/rspec/core/configuration_options.rb +233 -0
- data/lib/rspec/core/drb.rb +113 -0
- data/lib/rspec/core/dsl.rb +98 -0
- data/lib/rspec/core/example.rb +653 -0
- data/lib/rspec/core/example_group.rb +885 -0
- data/lib/rspec/core/example_status_persister.rb +235 -0
- data/lib/rspec/core/filter_manager.rb +231 -0
- data/lib/rspec/core/flat_map.rb +20 -0
- data/lib/rspec/core/formatters.rb +269 -0
- data/lib/rspec/core/formatters/base_bisect_formatter.rb +45 -0
- data/lib/rspec/core/formatters/base_formatter.rb +70 -0
- data/lib/rspec/core/formatters/base_text_formatter.rb +75 -0
- data/lib/rspec/core/formatters/bisect_drb_formatter.rb +29 -0
- data/lib/rspec/core/formatters/bisect_progress_formatter.rb +157 -0
- data/lib/rspec/core/formatters/console_codes.rb +68 -0
- data/lib/rspec/core/formatters/deprecation_formatter.rb +223 -0
- data/lib/rspec/core/formatters/documentation_formatter.rb +70 -0
- data/lib/rspec/core/formatters/exception_presenter.rb +508 -0
- data/lib/rspec/core/formatters/fallback_message_formatter.rb +28 -0
- data/lib/rspec/core/formatters/helpers.rb +110 -0
- data/lib/rspec/core/formatters/html_formatter.rb +153 -0
- data/lib/rspec/core/formatters/html_printer.rb +414 -0
- data/lib/rspec/core/formatters/html_snippet_extractor.rb +120 -0
- data/lib/rspec/core/formatters/json_formatter.rb +102 -0
- data/lib/rspec/core/formatters/profile_formatter.rb +68 -0
- data/lib/rspec/core/formatters/progress_formatter.rb +29 -0
- data/lib/rspec/core/formatters/protocol.rb +182 -0
- data/lib/rspec/core/formatters/snippet_extractor.rb +134 -0
- data/lib/rspec/core/formatters/syntax_highlighter.rb +91 -0
- data/lib/rspec/core/hooks.rb +624 -0
- data/lib/rspec/core/invocations.rb +87 -0
- data/lib/rspec/core/memoized_helpers.rb +554 -0
- data/lib/rspec/core/metadata.rb +499 -0
- data/lib/rspec/core/metadata_filter.rb +255 -0
- data/lib/rspec/core/minitest_assertions_adapter.rb +31 -0
- data/lib/rspec/core/mocking_adapters/flexmock.rb +31 -0
- data/lib/rspec/core/mocking_adapters/mocha.rb +57 -0
- data/lib/rspec/core/mocking_adapters/null.rb +14 -0
- data/lib/rspec/core/mocking_adapters/rr.rb +31 -0
- data/lib/rspec/core/mocking_adapters/rspec.rb +32 -0
- data/lib/rspec/core/notifications.rb +521 -0
- data/lib/rspec/core/option_parser.rb +309 -0
- data/lib/rspec/core/ordering.rb +158 -0
- data/lib/rspec/core/output_wrapper.rb +29 -0
- data/lib/rspec/core/pending.rb +165 -0
- data/lib/rspec/core/profiler.rb +34 -0
- data/lib/rspec/core/project_initializer.rb +48 -0
- data/lib/rspec/core/project_initializer/.rspec +1 -0
- data/lib/rspec/core/project_initializer/spec/spec_helper.rb +100 -0
- data/lib/rspec/core/rake_task.rb +168 -0
- data/lib/rspec/core/reporter.rb +257 -0
- data/lib/rspec/core/ruby_project.rb +53 -0
- data/lib/rspec/core/runner.rb +199 -0
- data/lib/rspec/core/sandbox.rb +37 -0
- data/lib/rspec/core/set.rb +54 -0
- data/lib/rspec/core/shared_context.rb +55 -0
- data/lib/rspec/core/shared_example_group.rb +269 -0
- data/lib/rspec/core/shell_escape.rb +49 -0
- data/lib/rspec/core/test_unit_assertions_adapter.rb +30 -0
- data/lib/rspec/core/version.rb +9 -0
- data/lib/rspec/core/warnings.rb +40 -0
- data/lib/rspec/core/world.rb +275 -0
- metadata +257 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Core
|
3
|
+
module Formatters
|
4
|
+
# @api private
|
5
|
+
# Formatter for providing message output as a fallback when no other
|
6
|
+
# profiler implements #message
|
7
|
+
class FallbackMessageFormatter
|
8
|
+
Formatters.register self, :message
|
9
|
+
|
10
|
+
def initialize(output)
|
11
|
+
@output = output
|
12
|
+
end
|
13
|
+
|
14
|
+
# @private
|
15
|
+
attr_reader :output
|
16
|
+
|
17
|
+
# @api public
|
18
|
+
#
|
19
|
+
# Used by the reporter to send messages to the output stream.
|
20
|
+
#
|
21
|
+
# @param notification [MessageNotification] containing message
|
22
|
+
def message(notification)
|
23
|
+
output.puts notification.message
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
RSpec::Support.require_rspec_core "shell_escape"
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Core
|
5
|
+
module Formatters
|
6
|
+
# Formatters helpers.
|
7
|
+
module Helpers
|
8
|
+
# @private
|
9
|
+
SUB_SECOND_PRECISION = 5
|
10
|
+
|
11
|
+
# @private
|
12
|
+
DEFAULT_PRECISION = 2
|
13
|
+
|
14
|
+
# @api private
|
15
|
+
#
|
16
|
+
# Formats seconds into a human-readable string.
|
17
|
+
#
|
18
|
+
# @param duration [Float, Fixnum] in seconds
|
19
|
+
# @return [String] human-readable time
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# format_duration(1) #=> "1 minute 1 second"
|
23
|
+
# format_duration(135.14) #=> "2 minutes 15.14 seconds"
|
24
|
+
def self.format_duration(duration)
|
25
|
+
precision = case
|
26
|
+
when duration < 1 then SUB_SECOND_PRECISION
|
27
|
+
when duration < 120 then DEFAULT_PRECISION
|
28
|
+
when duration < 300 then 1
|
29
|
+
else 0
|
30
|
+
end
|
31
|
+
|
32
|
+
if duration > 60
|
33
|
+
minutes = (duration.round / 60).to_i
|
34
|
+
seconds = (duration - minutes * 60)
|
35
|
+
|
36
|
+
"#{pluralize(minutes, 'minute')} #{pluralize(format_seconds(seconds, precision), 'second')}"
|
37
|
+
else
|
38
|
+
pluralize(format_seconds(duration, precision), 'second')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# @api private
|
43
|
+
#
|
44
|
+
# Formats seconds to have 5 digits of precision with trailing zeros
|
45
|
+
# removed if the number is less than 1 or with 2 digits of precision if
|
46
|
+
# the number is greater than zero.
|
47
|
+
#
|
48
|
+
# @param float [Float]
|
49
|
+
# @return [String] formatted float
|
50
|
+
#
|
51
|
+
# @example
|
52
|
+
# format_seconds(0.000006) #=> "0.00001"
|
53
|
+
# format_seconds(0.020000) #=> "0.02"
|
54
|
+
# format_seconds(1.00000000001) #=> "1"
|
55
|
+
#
|
56
|
+
# The precision used is set in {Helpers::SUB_SECOND_PRECISION} and
|
57
|
+
# {Helpers::DEFAULT_PRECISION}.
|
58
|
+
#
|
59
|
+
# @see #strip_trailing_zeroes
|
60
|
+
def self.format_seconds(float, precision=nil)
|
61
|
+
return '0' if float < 0
|
62
|
+
precision ||= (float < 1) ? SUB_SECOND_PRECISION : DEFAULT_PRECISION
|
63
|
+
formatted = "%.#{precision}f" % float
|
64
|
+
strip_trailing_zeroes(formatted)
|
65
|
+
end
|
66
|
+
|
67
|
+
# @api private
|
68
|
+
#
|
69
|
+
# Remove trailing zeros from a string.
|
70
|
+
#
|
71
|
+
# Only remove trailing zeros after a decimal place.
|
72
|
+
# see: http://rubular.com/r/ojtTydOgpn
|
73
|
+
#
|
74
|
+
# @param string [String] string with trailing zeros
|
75
|
+
# @return [String] string with trailing zeros removed
|
76
|
+
def self.strip_trailing_zeroes(string)
|
77
|
+
string.sub(/(?:(\..*[^0])0+|\.0+)$/, '\1')
|
78
|
+
end
|
79
|
+
private_class_method :strip_trailing_zeroes
|
80
|
+
|
81
|
+
# @api private
|
82
|
+
#
|
83
|
+
# Pluralize a word based on a count.
|
84
|
+
#
|
85
|
+
# @param count [Fixnum] number of objects
|
86
|
+
# @param string [String] word to be pluralized
|
87
|
+
# @return [String] pluralized word
|
88
|
+
def self.pluralize(count, string)
|
89
|
+
"#{count} #{string}#{'s' unless count.to_f == 1}"
|
90
|
+
end
|
91
|
+
|
92
|
+
# @api private
|
93
|
+
# Given a list of example ids, organizes them into a compact, ordered list.
|
94
|
+
def self.organize_ids(ids)
|
95
|
+
grouped = ids.inject(Hash.new { |h, k| h[k] = [] }) do |hash, id|
|
96
|
+
file, id = Example.parse_id(id)
|
97
|
+
hash[file] << id
|
98
|
+
hash
|
99
|
+
end
|
100
|
+
|
101
|
+
grouped.sort_by(&:first).map do |file, grouped_ids|
|
102
|
+
grouped_ids = grouped_ids.sort_by { |id| id.split(':').map(&:to_i) }
|
103
|
+
id = Metadata.id_from(:rerun_file_path => file, :scoped_id => grouped_ids.join(','))
|
104
|
+
ShellEscape.conditionally_quote(id)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
RSpec::Support.require_rspec_core "formatters/base_text_formatter"
|
2
|
+
RSpec::Support.require_rspec_core "formatters/html_printer"
|
3
|
+
|
4
|
+
module RSpec
|
5
|
+
module Core
|
6
|
+
module Formatters
|
7
|
+
# @private
|
8
|
+
class HtmlFormatter < BaseFormatter
|
9
|
+
Formatters.register self, :start, :example_group_started, :start_dump,
|
10
|
+
:example_started, :example_passed, :example_failed,
|
11
|
+
:example_pending, :dump_summary
|
12
|
+
|
13
|
+
def initialize(output)
|
14
|
+
super(output)
|
15
|
+
@failed_examples = []
|
16
|
+
@example_group_number = 0
|
17
|
+
@example_number = 0
|
18
|
+
@header_red = nil
|
19
|
+
@printer = HtmlPrinter.new(output)
|
20
|
+
end
|
21
|
+
|
22
|
+
def start(notification)
|
23
|
+
super
|
24
|
+
@printer.print_html_start
|
25
|
+
@printer.flush
|
26
|
+
end
|
27
|
+
|
28
|
+
def example_group_started(notification)
|
29
|
+
super
|
30
|
+
@example_group_red = false
|
31
|
+
@example_group_number += 1
|
32
|
+
|
33
|
+
@printer.print_example_group_end unless example_group_number == 1
|
34
|
+
@printer.print_example_group_start(example_group_number,
|
35
|
+
notification.group.description,
|
36
|
+
notification.group.parent_groups.size)
|
37
|
+
@printer.flush
|
38
|
+
end
|
39
|
+
|
40
|
+
def start_dump(_notification)
|
41
|
+
@printer.print_example_group_end
|
42
|
+
@printer.flush
|
43
|
+
end
|
44
|
+
|
45
|
+
def example_started(_notification)
|
46
|
+
@example_number += 1
|
47
|
+
end
|
48
|
+
|
49
|
+
def example_passed(passed)
|
50
|
+
@printer.move_progress(percent_done)
|
51
|
+
@printer.print_example_passed(passed.example.description, passed.example.execution_result.run_time)
|
52
|
+
@printer.flush
|
53
|
+
end
|
54
|
+
|
55
|
+
def example_failed(failure)
|
56
|
+
@failed_examples << failure.example
|
57
|
+
unless @header_red
|
58
|
+
@header_red = true
|
59
|
+
@printer.make_header_red
|
60
|
+
end
|
61
|
+
|
62
|
+
unless @example_group_red
|
63
|
+
@example_group_red = true
|
64
|
+
@printer.make_example_group_header_red(example_group_number)
|
65
|
+
end
|
66
|
+
|
67
|
+
@printer.move_progress(percent_done)
|
68
|
+
|
69
|
+
example = failure.example
|
70
|
+
|
71
|
+
exception = failure.exception
|
72
|
+
message_lines = failure.fully_formatted_lines(nil, RSpec::Core::Notifications::NullColorizer)
|
73
|
+
exception_details = if exception
|
74
|
+
{
|
75
|
+
# drop 2 removes the description (regardless of newlines) and leading blank line
|
76
|
+
:message => message_lines.drop(2).join("\n"),
|
77
|
+
:backtrace => failure.formatted_backtrace.join("\n"),
|
78
|
+
}
|
79
|
+
end
|
80
|
+
extra = extra_failure_content(failure)
|
81
|
+
|
82
|
+
@printer.print_example_failed(
|
83
|
+
example.execution_result.pending_fixed,
|
84
|
+
example.description,
|
85
|
+
example.execution_result.run_time,
|
86
|
+
@failed_examples.size,
|
87
|
+
exception_details,
|
88
|
+
(extra == "") ? false : extra
|
89
|
+
)
|
90
|
+
@printer.flush
|
91
|
+
end
|
92
|
+
|
93
|
+
def example_pending(pending)
|
94
|
+
example = pending.example
|
95
|
+
|
96
|
+
@printer.make_header_yellow unless @header_red
|
97
|
+
@printer.make_example_group_header_yellow(example_group_number) unless @example_group_red
|
98
|
+
@printer.move_progress(percent_done)
|
99
|
+
@printer.print_example_pending(example.description, example.execution_result.pending_message)
|
100
|
+
@printer.flush
|
101
|
+
end
|
102
|
+
|
103
|
+
def dump_summary(summary)
|
104
|
+
@printer.print_summary(
|
105
|
+
summary.duration,
|
106
|
+
summary.example_count,
|
107
|
+
summary.failure_count,
|
108
|
+
summary.pending_count
|
109
|
+
)
|
110
|
+
@printer.flush
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
# If these methods are declared with attr_reader Ruby will issue a
|
116
|
+
# warning because they are private.
|
117
|
+
# rubocop:disable Style/TrivialAccessors
|
118
|
+
|
119
|
+
# The number of the currently running example_group.
|
120
|
+
def example_group_number
|
121
|
+
@example_group_number
|
122
|
+
end
|
123
|
+
|
124
|
+
# The number of the currently running example (a global counter).
|
125
|
+
def example_number
|
126
|
+
@example_number
|
127
|
+
end
|
128
|
+
# rubocop:enable Style/TrivialAccessors
|
129
|
+
|
130
|
+
def percent_done
|
131
|
+
result = 100.0
|
132
|
+
if @example_count > 0
|
133
|
+
result = (((example_number).to_f / @example_count.to_f * 1000).to_i / 10.0).to_f
|
134
|
+
end
|
135
|
+
result
|
136
|
+
end
|
137
|
+
|
138
|
+
# Override this method if you wish to output extra HTML for a failed
|
139
|
+
# spec. For example, you could output links to images or other files
|
140
|
+
# produced during the specs.
|
141
|
+
def extra_failure_content(failure)
|
142
|
+
RSpec::Support.require_rspec_core "formatters/html_snippet_extractor"
|
143
|
+
backtrace = (failure.exception.backtrace || []).map do |line|
|
144
|
+
RSpec.configuration.backtrace_formatter.backtrace_line(line)
|
145
|
+
end
|
146
|
+
backtrace.compact!
|
147
|
+
@snippet_extractor ||= HtmlSnippetExtractor.new
|
148
|
+
" <pre class=\"ruby\"><code>#{@snippet_extractor.snippet(backtrace)}</code></pre>"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,414 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Core
|
5
|
+
module Formatters
|
6
|
+
# @private
|
7
|
+
class HtmlPrinter
|
8
|
+
include ERB::Util # For the #h method.
|
9
|
+
def initialize(output)
|
10
|
+
@output = output
|
11
|
+
end
|
12
|
+
|
13
|
+
def print_html_start
|
14
|
+
@output.puts HTML_HEADER
|
15
|
+
@output.puts REPORT_HEADER
|
16
|
+
end
|
17
|
+
|
18
|
+
def print_example_group_end
|
19
|
+
@output.puts " </dl>"
|
20
|
+
@output.puts "</div>"
|
21
|
+
end
|
22
|
+
|
23
|
+
def print_example_group_start(group_id, description, number_of_parents)
|
24
|
+
@output.puts "<div id=\"div_group_#{group_id}\" class=\"example_group passed\">"
|
25
|
+
@output.puts " <dl #{indentation_style(number_of_parents)}>"
|
26
|
+
@output.puts " <dt id=\"example_group_#{group_id}\" class=\"passed\">#{h(description)}</dt>"
|
27
|
+
end
|
28
|
+
|
29
|
+
def print_example_passed(description, run_time)
|
30
|
+
formatted_run_time = "%.5f" % run_time
|
31
|
+
@output.puts " <dd class=\"example passed\">" \
|
32
|
+
"<span class=\"passed_spec_name\">#{h(description)}</span>" \
|
33
|
+
"<span class='duration'>#{formatted_run_time}s</span></dd>"
|
34
|
+
end
|
35
|
+
|
36
|
+
# rubocop:disable Metrics/ParameterLists
|
37
|
+
def print_example_failed(pending_fixed, description, run_time, failure_id,
|
38
|
+
exception, extra_content)
|
39
|
+
# rubocop:enable Metrics/ParameterLists
|
40
|
+
formatted_run_time = "%.5f" % run_time
|
41
|
+
|
42
|
+
@output.puts " <dd class=\"example #{pending_fixed ? 'pending_fixed' : 'failed'}\">"
|
43
|
+
@output.puts " <span class=\"failed_spec_name\">#{h(description)}</span>"
|
44
|
+
@output.puts " <span class=\"duration\">#{formatted_run_time}s</span>"
|
45
|
+
@output.puts " <div class=\"failure\" id=\"failure_#{failure_id}\">"
|
46
|
+
if exception
|
47
|
+
@output.puts " <div class=\"message\"><pre>#{h(exception[:message])}</pre></div>"
|
48
|
+
@output.puts " <div class=\"backtrace\"><pre>#{h exception[:backtrace]}</pre></div>"
|
49
|
+
end
|
50
|
+
@output.puts extra_content if extra_content
|
51
|
+
@output.puts " </div>"
|
52
|
+
@output.puts " </dd>"
|
53
|
+
end
|
54
|
+
|
55
|
+
def print_example_pending(description, pending_message)
|
56
|
+
@output.puts " <dd class=\"example not_implemented\">" \
|
57
|
+
"<span class=\"not_implemented_spec_name\">#{h(description)} " \
|
58
|
+
"(PENDING: #{h(pending_message)})</span></dd>"
|
59
|
+
end
|
60
|
+
|
61
|
+
def print_summary(duration, example_count, failure_count, pending_count)
|
62
|
+
totals = String.new(
|
63
|
+
"#{example_count} example#{'s' unless example_count == 1}, "
|
64
|
+
)
|
65
|
+
totals << "#{failure_count} failure#{'s' unless failure_count == 1}"
|
66
|
+
totals << ", #{pending_count} pending" if pending_count > 0
|
67
|
+
|
68
|
+
formatted_duration = "%.5f" % duration
|
69
|
+
|
70
|
+
@output.puts "<script type=\"text/javascript\">" \
|
71
|
+
"document.getElementById('duration').innerHTML = \"Finished in " \
|
72
|
+
"<strong>#{formatted_duration} seconds</strong>\";</script>"
|
73
|
+
@output.puts "<script type=\"text/javascript\">" \
|
74
|
+
"document.getElementById('totals').innerHTML = \"#{totals}\";</script>"
|
75
|
+
@output.puts "</div>"
|
76
|
+
@output.puts "</div>"
|
77
|
+
@output.puts "</body>"
|
78
|
+
@output.puts "</html>"
|
79
|
+
end
|
80
|
+
|
81
|
+
def flush
|
82
|
+
@output.flush
|
83
|
+
end
|
84
|
+
|
85
|
+
def move_progress(percent_done)
|
86
|
+
@output.puts " <script type=\"text/javascript\">moveProgressBar('#{percent_done}');</script>"
|
87
|
+
@output.flush
|
88
|
+
end
|
89
|
+
|
90
|
+
def make_header_red
|
91
|
+
@output.puts " <script type=\"text/javascript\">makeRed('rspec-header');</script>"
|
92
|
+
end
|
93
|
+
|
94
|
+
def make_header_yellow
|
95
|
+
@output.puts " <script type=\"text/javascript\">makeYellow('rspec-header');</script>"
|
96
|
+
end
|
97
|
+
|
98
|
+
def make_example_group_header_red(group_id)
|
99
|
+
@output.puts " <script type=\"text/javascript\">" \
|
100
|
+
"makeRed('div_group_#{group_id}');</script>"
|
101
|
+
@output.puts " <script type=\"text/javascript\">" \
|
102
|
+
"makeRed('example_group_#{group_id}');</script>"
|
103
|
+
end
|
104
|
+
|
105
|
+
def make_example_group_header_yellow(group_id)
|
106
|
+
@output.puts " <script type=\"text/javascript\">" \
|
107
|
+
"makeYellow('div_group_#{group_id}');</script>"
|
108
|
+
@output.puts " <script type=\"text/javascript\">" \
|
109
|
+
"makeYellow('example_group_#{group_id}');</script>"
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def indentation_style(number_of_parents)
|
115
|
+
"style=\"margin-left: #{(number_of_parents - 1) * 15}px;\""
|
116
|
+
end
|
117
|
+
|
118
|
+
REPORT_HEADER = <<-EOF
|
119
|
+
<div class="rspec-report">
|
120
|
+
|
121
|
+
<div id="rspec-header">
|
122
|
+
<div id="label">
|
123
|
+
<h1>RSpec Code Examples</h1>
|
124
|
+
</div>
|
125
|
+
|
126
|
+
<div id="display-filters">
|
127
|
+
<input id="passed_checkbox" name="passed_checkbox" type="checkbox" checked="checked" onchange="apply_filters()" value="1" /> <label for="passed_checkbox">Passed</label>
|
128
|
+
<input id="failed_checkbox" name="failed_checkbox" type="checkbox" checked="checked" onchange="apply_filters()" value="2" /> <label for="failed_checkbox">Failed</label>
|
129
|
+
<input id="pending_checkbox" name="pending_checkbox" type="checkbox" checked="checked" onchange="apply_filters()" value="3" /> <label for="pending_checkbox">Pending</label>
|
130
|
+
</div>
|
131
|
+
|
132
|
+
<div id="summary">
|
133
|
+
<p id="totals"> </p>
|
134
|
+
<p id="duration"> </p>
|
135
|
+
</div>
|
136
|
+
</div>
|
137
|
+
|
138
|
+
|
139
|
+
<div class="results">
|
140
|
+
EOF
|
141
|
+
|
142
|
+
GLOBAL_SCRIPTS = <<-EOF
|
143
|
+
|
144
|
+
function addClass(element_id, classname) {
|
145
|
+
document.getElementById(element_id).className += (" " + classname);
|
146
|
+
}
|
147
|
+
|
148
|
+
function removeClass(element_id, classname) {
|
149
|
+
var elem = document.getElementById(element_id);
|
150
|
+
var classlist = elem.className.replace(classname,'');
|
151
|
+
elem.className = classlist;
|
152
|
+
}
|
153
|
+
|
154
|
+
function moveProgressBar(percentDone) {
|
155
|
+
document.getElementById("rspec-header").style.width = percentDone +"%";
|
156
|
+
}
|
157
|
+
|
158
|
+
function makeRed(element_id) {
|
159
|
+
removeClass(element_id, 'passed');
|
160
|
+
removeClass(element_id, 'not_implemented');
|
161
|
+
addClass(element_id,'failed');
|
162
|
+
}
|
163
|
+
|
164
|
+
function makeYellow(element_id) {
|
165
|
+
var elem = document.getElementById(element_id);
|
166
|
+
if (elem.className.indexOf("failed") == -1) { // class doesn't includes failed
|
167
|
+
if (elem.className.indexOf("not_implemented") == -1) { // class doesn't include not_implemented
|
168
|
+
removeClass(element_id, 'passed');
|
169
|
+
addClass(element_id,'not_implemented');
|
170
|
+
}
|
171
|
+
}
|
172
|
+
}
|
173
|
+
|
174
|
+
function apply_filters() {
|
175
|
+
var passed_filter = document.getElementById('passed_checkbox').checked;
|
176
|
+
var failed_filter = document.getElementById('failed_checkbox').checked;
|
177
|
+
var pending_filter = document.getElementById('pending_checkbox').checked;
|
178
|
+
|
179
|
+
assign_display_style("example passed", passed_filter);
|
180
|
+
assign_display_style("example failed", failed_filter);
|
181
|
+
assign_display_style("example not_implemented", pending_filter);
|
182
|
+
|
183
|
+
assign_display_style_for_group("example_group passed", passed_filter);
|
184
|
+
assign_display_style_for_group("example_group not_implemented", pending_filter, pending_filter || passed_filter);
|
185
|
+
assign_display_style_for_group("example_group failed", failed_filter, failed_filter || pending_filter || passed_filter);
|
186
|
+
}
|
187
|
+
|
188
|
+
function get_display_style(display_flag) {
|
189
|
+
var style_mode = 'none';
|
190
|
+
if (display_flag == true) {
|
191
|
+
style_mode = 'block';
|
192
|
+
}
|
193
|
+
return style_mode;
|
194
|
+
}
|
195
|
+
|
196
|
+
function assign_display_style(classname, display_flag) {
|
197
|
+
var style_mode = get_display_style(display_flag);
|
198
|
+
var elems = document.getElementsByClassName(classname)
|
199
|
+
for (var i=0; i<elems.length;i++) {
|
200
|
+
elems[i].style.display = style_mode;
|
201
|
+
}
|
202
|
+
}
|
203
|
+
|
204
|
+
function assign_display_style_for_group(classname, display_flag, subgroup_flag) {
|
205
|
+
var display_style_mode = get_display_style(display_flag);
|
206
|
+
var subgroup_style_mode = get_display_style(subgroup_flag);
|
207
|
+
var elems = document.getElementsByClassName(classname)
|
208
|
+
for (var i=0; i<elems.length;i++) {
|
209
|
+
var style_mode = display_style_mode;
|
210
|
+
if ((display_flag != subgroup_flag) && (elems[i].getElementsByTagName('dt')[0].innerHTML.indexOf(", ") != -1)) {
|
211
|
+
elems[i].style.display = subgroup_style_mode;
|
212
|
+
} else {
|
213
|
+
elems[i].style.display = display_style_mode;
|
214
|
+
}
|
215
|
+
}
|
216
|
+
}
|
217
|
+
EOF
|
218
|
+
# rubocop:enable LineLength
|
219
|
+
|
220
|
+
GLOBAL_STYLES = <<-EOF
|
221
|
+
#rspec-header {
|
222
|
+
background: #65C400; color: #fff; height: 4em;
|
223
|
+
}
|
224
|
+
|
225
|
+
.rspec-report h1 {
|
226
|
+
margin: 0px 10px 0px 10px;
|
227
|
+
padding: 10px;
|
228
|
+
font-family: "Lucida Grande", Helvetica, sans-serif;
|
229
|
+
font-size: 1.8em;
|
230
|
+
position: absolute;
|
231
|
+
}
|
232
|
+
|
233
|
+
#label {
|
234
|
+
float:left;
|
235
|
+
}
|
236
|
+
|
237
|
+
#display-filters {
|
238
|
+
float:left;
|
239
|
+
padding: 28px 0 0 40%;
|
240
|
+
font-family: "Lucida Grande", Helvetica, sans-serif;
|
241
|
+
}
|
242
|
+
|
243
|
+
#summary {
|
244
|
+
float:right;
|
245
|
+
padding: 5px 10px;
|
246
|
+
font-family: "Lucida Grande", Helvetica, sans-serif;
|
247
|
+
text-align: right;
|
248
|
+
}
|
249
|
+
|
250
|
+
#summary p {
|
251
|
+
margin: 0 0 0 2px;
|
252
|
+
}
|
253
|
+
|
254
|
+
#summary #totals {
|
255
|
+
font-size: 1.2em;
|
256
|
+
}
|
257
|
+
|
258
|
+
.example_group {
|
259
|
+
margin: 0 10px 5px;
|
260
|
+
background: #fff;
|
261
|
+
}
|
262
|
+
|
263
|
+
dl {
|
264
|
+
margin: 0; padding: 0 0 5px;
|
265
|
+
font: normal 11px "Lucida Grande", Helvetica, sans-serif;
|
266
|
+
}
|
267
|
+
|
268
|
+
dt {
|
269
|
+
padding: 3px;
|
270
|
+
background: #65C400;
|
271
|
+
color: #fff;
|
272
|
+
font-weight: bold;
|
273
|
+
}
|
274
|
+
|
275
|
+
dd {
|
276
|
+
margin: 5px 0 5px 5px;
|
277
|
+
padding: 3px 3px 3px 18px;
|
278
|
+
}
|
279
|
+
|
280
|
+
dd .duration {
|
281
|
+
padding-left: 5px;
|
282
|
+
text-align: right;
|
283
|
+
right: 0px;
|
284
|
+
float:right;
|
285
|
+
}
|
286
|
+
|
287
|
+
dd.example.passed {
|
288
|
+
border-left: 5px solid #65C400;
|
289
|
+
border-bottom: 1px solid #65C400;
|
290
|
+
background: #DBFFB4; color: #3D7700;
|
291
|
+
}
|
292
|
+
|
293
|
+
dd.example.not_implemented {
|
294
|
+
border-left: 5px solid #FAF834;
|
295
|
+
border-bottom: 1px solid #FAF834;
|
296
|
+
background: #FCFB98; color: #131313;
|
297
|
+
}
|
298
|
+
|
299
|
+
dd.example.pending_fixed {
|
300
|
+
border-left: 5px solid #0000C2;
|
301
|
+
border-bottom: 1px solid #0000C2;
|
302
|
+
color: #0000C2; background: #D3FBFF;
|
303
|
+
}
|
304
|
+
|
305
|
+
dd.example.failed {
|
306
|
+
border-left: 5px solid #C20000;
|
307
|
+
border-bottom: 1px solid #C20000;
|
308
|
+
color: #C20000; background: #FFFBD3;
|
309
|
+
}
|
310
|
+
|
311
|
+
|
312
|
+
dt.not_implemented {
|
313
|
+
color: #000000; background: #FAF834;
|
314
|
+
}
|
315
|
+
|
316
|
+
dt.pending_fixed {
|
317
|
+
color: #FFFFFF; background: #C40D0D;
|
318
|
+
}
|
319
|
+
|
320
|
+
dt.failed {
|
321
|
+
color: #FFFFFF; background: #C40D0D;
|
322
|
+
}
|
323
|
+
|
324
|
+
|
325
|
+
#rspec-header.not_implemented {
|
326
|
+
color: #000000; background: #FAF834;
|
327
|
+
}
|
328
|
+
|
329
|
+
#rspec-header.pending_fixed {
|
330
|
+
color: #FFFFFF; background: #C40D0D;
|
331
|
+
}
|
332
|
+
|
333
|
+
#rspec-header.failed {
|
334
|
+
color: #FFFFFF; background: #C40D0D;
|
335
|
+
}
|
336
|
+
|
337
|
+
|
338
|
+
.backtrace {
|
339
|
+
color: #000;
|
340
|
+
font-size: 12px;
|
341
|
+
}
|
342
|
+
|
343
|
+
a {
|
344
|
+
color: #BE5C00;
|
345
|
+
}
|
346
|
+
|
347
|
+
/* Ruby code, style similar to vibrant ink */
|
348
|
+
.ruby {
|
349
|
+
font-size: 12px;
|
350
|
+
font-family: monospace;
|
351
|
+
color: white;
|
352
|
+
background-color: black;
|
353
|
+
padding: 0.1em 0 0.2em 0;
|
354
|
+
}
|
355
|
+
|
356
|
+
.ruby .keyword { color: #FF6600; }
|
357
|
+
.ruby .constant { color: #339999; }
|
358
|
+
.ruby .attribute { color: white; }
|
359
|
+
.ruby .global { color: white; }
|
360
|
+
.ruby .module { color: white; }
|
361
|
+
.ruby .class { color: white; }
|
362
|
+
.ruby .string { color: #66FF00; }
|
363
|
+
.ruby .ident { color: white; }
|
364
|
+
.ruby .method { color: #FFCC00; }
|
365
|
+
.ruby .number { color: white; }
|
366
|
+
.ruby .char { color: white; }
|
367
|
+
.ruby .comment { color: #9933CC; }
|
368
|
+
.ruby .symbol { color: white; }
|
369
|
+
.ruby .regex { color: #44B4CC; }
|
370
|
+
.ruby .punct { color: white; }
|
371
|
+
.ruby .escape { color: white; }
|
372
|
+
.ruby .interp { color: white; }
|
373
|
+
.ruby .expr { color: white; }
|
374
|
+
|
375
|
+
.ruby .offending { background-color: gray; }
|
376
|
+
.ruby .linenum {
|
377
|
+
width: 75px;
|
378
|
+
padding: 0.1em 1em 0.2em 0;
|
379
|
+
color: #000000;
|
380
|
+
background-color: #FFFBD3;
|
381
|
+
}
|
382
|
+
EOF
|
383
|
+
|
384
|
+
HTML_HEADER = <<-EOF
|
385
|
+
<!DOCTYPE html>
|
386
|
+
<html lang='en'>
|
387
|
+
<head>
|
388
|
+
<title>RSpec results</title>
|
389
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
390
|
+
<meta http-equiv="Expires" content="-1" />
|
391
|
+
<meta http-equiv="Pragma" content="no-cache" />
|
392
|
+
<style type="text/css">
|
393
|
+
body {
|
394
|
+
margin: 0;
|
395
|
+
padding: 0;
|
396
|
+
background: #fff;
|
397
|
+
font-size: 80%;
|
398
|
+
}
|
399
|
+
</style>
|
400
|
+
<script type="text/javascript">
|
401
|
+
// <![CDATA[
|
402
|
+
#{GLOBAL_SCRIPTS}
|
403
|
+
// ]]>
|
404
|
+
</script>
|
405
|
+
<style type="text/css">
|
406
|
+
#{GLOBAL_STYLES}
|
407
|
+
</style>
|
408
|
+
</head>
|
409
|
+
<body>
|
410
|
+
EOF
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
414
|
+
end
|