xcpretty-bb 0.1.12.bb1

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 (69) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.hound.yml +2 -0
  4. data/.kick +17 -0
  5. data/.rubocop.yml +239 -0
  6. data/.travis.yml +11 -0
  7. data/CHANGELOG.md +200 -0
  8. data/CONTRIBUTING.md +64 -0
  9. data/Gemfile +9 -0
  10. data/LICENSE.txt +61 -0
  11. data/README.md +93 -0
  12. data/Rakefile +26 -0
  13. data/assets/report.html.erb +172 -0
  14. data/bin/xcpretty +85 -0
  15. data/features/assets/RACCommandSpec, line 80, hello xcpretty.png +0 -0
  16. data/features/assets/apple_raw.png +0 -0
  17. data/features/custom_formatter.feature +15 -0
  18. data/features/fixtures/xcodebuild.log +5963 -0
  19. data/features/html_report.feature +54 -0
  20. data/features/json_compilation_database_report.feature +21 -0
  21. data/features/junit_report.feature +44 -0
  22. data/features/knock_format.feature +11 -0
  23. data/features/simple_format.feature +204 -0
  24. data/features/steps/formatting_steps.rb +330 -0
  25. data/features/steps/html_steps.rb +32 -0
  26. data/features/steps/json_steps.rb +37 -0
  27. data/features/steps/junit_steps.rb +39 -0
  28. data/features/steps/report_steps.rb +22 -0
  29. data/features/steps/xcpretty_steps.rb +31 -0
  30. data/features/support/env.rb +117 -0
  31. data/features/tap_format.feature +31 -0
  32. data/features/test_format.feature +49 -0
  33. data/features/xcpretty.feature +14 -0
  34. data/lib/xcpretty/ansi.rb +72 -0
  35. data/lib/xcpretty/formatters/formatter.rb +177 -0
  36. data/lib/xcpretty/formatters/knock.rb +35 -0
  37. data/lib/xcpretty/formatters/rspec.rb +33 -0
  38. data/lib/xcpretty/formatters/simple.rb +200 -0
  39. data/lib/xcpretty/formatters/tap.rb +40 -0
  40. data/lib/xcpretty/parser.rb +591 -0
  41. data/lib/xcpretty/printer.rb +24 -0
  42. data/lib/xcpretty/reporters/html.rb +98 -0
  43. data/lib/xcpretty/reporters/json_compilation_database.rb +62 -0
  44. data/lib/xcpretty/reporters/junit.rb +102 -0
  45. data/lib/xcpretty/snippet.rb +38 -0
  46. data/lib/xcpretty/syntax.rb +51 -0
  47. data/lib/xcpretty/term.rb +14 -0
  48. data/lib/xcpretty/version.rb +4 -0
  49. data/lib/xcpretty.rb +37 -0
  50. data/spec/fixtures/NSStringTests.m +64 -0
  51. data/spec/fixtures/constants.rb +600 -0
  52. data/spec/fixtures/custom_formatter.rb +18 -0
  53. data/spec/fixtures/oneliner.m +1 -0
  54. data/spec/fixtures/raw_kiwi_compilation_fail.txt +24 -0
  55. data/spec/fixtures/raw_kiwi_fail.txt +1896 -0
  56. data/spec/fixtures/raw_specta_fail.txt +3110 -0
  57. data/spec/spec_helper.rb +7 -0
  58. data/spec/support/matchers/colors.rb +21 -0
  59. data/spec/xcpretty/ansi_spec.rb +47 -0
  60. data/spec/xcpretty/formatters/formatter_spec.rb +140 -0
  61. data/spec/xcpretty/formatters/rspec_spec.rb +56 -0
  62. data/spec/xcpretty/formatters/simple_spec.rb +173 -0
  63. data/spec/xcpretty/parser_spec.rb +542 -0
  64. data/spec/xcpretty/printer_spec.rb +55 -0
  65. data/spec/xcpretty/snippet_spec.rb +46 -0
  66. data/spec/xcpretty/syntax_spec.rb +39 -0
  67. data/spec/xcpretty/term_spec.rb +26 -0
  68. data/xcpretty.gemspec +37 -0
  69. metadata +237 -0
