learn-xcpretty 0.1.11

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 (68) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.kick +17 -0
  4. data/.travis.yml +18 -0
  5. data/CHANGELOG.md +152 -0
  6. data/CONTRIBUTING.md +60 -0
  7. data/Gemfile +8 -0
  8. data/LICENSE.txt +61 -0
  9. data/README.md +143 -0
  10. data/Rakefile +24 -0
  11. data/assets/report.html.erb +155 -0
  12. data/bin/learn-xcpretty +80 -0
  13. data/features/custom_formatter.feature +15 -0
  14. data/features/fixtures/xcodebuild.log +5963 -0
  15. data/features/html_report.feature +40 -0
  16. data/features/json_compilation_database_report.feature +21 -0
  17. data/features/junit_report.feature +44 -0
  18. data/features/knock_format.feature +11 -0
  19. data/features/simple_format.feature +172 -0
  20. data/features/steps/formatting_steps.rb +268 -0
  21. data/features/steps/html_steps.rb +23 -0
  22. data/features/steps/json_steps.rb +37 -0
  23. data/features/steps/junit_steps.rb +38 -0
  24. data/features/steps/report_steps.rb +21 -0
  25. data/features/steps/xcpretty_steps.rb +31 -0
  26. data/features/support/env.rb +108 -0
  27. data/features/tap_format.feature +31 -0
  28. data/features/test_format.feature +39 -0
  29. data/features/xcpretty.feature +14 -0
  30. data/learn-xcpretty.gemspec +37 -0
  31. data/lib/xcpretty/ansi.rb +71 -0
  32. data/lib/xcpretty/formatters/formatter.rb +134 -0
  33. data/lib/xcpretty/formatters/knock.rb +34 -0
  34. data/lib/xcpretty/formatters/rspec.rb +27 -0
  35. data/lib/xcpretty/formatters/simple.rb +155 -0
  36. data/lib/xcpretty/formatters/tap.rb +39 -0
  37. data/lib/xcpretty/parser.rb +421 -0
  38. data/lib/xcpretty/printer.rb +20 -0
  39. data/lib/xcpretty/reporters/html.rb +73 -0
  40. data/lib/xcpretty/reporters/json_compilation_database.rb +58 -0
  41. data/lib/xcpretty/reporters/junit.rb +99 -0
  42. data/lib/xcpretty/reporters/learn.rb +154 -0
  43. data/lib/xcpretty/snippet.rb +34 -0
  44. data/lib/xcpretty/syntax.rb +20 -0
  45. data/lib/xcpretty/version.rb +3 -0
  46. data/lib/xcpretty.rb +39 -0
  47. data/spec/fixtures/NSStringTests.m +64 -0
  48. data/spec/fixtures/constants.rb +546 -0
  49. data/spec/fixtures/custom_formatter.rb +17 -0
  50. data/spec/fixtures/oneliner.m +1 -0
  51. data/spec/fixtures/raw_kiwi_compilation_fail.txt +24 -0
  52. data/spec/fixtures/raw_kiwi_fail.txt +1896 -0
  53. data/spec/fixtures/raw_specta_fail.txt +3110 -0
  54. data/spec/spec_helper.rb +6 -0
  55. data/spec/support/matchers/colors.rb +20 -0
  56. data/spec/xcpretty/ansi_spec.rb +46 -0
  57. data/spec/xcpretty/formatters/formatter_spec.rb +113 -0
  58. data/spec/xcpretty/formatters/rspec_spec.rb +55 -0
  59. data/spec/xcpretty/formatters/simple_spec.rb +129 -0
  60. data/spec/xcpretty/parser_spec.rb +421 -0
  61. data/spec/xcpretty/printer_spec.rb +53 -0
  62. data/spec/xcpretty/snippet_spec.rb +39 -0
  63. data/spec/xcpretty/syntax_spec.rb +35 -0
  64. data/vendor/json_pure/COPYING +57 -0
  65. data/vendor/json_pure/LICENSE +340 -0
  66. data/vendor/json_pure/generator.rb +443 -0
  67. data/vendor/json_pure/parser.rb +364 -0
  68. metadata +261 -0
