rspec-legacy_formatters 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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