rspec-legacy_formatters 1.0.0.rc1

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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +1 -0
  4. data/.gitignore +11 -0
  5. data/.rspec +2 -0
  6. data/.travis.yml +16 -0
  7. data/.yardopts +7 -0
  8. data/Changelog.md +3 -0
  9. data/Gemfile +30 -0
  10. data/License.txt +22 -0
  11. data/README.md +41 -0
  12. data/Rakefile +27 -0
  13. data/cucumber.yml +6 -0
  14. data/features/custom_formatter.feature +28 -0
  15. data/features/regression_tests_for_built_in_formatters.feature +86 -0
  16. data/features/regression_tests_for_custom_formatters.feature +94 -0
  17. data/features/step_definitions/additional_cli_steps.rb +4 -0
  18. data/features/support/env.rb +13 -0
  19. data/lib/rspec/legacy_formatters.rb +59 -0
  20. data/lib/rspec/legacy_formatters/adaptor.rb +230 -0
  21. data/lib/rspec/legacy_formatters/base_formatter.rb +248 -0
  22. data/lib/rspec/legacy_formatters/base_text_formatter.rb +330 -0
  23. data/lib/rspec/legacy_formatters/documentation_formatter.rb +69 -0
  24. data/lib/rspec/legacy_formatters/helpers.rb +108 -0
  25. data/lib/rspec/legacy_formatters/html_formatter.rb +157 -0
  26. data/lib/rspec/legacy_formatters/html_printer.rb +412 -0
  27. data/lib/rspec/legacy_formatters/json_formatter.rb +71 -0
  28. data/lib/rspec/legacy_formatters/progress_formatter.rb +31 -0
  29. data/lib/rspec/legacy_formatters/snippet_extractor.rb +92 -0
  30. data/lib/rspec/legacy_formatters/version.rb +9 -0
  31. data/maintenance-branch +1 -0
  32. data/rspec-legacy_formatters.gemspec +43 -0
  33. data/script/functions.sh +144 -0
  34. data/script/run_build +13 -0
  35. data/spec/rspec/legacy_formatters_spec.rb +184 -0
  36. data/spec/spec_helper.rb +7 -0
  37. data/spec/support/formatter_support.rb +83 -0
  38. data/spec/support/legacy_formatter_using_sub_classing_example.rb +87 -0
  39. data/spec/support/old_style_formatter_example.rb +69 -0
  40. metadata +243 -0
  41. metadata.gz.sig +2 -0