data/README.md ADDED
@@ -0,0 +1,93 @@
1
+ ![logo](http://i.imgur.com/i2fElxx.png)
2
+
3
+ __`xcpretty` is a fast and flexible formatter for `xcodebuild`__.<br/>
4
+ It does one thing, and it should do it well.
5
+
6
+ [![Gem version](http://img.shields.io/gem/v/xcpretty.svg)](http://rubygems.org/gems/xcpretty)
7
+ [![Build Status](https://travis-ci.org/supermarin/xcpretty.svg?branch=master)](https://travis-ci.org/supermarin/xcpretty)
8
+ [![Code Climate](http://img.shields.io/codeclimate/github/supermarin/xcpretty.svg)](https://codeclimate.com/github/supermarin/xcpretty)
9
+
10
+ ## Installation
11
+ ``` bash
12
+ $ gem install xcpretty
13
+ ```
14
+
15
+ ## Usage
16
+ ``` bash
17
+ $ xcodebuild [flags] | xcpretty -c
18
+ ```
19
+ `xcpretty` is designed to be piped with `xcodebuild` and thus keeping 100%
20
+ compatibility with it. It's even a bit faster than `xcodebuild` itself, since
21
+ it saves your terminal some prints.
22
+
23
+ __Important:__ If you're running `xcpretty` on a CI like Travis or Jenkins, you
24
+ may want to exit with same status code as `xcodebuild`.
25
+ CI systems usually use status codes to determine if the build has failed.
26
+
27
+ ``` bash
28
+ $ set -o pipefail && xcodebuild [flags] | xcpretty -c
29
+ #
30
+ # OR
31
+ #
32
+ $ xcodebuild [flags] | xcpretty -c && exit ${PIPESTATUS[0]}
33
+ ```
34
+
35
+ ## Raw xcodebuild output
36
+ You might want to use `xcpretty` together with `tee` to store the raw log in a
37
+ file, and get the pretty output in the terminal. This might be useful if you
38
+ want to inspect a failure in detail and aren't able to tell from the pretty
39
+ output.
40
+
41
+ Here's a way of doing it:
42
+ ``` bash
43
+ $ xcodebuild [flags] | tee xcodebuild.log | xcpretty -c
44
+ ```
45
+
46
+ ## Formats
47
+
48
+ - `--[no-]color`: Show build icons in color. (you can add it to `--simple` or `--test` format).
49
+ Defaults to auto-detecting color availability.
50
+ - `--[no-]utf`: Use unicode characters in build output or only ASCII.
51
+ Defaults to auto-detecting the current locale
52
+
53
+ - `--simple`, `-s` (default)
54
+ ![xcpretty --simple](http://i.imgur.com/LdmozBS.gif)
55
+
56
+ - `--test`, `-t` (RSpec style)
57
+ ![xcpretty alpha](http://i.imgur.com/VeTQQub.gif)
58
+ - `--tap` ([Test Anything Protocol](http://testanything.org)-compatible output)
59
+ - `--knock`, `-k` (a [simplified version](https://github.com/chneukirchen/knock) of the Test Anything Protocol)
60
+
61
+
62
+ ## Reporters
63
+
64
+ - `--report junit`, `-r junit`: Creates a JUnit-style XML report at `build/reports/junit.xml`, compatible with Jenkins and TeamCity CI.
65
+
66
+ - `--report html`, `-r html`: Creates a simple HTML report at `build/reports/tests.html`.
67
+ ![xcpretty html](http://i.imgur.com/0Rnux3v.gif)
68
+
69
+ - `--report json-compilation-database`, `-r json-compilation-database`: Creates a [JSON compilation database](http://clang.llvm.org/docs/JSONCompilationDatabase.html) at `build/reports/compilation.json`. This is a format to replay single compilations independently of the build system.
70
+
71
+ Writing a report to a custom path can be specified using `--output PATH`.
72
+
73
+ ## Extensions
74
+
75
+ `xcpretty` supports custom formatters through the use of the
76
+ `--formatter` flag, which takes a path to a file as an argument. The
77
+ file must contain a Ruby subclass of `XCPretty::Formatter`, and
78
+ return that class at the end of te file. The class
79
+ can override the `format_*` methods to hook into output parsing
80
+ events.
81
+
82
+ ### Known extensions
83
+
84
+ * [xcpretty-travis-formatter](https://github.com/kattrali/xcpretty-travis-formatter): support for cleaner output in TravisCI using code folding
85
+
86
+ The recommended format is a gem containing the formatter and named
87
+ with an `xcpretty-` prefix, for easier discovery.
88
+
89
+
90
+ ## Team
91
+
92
+ - [Marin Usalj](http://github.com/supermarin) http://supermar.in
93
+ - [Delisa Mason](http://github.com/kattrali) http://delisa.me
data/Rakefile ADDED
@@ -0,0 +1,26 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rubocop/rake_task'
3
+ require 'rspec/core/rake_task'
4
+ require 'cucumber/rake/task'
5
+
6
+ task :kick do
7
+ sh 'bundle exec kicker -r ruby'
8
+ end
9
+
10
+ Cucumber::Rake::Task.new(:cucumber) do |task|
11
+ end
12
+
13
+ RSpec::Core::RakeTask.new(:spec) do |task|
14
+ task.rspec_opts = %w(--color --format=doc)
15
+ end
16
+
17
+ RuboCop::RakeTask.new(:lint) do |task|
18
+ task.fail_on_error = false
19
+ end
20
+
21
+ task :ci do
22
+ Rake::Task[:spec].invoke
23
+ Rake::Task[:cucumber].invoke
24
+ Rake::Task[:lint].invoke
25
+ end
26
+
@@ -0,0 +1,172 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>Test Results | xcpretty</title>
6
+ <style type="text/css">
7
+ body { font-family:Avenir Next, Helvetica Neue, sans-serif; color: #4A4A4A; background-color: #F0F3FB; margin:0;}
8
+ h1 { font-weight: normal; font-size: 24px; margin: 10px 0 0 0;}
9
+ h3 { font-weight: normal; margin: 2px; font-size: 1.1em;}
10
+ header { position: fixed;width: 100%;background: rgba(249, 254, 255, 0.9);margin: 0;padding: 10px;}
11
+ header:before, header:after { content:""; display:table;}
12
+ header:after { clear:both;}
13
+ a:link { color: #A1D761;}
14
+ footer { clear: both;position: relative;z-index: 10;height: 40px;margin-top: -10px; margin-left:30px; font-size:12px;}
15
+ table { width:100%; border-collapse: collapse;}
16
+ tr td:first-child { width:7%}
17
+ .left { float: left; margin-left:30px;}
18
+ .right { float: right; margin-right: 40px; margin-top: 0; margin-bottom:0;}
19
+ .test-suite { margin: 0 0 30px 0;}
20
+ .test-suite > .heading { font-family:Menlo, Monaco, monospace; font-weight: bold; border-color: #A1D761; background-color: #B8E986; border-width: 1px;}
21
+ .test-suite.failing > .heading { border-color: #C84F5E; background-color: #E58591;}
22
+ .test-suite > .heading > .title { margin-top: 4px; margin-left: 10px;}
23
+ .tests { overflow: scroll;margin: 0 30px 0 60px;}
24
+ .test, .test-suite > .heading { height: 30px; overflow: hidden; margin: 0 30px;}
25
+ .test, .test-suite > .heading { border-width: 1px; border-collapse: collapse; border-style: solid; }
26
+ .test { margin-left: 30px; border-top:none;}
27
+ .test.failing { border-color: #C84F5E; background-color: #F4DDE0;}
28
+ .test.passing { border-color: #A1D761;}
29
+ .test.failing { background-color: #E7A1AA;}
30
+ .test.passing { background-color: #CAF59F;}
31
+ .test.failing.odd { background-color: #EEC7CC;}
32
+ .test.passing.odd { background-color: #E5FBCF;}
33
+ .details { background-color: #F4DDE0; border: 1px solid #C84F5E;}
34
+ .test .test-detail:last-child { padding-bottom: 8px;}
35
+ .test .title { float: left; font-size: 0.9em; margin-top: 8px; font-family: Menlo, Monaco, monospace;}
36
+ .test .time { float: left;margin: 4px 10px 0 20px;}
37
+ .test-detail { font-family:Menlo, Monaco, monospace; font-size: 0.9em; margin: 5px 0 5px 0px;}
38
+ .screenshots { height: auto; overflow: hidden; padding: 4px 4px 0 4px; background-color: #B8E986; border: #A1D761; border-width: 0 1px; border-style: solid; }
39
+ .screenshots.failing { border-color: #C84F5E; background-color: #E58591; }
40
+ .screenshot { max-height: 60px; float: left; transition: max-height 0.2s; margin: 0 4px 4px 0 }
41
+ .screenshot.selected { max-height: 568px; }
42
+ #test-suites { display: inline-block; width: 100%;margin-top:100px;}
43
+ #segment-bar { margin-top: 10px;margin-left: 14px;float:right;}
44
+ #segment-bar a:first-child { border-radius: 9px 0 0 9px; border-right: none;}
45
+ #segment-bar a:last-child { border-radius: 0 9px 9px 0; border-left: none;}
46
+ #segment-bar > a { color: #565656; border: 2px solid #7B7B7B; width: 80px; font-weight: bold; display:inline-block;text-align:center; font-weight: normal;}
47
+ #segment-bar > a.selected { background-color: #979797; color: #F0F3FB;}
48
+ #counters { float: left;margin: 10px;text-align: right;}
49
+ #counters h2 { font-size: 16px; font-family: Avenir, sans-serif; font-weight: lighter; display:inline;}
50
+ #counters .number { font-size: 20px;}
51
+ #fail-count { color: #D0021B; margin-left:10px;}
52
+ @media (max-width: 640px) {
53
+ h1, #counters, #segment-bar { margin: 5px auto; text-align:center;}
54
+ header, #segment-bar { width: 100%; position: relative; background:none;}
55
+ .left, .right { float:none; margin:0;}
56
+ #test-suites { margin-top: 0;}
57
+ #counters { float:none;}
58
+ }
59
+ </style>
60
+ <script type="text/javascript">
61
+ var hide = function(element) { element.style.display = 'none';}
62
+ var show = function(element) { element.style.display = '';}
63
+ var isHidden = function(element) { return element.style.display == 'none';}
64
+ var isSelected = function(element) { return element.classList.contains("selected");}
65
+ var deselect = function(element) { return element.classList.remove("selected");}
66
+ var select = function(element) { return element.classList.add("selected");}
67
+ var toggle = function(element) { isHidden(element) ? show(element) : hide(element);};
68
+ var toggleTests = function(heading) { toggle(heading.parentNode.children[1]);};
69
+ var toggleDetails = function(detailClass) {
70
+ var details = document.querySelectorAll('.' + detailClass);
71
+ for (var i = details.length - 1; i >= 0; i--) { toggle(details[i]);};
72
+ };
73
+ var hideAll = function(collection) {
74
+ for (var i = collection.length - 1; i >= 0; i--) { hide(collection[i]); };
75
+ }
76
+ var showAll = function(collection) {
77
+ for (var i = collection.length - 1; i >= 0; i--) { show(collection[i]); };
78
+ }
79
+ var selectSegment = function(segment) {
80
+ if (isSelected(segment)) return;
81
+ var segments = document.querySelectorAll('#segment-bar > a');
82
+ for (var i = segments.length - 1; i >= 0; i--) { deselect(segments[i]);};
83
+ select(segment);
84
+ if (segment.id == "all-segment") {
85
+ showAll(document.querySelectorAll('.test-suite'));
86
+ showAll(document.querySelectorAll('.test'));
87
+ } else if (segment.id == "failing-segment") {
88
+ hideAll(document.querySelectorAll('.test.passing'));
89
+ showAll(document.querySelectorAll('.test.failing'));
90
+ hideAll(document.querySelectorAll('.test-suite.passing'));
91
+ showAll(document.querySelectorAll('.test-suite.failing'));
92
+ } else if (segment.id == "passing-segment") {
93
+ hideAll(document.querySelectorAll('.test.failing'));
94
+ showAll(document.querySelectorAll('.test.passing'));
95
+ hideAll(document.querySelectorAll('.test-suite.failing'));
96
+ showAll(document.querySelectorAll('.test-suite.passing'));
97
+ }
98
+ }
99
+ var toggleScreenshot = function(suiteName, index) {
100
+ var screenshot = document.getElementById("screenshot-" + suiteName + "-" + index);
101
+ isSelected(screenshot) ? deselect(screenshot) : select(screenshot);
102
+ }
103
+ </script>
104
+ </head>
105
+ <body>
106
+ <header>
107
+ <section class="left">
108
+ <h1>Test Results</h1>
109
+ </section>
110
+ <section class="right">
111
+ <section id="counters">
112
+ <h2 id="test-count"><span class="number"><%= test_count %></span> tests</h2>
113
+ <% if fail_count > 0 %>
114
+ <h2 id="fail-count"><span class="number"><%= fail_count %></span> failures</h2>
115
+ <% end %>
116
+ </section>
117
+ <section id="segment-bar">
118
+ <a id="all-segment" onclick="selectSegment(this);" class="selected">All</a><a id="failing-segment" onclick="selectSegment(this);">Failing</a><a id="passing-segment" onclick="selectSegment(this);">Passing</a>
119
+ </section>
120
+ </section>
121
+ </header>
122
+ <section id="test-suites">
123
+ <% test_suites.each do |name, info| %>
124
+ <% next unless info[:tests].size > 0 %>
125
+ <section class="test-suite <%= info[:failing] ? 'failing' : 'passing'%>" id="<%= name %>">
126
+ <section class="heading" onclick="toggleTests(this);">
127
+ <h3 class="title"><%= name %></h3>
128
+ </section>
129
+ <section class="tests">
130
+ <% unless info[:screenshots].empty? %>
131
+ <div class="screenshots <%= info[:failing] ? 'failing' : 'passing'%>">
132
+ <% info[:screenshots].each_with_index do |screenshot, index| %>
133
+ <a href="javascript:toggleScreenshot('<%=name %>', <%=index %>)">
134
+ <img class="screenshot" id="screenshot-<%=name %>-<%=index %>" src="<%=screenshot %>" />
135
+ </a>
136
+ <% end %>
137
+ </div>
138
+ <% end %>
139
+ <table>
140
+ <% info[:tests].each_with_index do |test, index| %>
141
+ <% detail_class = test[:name].gsub(/\s/,'') %>
142
+ <tr class="test <%= test[:failing] ? 'failing' : 'passing'%> <%= index % 2 != 0 ? 'odd' :''%>" onclick="toggleDetails('<%= detail_class %>');">
143
+ <td>
144
+ <% if test[:time] %>
145
+ <h3 class="time"><%= test[:time] %>s</h3>
146
+ <% end %>
147
+ </td>
148
+ <td><h3 class="title"><%= test[:name] %></h3></td>
149
+ </tr>
150
+ <% if test[:reason] || test[:snippet] %>
151
+ <tr class="details <%= detail_class %>">
152
+ <td></td>
153
+ <td>
154
+ <% if test[:reason] %>
155
+ <section class="test-detail reason"><%= test[:reason] %></section>
156
+ <% end %>
157
+ <% if test[:snippet] %>
158
+ <section class="test-detail snippet"><%= test[:snippet] %></section>
159
+ <section class="test-detail"><%= test[:file] %></section>
160
+ <% end %>
161
+ </td>
162
+ </tr>
163
+ <% end %>
164
+ <% end %>
165
+ </table>
166
+ </section>
167
+ </section>
168
+ <% end %>
169
+ </section>
170
+ <footer>Report generated with <a href="https://github.com/supermarin/xcpretty">xcpretty</a></footer>
171
+ </body>
172
+ </html>
data/bin/xcpretty ADDED
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if RUBY_VERSION < '2.0.0'
4
+ abort "error: XCPretty requires Ruby 2.0.0 or higher."
5
+ end
6
+
7
+ if $PROGRAM_NAME == __FILE__
8
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
9
+ end
10
+ require 'xcpretty'
11
+ require 'optparse'
12
+
13
+ report_options = []
14
+ report_classes = []
15
+ report_formats = {
16
+ "junit" => XCPretty::JUnit,
17
+ "html" => XCPretty::HTML,
18
+ "json-compilation-database" => XCPretty::JSONCompilationDatabase
19
+ }
20
+
21
+ printer_opts = {
22
+ unicode: XCPretty::Term.unicode?,
23
+ colorize: XCPretty::Term.color?,
24
+ formatter: XCPretty::Simple
25
+ }
26
+
27
+ OptionParser.new do |opts|
28
+ opts.banner = "Usage: xcodebuild [options] | xcpretty"
29
+ opts.on('-t', '--test', 'Use RSpec style output') do
30
+ printer_opts[:formatter] = XCPretty::RSpec
31
+ end
32
+ opts.on('-s', '--simple', 'Use simple output (default)') do
33
+ printer_opts[:formatter] = XCPretty::Simple
34
+ end
35
+ opts.on('-k', '--knock', 'Use knock output') do
36
+ printer_opts[:formatter] = XCPretty::Knock
37
+ end
38
+ opts.on('--tap', 'Use TAP output') do
39
+ printer_opts[:formatter] = XCPretty::TestAnything
40
+ end
41
+ opts.on('-f', '--formatter PATH', 'Use formatter returned from evaluating the specified Ruby file') do |path|
42
+ printer_opts[:formatter] = XCPretty.load_custom_formatter(path)
43
+ end
44
+ opts.on('--[no-]color', 'Use colorized output. Defaults is auto') do |value|
45
+ printer_opts[:colorize] = value
46
+ end
47
+ opts.on('--[no-]utf', 'Use unicode characters in output. Default is auto.') do |value|
48
+ printer_opts[:unicode] = value
49
+ end
50
+ opts.on("-r", "--report FORMAT", "Run FORMAT reporter",
51
+ " Choices: #{report_formats.keys.join(', ')}") do |format|
52
+ report_classes << report_formats[format]
53
+ report_options << {}
54
+ end
55
+ opts.on('-o', '--output PATH', 'Write report output to PATH') do |path|
56
+ unless opts = report_options.last
57
+ XCPretty.exit_with_error('Expected report format to be specified before output path')
58
+ end
59
+ opts[:path] = path
60
+ end
61
+ opts.on('--screenshots', 'Collect screenshots in the HTML report') do
62
+ unless opts = report_options.last
63
+ XCPretty.exit_with_error('Expected screenshot argument to be specified after report format')
64
+ end
65
+ opts[:screenshots] = true
66
+ end
67
+ opts.on_tail('-h', '--help', 'Show this message') { puts opts; exit }
68
+ opts.on_tail("-v", "--version", "Show version") { puts XCPretty::VERSION; exit }
69
+ opts.parse!
70
+
71
+ if STDIN.tty?
72
+ XCPretty.exit_with_error(opts.help)
73
+ end
74
+ end
75
+
76
+ printer = XCPretty::Printer.new(printer_opts)
77
+ reporters = report_classes.compact.each_with_index.map { |k, i| k.new(report_options[i]) }
78
+
79
+ STDIN.each_line do |line|
80
+ printer.pretty_print(line)
81
+ reporters.each { |r| r.handle(line) }
82
+ end
83
+
84
+ reporters.each(&:finish)
85
+
Binary file
@@ -0,0 +1,15 @@
1
+ Feature: Loading an arbitrary Ruby file as a formatter
2
+
3
+ Scenario: The file loaded does not contain a Ruby class
4
+ When I pipe to xcpretty with "--formatter /bin/bash"
5
+ Then the exit status code should be 1
6
+
7
+ Scenario: The file loaded contains a Ruby class
8
+ Given I have a file to compile
9
+ When I pipe to xcpretty with a custom formatter
10
+ Then the exit status code should be 0
11
+
12
+ Scenario: Showing output using a custom formatter
13
+ Given I have a file to compile
14
+ When I pipe to xcpretty with a custom formatter
15
+ Then I should see a custom compilation message