@@ -0,0 +1,20 @@
1
+ require "xcpretty/ansi"
2
+
3
+ module XCPretty
4
+
5
+ class Printer
6
+
7
+ attr_reader :formatter
8
+
9
+ def initialize(params)
10
+ klass = params[:formatter]
11
+ @formatter = klass.new(params[:unicode], params[:colorize])
12
+ end
13
+
14
+ def pretty_print(text)
15
+ formatted_text = formatter.pretty_format(text)
16
+ STDOUT.print(formatted_text + formatter.optional_newline) unless formatted_text.empty?
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,73 @@
1
+ module XCPretty
2
+ class HTML
3
+
4
+ include XCPretty::FormatMethods
5
+ FILEPATH = 'build/reports/tests.html'
6
+ TEMPLATE = File.expand_path('../../../../assets/report.html.erb', __FILE__)
7
+
8
+ def load_dependencies
9
+ unless @@loaded ||= false
10
+ require 'fileutils'
11
+ require 'pathname'
12
+ require 'erb'
13
+ @@loaded = true
14
+ end
15
+ end
16
+
17
+ def initialize(options)
18
+ load_dependencies
19
+ @test_suites = {}
20
+ @filepath = options[:path] || FILEPATH
21
+ @parser = Parser.new(self)
22
+ @test_count = 0
23
+ @fail_count = 0
24
+ end
25
+
26
+ def handle(line)
27
+ @parser.parse(line)
28
+ end
29
+
30
+ def format_failing_test(suite, test_case, reason, file)
31
+ add_test(suite, {:name => test_case, :failing => true,
32
+ :reason => reason, :file => file, :snippet => formatted_snippet(file)})
33
+ end
34
+
35
+ def format_passing_test(suite, test_case, time)
36
+ add_test(suite, {:name => test_case, :time => time})
37
+ end
38
+
39
+ def finish
40
+ FileUtils.mkdir_p(File.dirname(@filepath))
41
+ write_report
42
+ end
43
+
44
+ private
45
+
46
+ def formatted_snippet(filepath)
47
+ snippet = Snippet.from_filepath(filepath)
48
+ Syntax.highlight(snippet, "-f html -O style=colorful -O noclasses")
49
+ end
50
+
51
+
52
+ def add_test(suite_name, data)
53
+ @test_count += 1
54
+ @test_suites[suite_name] ||= {:tests => []}
55
+ @test_suites[suite_name][:tests] << data
56
+ if data[:failing]
57
+ @test_suites[suite_name][:failing] = true
58
+ @fail_count += 1
59
+ end
60
+ end
61
+
62
+ def write_report
63
+ File.open(@filepath, 'w') do |f|
64
+ # WAT: get rid of these locals. BTW Cucumber fails if you remove them
65
+ test_suites = @test_suites
66
+ fail_count = @fail_count
67
+ test_count = @test_count
68
+ erb = ERB.new(File.open(TEMPLATE, 'r').read)
69
+ f.write erb.result(binding)
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,58 @@
1
+ module XCPretty
2
+ class JSONCompilationDatabase
3
+
4
+ include XCPretty::FormatMethods
5
+ FILEPATH = 'build/reports/compilation_db.json'
6
+
7
+ def load_dependencies
8
+ unless @@loaded ||= false
9
+ require 'fileutils'
10
+ require 'pathname'
11
+ unless Object.const_defined?(:JSON)
12
+ begin
13
+ require 'json'
14
+ rescue LoadError
15
+ require File.expand_path(File.join(File.dirname(__FILE__),'../../../vendor/json_pure/generator'))
16
+ end
17
+ end
18
+ @@loaded = true
19
+ end
20
+ end
21
+
22
+ def initialize(options)
23
+ load_dependencies
24
+ @filepath = options[:path] || FILEPATH
25
+ @parser = Parser.new(self)
26
+ @compilation_units = []
27
+ @current_file = nil
28
+ @current_path = nil
29
+ end
30
+
31
+ def handle(line)
32
+ @parser.parse(line)
33
+ end
34
+
35
+ def format_compile(file_name, file_path)
36
+ @current_file = file_name
37
+ @current_path = File.dirname(file_path)
38
+ end
39
+
40
+ def format_compile_command(compiler_command)
41
+ @compilation_units << { :command => compiler_command,
42
+ :file => @current_file, :directory => @current_path }
43
+ end
44
+
45
+ def finish
46
+ FileUtils.mkdir_p(File.dirname(@filepath))
47
+ write_report
48
+ end
49
+
50
+ private
51
+
52
+ def write_report
53
+ File.open(@filepath, 'w') do |f|
54
+ f.write(@compilation_units.to_json)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,99 @@
1
+ module XCPretty
2
+ class JUnit
3
+
4
+ include XCPretty::FormatMethods
5
+ FILEPATH = 'build/reports/junit.xml'
6
+
7
+ def load_dependencies
8
+ unless @@loaded ||= false
9
+ require 'fileutils'
10
+ require 'pathname'
11
+ require 'rexml/document'
12
+ require 'rexml/formatters/pretty'
13
+ @@loaded = true
14
+ end
15
+ end
16
+
17
+ def initialize(options)
18
+ load_dependencies
19
+ @filepath = options[:path] || FILEPATH
20
+ @directory = `pwd`.strip
21
+ @document = REXML::Document.new
22
+ @document << REXML::XMLDecl.new('1.0','UTF-8')
23
+ @document.add_element('testsuites')
24
+ @parser = Parser.new(self)
25
+ @total_tests = 0
26
+ @total_fails = 0
27
+ end
28
+
29
+ def handle(line)
30
+ @parser.parse(line)
31
+ end
32
+
33
+ def format_passing_test(classname, test_case, time)
34
+ test_node = suite(classname).add_element('testcase')
35
+ test_node.attributes['classname'] = classname
36
+ test_node.attributes['name'] = test_case
37
+ test_node.attributes['time'] = time
38
+ @test_count += 1
39
+ end
40
+
41
+ def format_pending_test(classname, test_case)
42
+ test_node = suite(classname).add_element('testcase')
43
+ test_node.attributes['classname'] = classname
44
+ test_node.attributes['name'] = test_case
45
+ test_node.add_element('skipped')
46
+ @test_count += 1
47
+ end
48
+
49
+ def format_failing_test(classname, test_case, reason, file)
50
+ test_node = suite(classname).add_element('testcase')
51
+ test_node.attributes['classname'] = classname
52
+ test_node.attributes['name'] = test_case
53
+ fail_node = test_node.add_element('failure')
54
+ fail_node.attributes['message'] = reason
55
+ fail_node.text = file.sub(@directory + '/', '')
56
+ @test_count += 1
57
+ @fail_count += 1
58
+ end
59
+
60
+ def finish
61
+ set_test_counters
62
+ @document.root.attributes['tests'] = @total_tests
63
+ @document.root.attributes['failures'] = @total_fails
64
+ write_report_file
65
+ end
66
+
67
+ private
68
+
69
+ def write_report_file
70
+ FileUtils.mkdir_p(File.dirname(@filepath))
71
+ formatter = REXML::Formatters::Pretty.new(2)
72
+ formatter.compact = true
73
+ output_file = File.open(@filepath, 'w+')
74
+ result = formatter.write(@document, output_file)
75
+ output_file.close
76
+ result
77
+ end
78
+
79
+ def suite(classname)
80
+ return @last_suite if @last_suite && @last_suite.attributes['name'] == classname
81
+
82
+ set_test_counters
83
+ @last_suite = @document.root.add_element('testsuite')
84
+ @last_suite.attributes['name'] = classname
85
+ @last_suite
86
+ end
87
+
88
+ def set_test_counters
89
+ if @last_suite
90
+ @last_suite.attributes['tests'] = @test_count
91
+ @last_suite.attributes['failures'] = @fail_count
92
+ end
93
+ @total_fails += @fail_count || 0
94
+ @total_tests += @test_count || 0
95
+ @test_count = 0
96
+ @fail_count = 0
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,154 @@
1
+ module XCPretty
2
+ class Learn
3
+ SERVICE_URL = 'http://ironbroker.flatironschool.com'
4
+ SERVICE_ENDPOINT = '/e/flatiron_xcpretty/build'
5
+
6
+ include XCPretty::FormatMethods
7
+
8
+ def load_dependencies
9
+ unless @@loaded ||= false
10
+ require 'fileutils'
11
+ require 'pathname'
12
+ require 'json'
13
+ require 'faraday'
14
+ require 'netrc'
15
+ require 'git'
16
+ require 'oj'
17
+ @@loaded = true
18
+ end
19
+ end
20
+
21
+ def initialize(options)
22
+ load_dependencies
23
+ @formatted_output = {
24
+ username: UsernameParser.get_username,
25
+ github_user_id: UserIdParser.get_user_id,
26
+ repo_name: RepoParser.get_repo,
27
+ build: {
28
+ test_suite: [{
29
+ framework: 'xcpretty',
30
+ formatted_output: [],
31
+ duration: 0.0,
32
+ build_output: [],
33
+ }]
34
+ },
35
+ total_count: 0,
36
+ passing_count: 0,
37
+ failure_count: 0
38
+ }
39
+
40
+ @parser = Parser.new(self)
41
+
42
+ @connection = Faraday.new(url: SERVICE_URL) do |faraday|
43
+ faraday.adapter Faraday.default_adapter
44
+ end
45
+ end
46
+
47
+ def handle(line)
48
+ @parser.parse(line)
49
+ end
50
+
51
+ def format_passing_test(classname, test_case, time)
52
+ pass = {classname: classname, name: test_case, time: time}
53
+ @formatted_output[:build][:test_suite][0][:formatted_output] << pass
54
+ @formatted_output[:total_count] += 1
55
+ @formatted_output[:passing_count] += 1
56
+ end
57
+
58
+ def format_failing_test(classname, test_case, reason, file)
59
+ failure = {classname: classname, name: test_case, file: file, reason: reason}
60
+ @formatted_output[:build][:test_suite][0][:formatted_output] << failure
61
+ @formatted_output[:total_count] += 1
62
+ @formatted_output[:failure_count] += 1
63
+ end
64
+
65
+ def finish
66
+ write_report_file
67
+ end
68
+
69
+ private
70
+
71
+ def write_report_file
72
+ @connection.post do |req|
73
+ req.url SERVICE_ENDPOINT
74
+ req.headers['Content-Type'] = 'application/json'
75
+ req.body = @formatted_output.to_json
76
+ end
77
+ end
78
+ end
79
+
80
+ class UsernameParser
81
+ def self.get_username
82
+ parser = NetrcInteractor.new
83
+ username = parser.username
84
+
85
+ if !username
86
+ print "Enter your github username: "
87
+ username = gets.strip
88
+ user_id = GitHubInteractor.get_user_id_for(username)
89
+ parser.write(username, user_id)
90
+ end
91
+
92
+ username
93
+ end
94
+ end
95
+
96
+ class UserIdParser
97
+ def self.get_user_id
98
+ parser = NetrcInteractor.new
99
+ user_id = parser.user_id
100
+ end
101
+ end
102
+
103
+ class GitHubInteractor
104
+ attr_reader :username, :user_id
105
+
106
+ def self.get_user_id_for(username)
107
+ new(username).get_user_id
108
+ end
109
+
110
+ def initialize(username)
111
+ @username = username
112
+ end
113
+
114
+ def get_user_id
115
+ @user_id ||= Oj.load(
116
+ open("https://api.github.com/users/#{username}").read,
117
+ symbol_keys: true
118
+ )[:id]
119
+ end
120
+ end
121
+
122
+ class NetrcInteractor
123
+ attr_reader :username, :user_id, :netrc
124
+
125
+ def initialize
126
+ @netrc = Netrc.read
127
+ @username, @user_id = netrc["flatiron-push"]
128
+ end
129
+
130
+ def write(username, user_id)
131
+ netrc["flatiron-push"] = username, user_id
132
+ netrc.save
133
+ end
134
+ end
135
+
136
+ class RepoParser
137
+ def self.get_repo
138
+ begin
139
+ repo = Git.open(File.expand_path(".", Dir.pwd))
140
+ rescue
141
+ puts "Not a valid Git repository"
142
+ die
143
+ end
144
+
145
+ url = repo.remote.url
146
+
147
+ repo_name = url.match(/(?:https:\/\/|git@).*\/(.+)(?:\.git)/)[1]
148
+ end
149
+
150
+ def self.die
151
+ exit
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,34 @@
1
+ module XCPretty
2
+ class Snippet
3
+
4
+ def self.from_filepath(filepath)
5
+ path, line = filepath.split(':')
6
+ file = File.open(path)
7
+
8
+ text = read_snippet(file, line)
9
+
10
+ file.close
11
+ text
12
+ rescue
13
+ ''
14
+ end
15
+
16
+
17
+ private
18
+
19
+ def self.read_snippet(file, around_line)
20
+ text = ""
21
+ starting_position = around_line.to_i - 2
22
+ starting_position.times { file.gets }
23
+ 3.times { text += readline(file) }
24
+ text
25
+ end
26
+
27
+ def self.readline(file)
28
+ file.gets
29
+ $_ || ''
30
+ end
31
+
32
+ end
33
+ end
34
+
@@ -0,0 +1,20 @@
1
+ module XCPretty
2
+ class Syntax
3
+
4
+ def self.highlight(code, options="")
5
+ pygments_available? ? pygmentize(code, options) : code
6
+ end
7
+
8
+
9
+ private
10
+
11
+ def self.pygments_available?
12
+ @available = system('which pygmentize > /dev/null') if @available.nil?
13
+ @available
14
+ end
15
+
16
+ def self.pygmentize(code, options)
17
+ `echo "#{code}" | pygmentize -l objc #{options}`
18
+ end
19
+ end
20
+ end