@@ -0,0 +1,157 @@
1
+ require 'rspec/legacy_formatters/base_text_formatter'
2
+ require 'rspec/legacy_formatters/html_printer'
3
+
4
+ module RSpec
5
+ module Core
6
+ module Formatters
7
+ remove_const :HtmlFormatter
8
+
9
+ class HtmlFormatter < BaseTextFormatter
10
+
11
+ def initialize(output)
12
+ super(output)
13
+ @example_group_number = 0
14
+ @example_number = 0
15
+ @header_red = nil
16
+ @printer = HtmlPrinter.new(output)
17
+ end
18
+
19
+ private
20
+ def method_missing(m, *a, &b)
21
+ # no-op
22
+ end
23
+
24
+ public
25
+ def message(message)
26
+ end
27
+
28
+ # The number of the currently running example_group
29
+ def example_group_number
30
+ @example_group_number
31
+ end
32
+
33
+ # The number of the currently running example (a global counter)
34
+ def example_number
35
+ @example_number
36
+ end
37
+
38
+ def start(example_count)
39
+ super(example_count)
40
+ @printer.print_html_start
41
+ @printer.flush
42
+ end
43
+
44
+ def example_group_started(example_group)
45
+ super(example_group)
46
+ @example_group_red = false
47
+ @example_group_number += 1
48
+
49
+ unless example_group_number == 1
50
+ @printer.print_example_group_end
51
+ end
52
+ @printer.print_example_group_start( example_group_number, example_group.description, example_group.parent_groups.size )
53
+ @printer.flush
54
+ end
55
+
56
+ def start_dump
57
+ @printer.print_example_group_end
58
+ @printer.flush
59
+ end
60
+
61
+ def example_started(example)
62
+ super(example)
63
+ @example_number += 1
64
+ end
65
+
66
+ def example_passed(example)
67
+ @printer.move_progress(percent_done)
68
+ @printer.print_example_passed( example.description, example.execution_result.run_time )
69
+ @printer.flush
70
+ end
71
+
72
+ def example_failed(example)
73
+ super(example)
74
+
75
+ unless @header_red
76
+ @header_red = true
77
+ @printer.make_header_red
78
+ end
79
+
80
+ unless @example_group_red
81
+ @example_group_red = true
82
+ @printer.make_example_group_header_red(example_group_number)
83
+ end
84
+
85
+ @printer.move_progress(percent_done)
86
+
87
+ exception = example.execution_result.exception
88
+ exception_details = if exception
89
+ {
90
+ :message => exception.message,
91
+ :backtrace => format_backtrace(exception.backtrace, example).join("\n")
92
+ }
93
+ else
94
+ false
95
+ end
96
+ extra = extra_failure_content(exception)
97
+
98
+ @printer.print_example_failed(
99
+ example.execution_result.pending_fixed?,
100
+ example.description,
101
+ example.execution_result.run_time,
102
+ @failed_examples.size,
103
+ exception_details,
104
+ (extra == "") ? false : extra,
105
+ true
106
+ )
107
+ @printer.flush
108
+ end
109
+
110
+ def example_pending(example)
111
+
112
+ @printer.make_header_yellow unless @header_red
113
+ @printer.make_example_group_header_yellow(example_group_number) unless @example_group_red
114
+ @printer.move_progress(percent_done)
115
+ @printer.print_example_pending( example.description, example.execution_result.pending_message )
116
+ @printer.flush
117
+ end
118
+
119
+ # Override this method if you wish to output extra HTML for a failed spec. For example, you
120
+ # could output links to images or other files produced during the specs.
121
+ #
122
+ def extra_failure_content(exception)
123
+ require 'rspec/legacy_formatters/snippet_extractor'
124
+ backtrace = exception.backtrace.map {|line| backtrace_line(line)}
125
+ backtrace.compact!
126
+ @snippet_extractor ||= SnippetExtractor.new
127
+ " <pre class=\"ruby\"><code>#{@snippet_extractor.snippet(backtrace)}</code></pre>"
128
+ end
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
+ def dump_failures
139
+ end
140
+
141
+ def dump_pending
142
+ end
143
+
144
+ def dump_summary(duration, example_count, failure_count, pending_count)
145
+ @printer.print_summary(
146
+ dry_run?,
147
+ duration,
148
+ example_count,
149
+ failure_count,
150
+ pending_count
151
+ )
152
+ @printer.flush
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,412 @@
1
+ require 'erb'
2
+
3
+ module RSpec
4
+ module Core
5
+ module Formatters
6
+ class HtmlPrinter
7
+ include ERB::Util # for the #h method
8
+ def initialize(output)
9
+ @output = output
10
+ end
11
+
12
+ def print_html_start
13
+ @output.puts HTML_HEADER
14
+ @output.puts REPORT_HEADER
15
+ end
16
+
17
+ def print_example_group_end
18
+ @output.puts " </dl>"
19
+ @output.puts "</div>"
20
+ end
21
+
22
+ def print_example_group_start( group_id, description, number_of_parents )
23
+ @output.puts "<div id=\"div_group_#{group_id}\" class=\"example_group passed\">"
24
+ @output.puts " <dl #{indentation_style(number_of_parents)}>"
25
+ @output.puts " <dt id=\"example_group_#{group_id}\" class=\"passed\">#{h(description)}</dt>"
26
+ end
27
+
28
+ def print_example_passed( description, run_time )
29
+ formatted_run_time = sprintf("%.5f", run_time)
30
+ @output.puts " <dd class=\"example passed\"><span class=\"passed_spec_name\">#{h(description)}</span><span class='duration'>#{formatted_run_time}s</span></dd>"
31
+ end
32
+
33
+ def print_example_failed( pending_fixed, description, run_time, failure_id, exception, extra_content, escape_backtrace = false )
34
+ formatted_run_time = sprintf("%.5f", run_time)
35
+
36
+ @output.puts " <dd class=\"example #{pending_fixed ? 'pending_fixed' : 'failed'}\">"
37
+ @output.puts " <span class=\"failed_spec_name\">#{h(description)}</span>"
38
+ @output.puts " <span class=\"duration\">#{formatted_run_time}s</span>"
39
+ @output.puts " <div class=\"failure\" id=\"failure_#{failure_id}\">"
40
+ if exception
41
+ @output.puts " <div class=\"message\"><pre>#{h(exception[:message])}</pre></div>"
42
+ if escape_backtrace
43
+ @output.puts " <div class=\"backtrace\"><pre>#{h exception[:backtrace]}</pre></div>"
44
+ else
45
+ @output.puts " <div class=\"backtrace\"><pre>#{exception[:backtrace]}</pre></div>"
46
+ end
47
+ end
48
+ @output.puts extra_content if extra_content
49
+ @output.puts " </div>"
50
+ @output.puts " </dd>"
51
+ end
52
+
53
+ def print_example_pending( description, pending_message )
54
+ @output.puts " <dd class=\"example not_implemented\"><span class=\"not_implemented_spec_name\">#{h(description)} (PENDING: #{h(pending_message)})</span></dd>"
55
+ end
56
+
57
+ def print_summary( was_dry_run, duration, example_count, failure_count, pending_count )
58
+ # TODO - kill dry_run?
59
+ if was_dry_run
60
+ totals = "This was a dry-run"
61
+ else
62
+ totals = "#{example_count} example#{'s' unless example_count == 1}, "
63
+ totals << "#{failure_count} failure#{'s' unless failure_count == 1}"
64
+ totals << ", #{pending_count} pending" if pending_count > 0
65
+ end
66
+
67
+ formatted_duration = sprintf("%.5f", duration)
68
+
69
+ @output.puts "<script type=\"text/javascript\">document.getElementById('duration').innerHTML = \"Finished in <strong>#{formatted_duration} seconds</strong>\";</script>"
70
+ @output.puts "<script type=\"text/javascript\">document.getElementById('totals').innerHTML = \"#{totals}\";</script>"
71
+ @output.puts "</div>"
72
+ @output.puts "</div>"
73
+ @output.puts "</body>"
74
+ @output.puts "</html>"
75
+ end
76
+
77
+ def flush
78
+ @output.flush
79
+ end
80
+
81
+ def move_progress( percent_done )
82
+ @output.puts " <script type=\"text/javascript\">moveProgressBar('#{percent_done}');</script>"
83
+ @output.flush
84
+ end
85
+
86
+ def make_header_red
87
+ @output.puts " <script type=\"text/javascript\">makeRed('rspec-header');</script>"
88
+ end
89
+
90
+ def make_header_yellow
91
+ @output.puts " <script type=\"text/javascript\">makeYellow('rspec-header');</script>"
92
+ end
93
+
94
+ def make_example_group_header_red(group_id)
95
+ @output.puts " <script type=\"text/javascript\">makeRed('div_group_#{group_id}');</script>"
96
+ @output.puts " <script type=\"text/javascript\">makeRed('example_group_#{group_id}');</script>"
97
+ end
98
+
99
+ def make_example_group_header_yellow(group_id)
100
+ @output.puts " <script type=\"text/javascript\">makeYellow('div_group_#{group_id}');</script>"
101
+ @output.puts " <script type=\"text/javascript\">makeYellow('example_group_#{group_id}');</script>"
102
+ end
103
+
104
+
105
+ private
106
+
107
+ def indentation_style( number_of_parents )
108
+ "style=\"margin-left: #{(number_of_parents - 1) * 15}px;\""
109
+ end
110
+
111
+ remove_const :REPORT_HEADER
112
+ remove_const :GLOBAL_SCRIPTS
113
+ remove_const :GLOBAL_STYLES
114
+ remove_const :HTML_HEADER
115
+
116
+ REPORT_HEADER = <<-EOF
117
+ <div class="rspec-report">
118
+
119
+ <div id="rspec-header">
120
+ <div id="label">
121
+ <h1>RSpec Code Examples</h1>
122
+ </div>
123
+
124
+ <div id="display-filters">
125
+ <input id="passed_checkbox" name="passed_checkbox" type="checkbox" checked="checked" onchange="apply_filters()" value="1" /> <label for="passed_checkbox">Passed</label>
126
+ <input id="failed_checkbox" name="failed_checkbox" type="checkbox" checked="checked" onchange="apply_filters()" value="2" /> <label for="failed_checkbox">Failed</label>
127
+ <input id="pending_checkbox" name="pending_checkbox" type="checkbox" checked="checked" onchange="apply_filters()" value="3" /> <label for="pending_checkbox">Pending</label>
128
+ </div>
129
+
130
+ <div id="summary">
131
+ <p id="totals">&#160;</p>
132
+ <p id="duration">&#160;</p>
133
+ </div>
134
+ </div>
135
+
136
+
137
+ <div class="results">
138
+ EOF
139
+
140
+ GLOBAL_SCRIPTS = <<-EOF
141
+
142
+ function addClass(element_id, classname) {
143
+ document.getElementById(element_id).className += (" " + classname);
144
+ }
145
+
146
+ function removeClass(element_id, classname) {
147
+ var elem = document.getElementById(element_id);
148
+ var classlist = elem.className.replace(classname,'');
149
+ elem.className = classlist;
150
+ }
151
+
152
+ function moveProgressBar(percentDone) {
153
+ document.getElementById("rspec-header").style.width = percentDone +"%";
154
+ }
155
+
156
+ function makeRed(element_id) {
157
+ removeClass(element_id, 'passed');
158
+ removeClass(element_id, 'not_implemented');
159
+ addClass(element_id,'failed');
160
+ }
161
+
162
+ function makeYellow(element_id) {
163
+ var elem = document.getElementById(element_id);
164
+ if (elem.className.indexOf("failed") == -1) { // class doesn't includes failed
165
+ if (elem.className.indexOf("not_implemented") == -1) { // class doesn't include not_implemented
166
+ removeClass(element_id, 'passed');
167
+ addClass(element_id,'not_implemented');
168
+ }
169
+ }
170
+ }
171
+
172
+ function apply_filters() {
173
+ var passed_filter = document.getElementById('passed_checkbox').checked;
174
+ var failed_filter = document.getElementById('failed_checkbox').checked;
175
+ var pending_filter = document.getElementById('pending_checkbox').checked;
176
+
177
+ assign_display_style("example passed", passed_filter);
178
+ assign_display_style("example failed", failed_filter);
179
+ assign_display_style("example not_implemented", pending_filter);
180
+
181
+ assign_display_style_for_group("example_group passed", passed_filter);
182
+ assign_display_style_for_group("example_group not_implemented", pending_filter, pending_filter || passed_filter);
183
+ assign_display_style_for_group("example_group failed", failed_filter, failed_filter || pending_filter || passed_filter);
184
+ }
185
+
186
+ function get_display_style(display_flag) {
187
+ var style_mode = 'none';
188
+ if (display_flag == true) {
189
+ style_mode = 'block';
190
+ }
191
+ return style_mode;
192
+ }
193
+
194
+ function assign_display_style(classname, display_flag) {
195
+ var style_mode = get_display_style(display_flag);
196
+ var elems = document.getElementsByClassName(classname)
197
+ for (var i=0; i<elems.length;i++) {
198
+ elems[i].style.display = style_mode;
199
+ }
200
+ }
201
+
202
+ function assign_display_style_for_group(classname, display_flag, subgroup_flag) {
203
+ var display_style_mode = get_display_style(display_flag);
204
+ var subgroup_style_mode = get_display_style(subgroup_flag);
205
+ var elems = document.getElementsByClassName(classname)
206
+ for (var i=0; i<elems.length;i++) {
207
+ var style_mode = display_style_mode;
208
+ if ((display_flag != subgroup_flag) && (elems[i].getElementsByTagName('dt')[0].innerHTML.indexOf(", ") != -1)) {
209
+ elems[i].style.display = subgroup_style_mode;
210
+ } else {
211
+ elems[i].style.display = display_style_mode;
212
+ }
213
+ }
214
+ }
215
+ EOF
216
+
217
+ GLOBAL_STYLES = <<-EOF
218
+ #rspec-header {
219
+ background: #65C400; color: #fff; height: 4em;
220
+ }
221
+
222
+ .rspec-report h1 {
223
+ margin: 0px 10px 0px 10px;
224
+ padding: 10px;
225
+ font-family: "Lucida Grande", Helvetica, sans-serif;
226
+ font-size: 1.8em;
227
+ position: absolute;
228
+ }
229
+
230
+ #label {
231
+ float:left;
232
+ }
233
+
234
+ #display-filters {
235
+ float:left;
236
+ padding: 28px 0 0 40%;
237
+ font-family: "Lucida Grande", Helvetica, sans-serif;
238
+ }
239
+
240
+ #summary {
241
+ float:right;
242
+ padding: 5px 10px;
243
+ font-family: "Lucida Grande", Helvetica, sans-serif;
244
+ text-align: right;
245
+ }
246
+
247
+ #summary p {
248
+ margin: 0 0 0 2px;
249
+ }
250
+
251
+ #summary #totals {
252
+ font-size: 1.2em;
253
+ }
254
+
255
+ .example_group {
256
+ margin: 0 10px 5px;
257
+ background: #fff;
258
+ }
259
+
260
+ dl {
261
+ margin: 0; padding: 0 0 5px;
262
+ font: normal 11px "Lucida Grande", Helvetica, sans-serif;
263
+ }
264
+
265
+ dt {
266
+ padding: 3px;
267
+ background: #65C400;
268
+ color: #fff;
269
+ font-weight: bold;
270
+ }
271
+
272
+ dd {
273
+ margin: 5px 0 5px 5px;
274
+ padding: 3px 3px 3px 18px;
275
+ }
276
+
277
+ dd .duration {
278
+ padding-left: 5px;
279
+ text-align: right;
280
+ right: 0px;
281
+ float:right;
282
+ }
283
+
284
+ dd.example.passed {
285
+ border-left: 5px solid #65C400;
286
+ border-bottom: 1px solid #65C400;
287
+ background: #DBFFB4; color: #3D7700;
288
+ }
289
+
290
+ dd.example.not_implemented {
291
+ border-left: 5px solid #FAF834;
292
+ border-bottom: 1px solid #FAF834;
293
+ background: #FCFB98; color: #131313;
294
+ }
295
+
296
+ dd.example.pending_fixed {
297
+ border-left: 5px solid #0000C2;
298
+ border-bottom: 1px solid #0000C2;
299
+ color: #0000C2; background: #D3FBFF;
300
+ }
301
+
302
+ dd.example.failed {
303
+ border-left: 5px solid #C20000;
304
+ border-bottom: 1px solid #C20000;
305
+ color: #C20000; background: #FFFBD3;
306
+ }
307
+
308
+
309
+ dt.not_implemented {
310
+ color: #000000; background: #FAF834;
311
+ }
312
+
313
+ dt.pending_fixed {
314
+ color: #FFFFFF; background: #C40D0D;
315
+ }
316
+
317
+ dt.failed {
318
+ color: #FFFFFF; background: #C40D0D;
319
+ }
320
+
321
+
322
+ #rspec-header.not_implemented {
323
+ color: #000000; background: #FAF834;
324
+ }
325
+
326
+ #rspec-header.pending_fixed {
327
+ color: #FFFFFF; background: #C40D0D;
328
+ }
329
+
330
+ #rspec-header.failed {
331
+ color: #FFFFFF; background: #C40D0D;
332
+ }
333
+
334
+
335
+ .backtrace {
336
+ color: #000;
337
+ font-size: 12px;
338
+ }
339
+
340
+ a {
341
+ color: #BE5C00;
342
+ }
343
+
344
+ /* Ruby code, style similar to vibrant ink */
345
+ .ruby {
346
+ font-size: 12px;
347
+ font-family: monospace;
348
+ color: white;
349
+ background-color: black;
350
+ padding: 0.1em 0 0.2em 0;
351
+ }
352
+
353
+ .ruby .keyword { color: #FF6600; }
354
+ .ruby .constant { color: #339999; }
355
+ .ruby .attribute { color: white; }
356
+ .ruby .global { color: white; }
357
+ .ruby .module { color: white; }
358
+ .ruby .class { color: white; }
359
+ .ruby .string { color: #66FF00; }
360
+ .ruby .ident { color: white; }
361
+ .ruby .method { color: #FFCC00; }
362
+ .ruby .number { color: white; }
363
+ .ruby .char { color: white; }
364
+ .ruby .comment { color: #9933CC; }
365
+ .ruby .symbol { color: white; }
366
+ .ruby .regex { color: #44B4CC; }
367
+ .ruby .punct { color: white; }
368
+ .ruby .escape { color: white; }
369
+ .ruby .interp { color: white; }
370
+ .ruby .expr { color: white; }
371
+
372
+ .ruby .offending { background-color: gray; }
373
+ .ruby .linenum {
374
+ width: 75px;
375
+ padding: 0.1em 1em 0.2em 0;
376
+ color: #000000;
377
+ background-color: #FFFBD3;
378
+ }
379
+ EOF
380
+
381
+ HTML_HEADER = <<-EOF
382
+ <!DOCTYPE html>
383
+ <html lang='en'>
384
+ <head>
385
+ <title>RSpec results</title>
386
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
387
+ <meta http-equiv="Expires" content="-1" />
388
+ <meta http-equiv="Pragma" content="no-cache" />
389
+ <style type="text/css">
390
+ body {
391
+ margin: 0;
392
+ padding: 0;
393
+ background: #fff;
394
+ font-size: 80%;
395
+ }
396
+ </style>
397
+ <script type="text/javascript">
398
+ // <![CDATA[
399
+ #{GLOBAL_SCRIPTS}
400
+ // ]]>
401
+ </script>
402
+ <style type="text/css">
403
+ #{GLOBAL_STYLES}
404
+ </style>
405
+ </head>
406
+ <body>
407
+ EOF
408
+
409
+ end
410
+ end
411
+ end
412
+ end