xcpretty 0.0.6 → 0.0.7

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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +3 -1
  4. data/CHANGELOG.md +24 -0
  5. data/README.md +3 -1
  6. data/Rakefile +6 -1
  7. data/bin/xcpretty +51 -16
  8. data/features/custom_formatter.feature +15 -0
  9. data/features/junit_report.feature +9 -1
  10. data/features/simple_format.feature +68 -4
  11. data/features/steps/formatting_steps.rb +87 -4
  12. data/features/steps/junit_steps.rb +18 -6
  13. data/features/steps/xcpretty_steps.rb +7 -0
  14. data/features/support/env.rb +18 -15
  15. data/features/test_format.feature +1 -0
  16. data/features/xcpretty.feature +12 -0
  17. data/lib/xcpretty.rb +25 -3
  18. data/lib/xcpretty/ansi.rb +1 -0
  19. data/lib/xcpretty/formatters/formatter.rb +90 -0
  20. data/lib/xcpretty/formatters/rspec.rb +22 -0
  21. data/lib/xcpretty/formatters/simple.rb +137 -0
  22. data/lib/xcpretty/parser.rb +283 -0
  23. data/lib/xcpretty/printer.rb +7 -112
  24. data/lib/xcpretty/reporters/junit.rb +53 -45
  25. data/lib/xcpretty/syntax.rb +22 -0
  26. data/lib/xcpretty/version.rb +1 -1
  27. data/spec/fixtures/constants.rb +63 -15
  28. data/spec/fixtures/custom_formatter.rb +17 -0
  29. data/spec/spec_helper.rb +1 -1
  30. data/spec/support/matchers/colors.rb +1 -1
  31. data/spec/xcpretty/formatters/formatter_spec.rb +56 -0
  32. data/spec/xcpretty/formatters/rspec_spec.rb +46 -0
  33. data/spec/xcpretty/formatters/simple_spec.rb +132 -0
  34. data/spec/xcpretty/parser_spec.rb +258 -0
  35. data/spec/xcpretty/printer_spec.rb +39 -74
  36. data/spec/xcpretty/syntax_spec.rb +35 -0
  37. data/xcpretty.gemspec +1 -1
  38. metadata +40 -25
  39. data/lib/xcpretty/printers/rspec.rb +0 -23
  40. data/lib/xcpretty/printers/simple.rb +0 -153
  41. data/spec/xcpretty/printers/printer_spec.rb +0 -117
  42. data/spec/xcpretty/printers/rspec_spec.rb +0 -52
  43. data/spec/xcpretty/printers/simple_spec.rb +0 -125
@@ -1,21 +1,33 @@
1
+ Given(/^I have tests in my suite from 2 classes$/) do
2
+ add_run_input SAMPLE_OCUNIT_TEST
3
+ add_run_input SAMPLE_KIWI_TEST
4
+ end
5
+
1
6
  Then(/^I should see a failed test node in my report$/) do
2
- junit_report.root.elements.to_a.detect do |node|
7
+ junit_report_root.elements.to_a.detect do |node|
3
8
  element = node.elements.to_a.first
4
9
  element && element.name == "failure"
5
10
  end.should_not be_nil
6
11
  end
7
12
 
8
13
  Then(/^I should see a passing test node in my report$/) do
9
- junit_report.root.elements.to_a.detect do |node|
14
+ junit_report_root.elements.to_a.detect do |node|
10
15
  node.attributes["time"] != nil
11
16
  end.should_not be_nil
12
17
  end
13
18
 
14
19
  Then(/^I should see a test suite node$/) do
15
- junit_report.root.should_not be_nil
20
+ junit_report_root.elements.to_a.first.should_not be_nil
16
21
  end
17
22
 
18
23
  Then(/^I should see (\d+) tests in my report$/) do |test_count|
19
- junit_report.root.attributes["tests"].should == test_count
20
- junit_report.root.elements.to_a.count.should == test_count.to_i
21
- end
24
+ junit_report_root.attributes["tests"].should == test_count
25
+ junit_report_root.elements.to_a.count.should == test_count.to_i
26
+ end
27
+
28
+ Then(/^I should see (\d+) test suites$/) do |count|
29
+ suites = junit_report.root.elements.to_a
30
+ suites.size.should == count.to_i
31
+ suites.select {|s| s.name == 'testsuite' }.size.should == count.to_i
32
+ end
33
+
@@ -0,0 +1,7 @@
1
+ Given(/^the build has failed$/) do
2
+ add_run_input "/Users/musalj/code/OSS/ObjectiveSugar/Example/ObjectiveSugarTests/NSArrayCategoriesTests.m:53:13: error: use of undeclared identifier 'something'"
3
+ end
4
+
5
+ Then(/^the exit status code should be (\d)$/) do |numbah|
6
+ $?.exitstatus.should == numbah.to_i
7
+ end
@@ -1,12 +1,13 @@
1
1
  $:.unshift File.expand_path('../../..', __FILE__)
2
2
 
3
- require "tempfile"
4
- require "spec/fixtures/constants"
5
- require "spec/support/matchers/colors"
6
- require "lib/xcpretty/ansi"
7
- require "rexml/document"
8
- require "lib/xcpretty/printer"
9
- require "lib/xcpretty/reporters/junit"
3
+ require 'tempfile'
4
+ require 'spec/fixtures/constants'
5
+ require 'spec/support/matchers/colors'
6
+ require 'lib/xcpretty/ansi'
7
+ require 'lib/xcpretty/syntax'
8
+ require 'rexml/document'
9
+ require 'lib/xcpretty/formatters/formatter'
10
+ require 'lib/xcpretty/reporters/junit'
10
11
 
11
12
  include XCPretty::ANSI
12
13
 
@@ -17,10 +18,8 @@ TEST_PATH_MATCHER = %r{[\w/\-\s]+:\d+}
17
18
  PASSING_TEST_NAME_MATCHER = %r{\w+\s\(\d+\.\d+\sseconds\)}
18
19
  FAILING_TEST_NAME_MATCHER = %r{\w+, expected:}
19
20
 
20
- def run_xcpretty flags
21
- add_run_input SAMPLE_OCUNIT_SUITE_COMPLETION
22
- add_run_input SAMPLE_EXECUTED_TESTS
23
- input_file = Tempfile.new("xcpretty_input")
21
+ def run_xcpretty(flags)
22
+ input_file = Tempfile.new('xcpretty_input')
24
23
  File.open(input_file.path, 'w') do |file|
25
24
  file.print run_input
26
25
  end
@@ -28,24 +27,28 @@ def run_xcpretty flags
28
27
  input_file.unlink
29
28
  end
30
29
 
31
- def add_run_input text
30
+ def add_run_input(text)
32
31
  run_input << "\n#{text}"
33
32
  end
34
33
 
35
34
  def run_input
36
- @input ||= ""
35
+ @input ||= ''
37
36
  end
38
37
 
39
38
  def run_output
40
- @output ||= ""
39
+ @output ||= ''
41
40
  end
42
41
 
43
42
  def junit_report
44
43
  REXML::Document.new(File.open(XCPretty::JUnit::FILEPATH, 'r').read)
45
44
  end
46
45
 
46
+ def junit_report_root
47
+ junit_report.root.elements.to_a.first
48
+ end
49
+
47
50
  Before do
48
- self.colorize = true
51
+ self.colorize = true
49
52
  end
50
53
 
51
54
  After do
@@ -12,6 +12,7 @@ Feature: Showing RSpec-style test output
12
12
 
13
13
  Scenario: Showing some tests failed with color
14
14
  Given I have a failing test in my suite
15
+ And the test suite has finished
15
16
  When I pipe to xcpretty with "--test --color"
16
17
  Then I should see a red failed test icon
17
18
  And I should see the path of a failed test
@@ -0,0 +1,12 @@
1
+ Feature: Status codes
2
+
3
+ Scenario: Xcode tests have failed
4
+ Given I have a failing test in my suite
5
+ When I pipe to xcpretty
6
+ Then the exit status code should be 1
7
+
8
+ Scenario: Xcode build has failed
9
+ Given the build has failed
10
+ When I pipe to xcpretty
11
+ Then the exit status code should be 1
12
+
data/lib/xcpretty.rb CHANGED
@@ -1,9 +1,31 @@
1
1
  require "xcpretty/version"
2
2
  require "xcpretty/printer"
3
- require "xcpretty/printers/simple"
4
- require "xcpretty/printers/rspec"
3
+ require "xcpretty/syntax"
4
+ require "xcpretty/formatters/formatter"
5
+ require "xcpretty/formatters/simple"
6
+ require "xcpretty/formatters/rspec"
5
7
  require "xcpretty/reporters/junit"
6
8
 
7
9
  module XCPretty
8
- # Your code goes here...
10
+ class ExitStatus
11
+
12
+ include XCPretty::Matchers
13
+
14
+ POSSIBLE_FAILURES = [
15
+ FAILING_TEST_MATCHER,
16
+ /\serror:\s/
17
+ ]
18
+
19
+ def self.code
20
+ $exit_status || 0
21
+ end
22
+
23
+ def self.handle(text)
24
+ POSSIBLE_FAILURES.detect do |failure|
25
+ $exit_status = 1 if text =~ failure
26
+ end
27
+ end
28
+
29
+ end
9
30
  end
31
+
data/lib/xcpretty/ansi.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  module XCPretty
2
2
  module ANSI
3
+
3
4
  attr_accessor :colorize
4
5
 
5
6
  FORMATTED_MATCHER = %r{\e\[(\d+)[;]?(\d+)?m(.*)\e\[0m}
@@ -0,0 +1,90 @@
1
+ require 'xcpretty/ansi'
2
+ require 'xcpretty/parser'
3
+
4
+ module XCPretty
5
+
6
+ # Making a new formatter is easy.
7
+ # Just make a subclass of Formatter, and override any of these methods.
8
+ module FormatMethods
9
+ EMPTY_STRING = ''
10
+ def format_analyze(file_name, file_path); EMPTY_STRING; end
11
+ def format_build_target(target, project, configuration); EMPTY_STRING; end
12
+ def format_check_dependencies; EMPTY_STRING; end
13
+ def format_clean(project, target, configuration); EMPTY_STRING; end
14
+ def format_clean_target(target, project, configuration); EMPTY_STRING; end
15
+ def format_clean_remove; EMPTY_STRING; end
16
+ def format_compile(file_name, file_path); EMPTY_STRING; end
17
+ def format_compile_error(file_name, file_path, reason, line, cursor); EMPTY_STRING; end
18
+ def format_compile_xib(file_name, file_path); EMPTY_STRING; end
19
+ def format_copy_strings_file(file_name); EMPTY_STRING; end
20
+ def format_cpresource(file); EMPTY_STRING; end
21
+ def format_error(message); EMPTY_STRING; end
22
+ def format_generate_dsym(dsym); EMPTY_STRING; end
23
+ def format_linking(file, build_variant, arch); EMPTY_STRING; end
24
+ def format_libtool(library); EMPTY_STRING; end
25
+ def format_passing_test(suite, test, time); EMPTY_STRING; end
26
+ def format_failing_test(suite, test, time, file_path); EMPTY_STRING; end
27
+ def format_process_pch(file); EMPTY_STRING; end
28
+ def format_phase_script_execution(script_name); EMPTY_STRING; end
29
+ def format_process_info_plist(file_name, file_path); EMPTY_STRING; end
30
+ def format_codesign(file); EMPTY_STRING; end
31
+ def format_preprocess(file); EMPTY_STRING; end
32
+ def format_pbxcp(file); EMPTY_STRING; end
33
+ def format_test_run_started(name); EMPTY_STRING; end
34
+ def format_test_run_finished(name, time); EMPTY_STRING; end
35
+ def format_test_suite_started(name); EMPTY_STRING; end
36
+ def format_test_summary(message, failures_per_suite); EMPTY_STRING; end
37
+ end
38
+
39
+ class Formatter
40
+
41
+ include ANSI
42
+ include FormatMethods
43
+
44
+ attr_reader :parser
45
+
46
+ def initialize(use_unicode, colorize)
47
+ @use_unicode = use_unicode
48
+ @colorize = colorize
49
+ @parser = Parser.new(self)
50
+ end
51
+
52
+ # Override if you want to catch something specific with your regex
53
+ def pretty_format(text)
54
+ parser.parse(text)
55
+ end
56
+
57
+ # If you want to print inline, override #optional_newline with ''
58
+ def optional_newline
59
+ "\n"
60
+ end
61
+
62
+ def use_unicode?
63
+ !!@use_unicode
64
+ end
65
+
66
+ # Will be printed by default. Override with '' if you don't want summary
67
+ def format_test_summary(executed_message, failures_per_suite)
68
+ failures = format_failures(failures_per_suite)
69
+ final_message = failures.empty? ? green(executed_message) : red(executed_message)
70
+
71
+ text = [failures, final_message].join("\n\n\n").strip
72
+ "\n\n#{text}"
73
+ end
74
+
75
+
76
+ private
77
+
78
+ def format_failures(failures_per_suite)
79
+ failures_per_suite.map do |suite, failures|
80
+ formatted_failures = failures.map do |f|
81
+ " #{f[:test_case]}, #{red(f[:reason])}\n #{cyan(f[:file])}"
82
+ end.join("\n\n")
83
+
84
+ "\n#{suite}\n#{formatted_failures}"
85
+ end.join("\n")
86
+ end
87
+
88
+ end
89
+ end
90
+
@@ -0,0 +1,22 @@
1
+ module XCPretty
2
+
3
+ class RSpec < Formatter
4
+
5
+ FAIL = "F"
6
+ PASS = "."
7
+
8
+ def optional_newline
9
+ ''
10
+ end
11
+
12
+ def format_passing_test(suite, test_case, time)
13
+ green(PASS)
14
+ end
15
+
16
+ def format_failing_test(test_suite, test_case, reason, file)
17
+ red(FAIL)
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -0,0 +1,137 @@
1
+ # encoding: utf-8
2
+ require 'shellwords'
3
+
4
+ module XCPretty
5
+
6
+ class Simple < Formatter
7
+
8
+ PASS = "✓"
9
+ FAIL = "✗"
10
+ ERROR = "⌦ "
11
+
12
+ ASCII_PASS = "."
13
+ ASCII_FAIL = "x"
14
+ ASCII_ERROR = "[!]"
15
+ COMPLETION = "▸"
16
+ ASCII_COMPLETION = ">"
17
+
18
+ def format_analyze(file_name, file_path)
19
+ format("Analyzing", file_name)
20
+ end
21
+
22
+ def format_build_target(target, project, configuration)
23
+ format("Building", "#{project}/#{target} [#{configuration}]")
24
+ end
25
+
26
+ def format_clean_target(target, project, configuration)
27
+ format("Cleaning", "#{project}/#{target} [#{configuration}]")
28
+ end
29
+
30
+ def format_compile(file_name, file_path)
31
+ format("Compiling", file_name)
32
+ end
33
+
34
+ def format_compile_xib(file_name, file_path)
35
+ format("Compiling", file_name)
36
+ end
37
+
38
+ def format_copy_strings_file(file)
39
+ format("Copying", file)
40
+ end
41
+
42
+ def format_cpresource(resource)
43
+ format("Copying", resource)
44
+ end
45
+
46
+ def format_error(message)
47
+ status_symbol(:error) + " " + red(message)
48
+ end
49
+
50
+ def format_compile_error(file, file_path, reason, line, cursor)
51
+ "\n#{file_path}: #{red(reason)}\n\n#{line}\n#{cyan(cursor)}\n\n"
52
+ end
53
+
54
+ def format_generate_dsym(dsym)
55
+ format("Generating '#{dsym}'")
56
+ end
57
+
58
+ def format_libtool(library)
59
+ format("Building library", library)
60
+ end
61
+
62
+ def format_linking(target, build_variants, arch)
63
+ format("Linking", target)
64
+ end
65
+
66
+ def format_failing_test(suite, test_case, reason, file)
67
+ format_test("#{test_case}, #{reason}", false)
68
+ end
69
+
70
+ def format_passing_test(suite, test_case, time)
71
+ format_test("#{test_case} (#{time} seconds)")
72
+ end
73
+
74
+ def format_phase_script_execution(script_name)
75
+ format("Running script", "'#{script_name}'")
76
+ end
77
+
78
+ def format_process_info_plist(file_name, file_path)
79
+ format("Processing", file_name)
80
+ end
81
+
82
+ def format_process_pch(file)
83
+ format("Precompiling", file)
84
+ end
85
+
86
+ def format_codesign(file)
87
+ format("Signing", file)
88
+ end
89
+
90
+ def format_preprocess(file)
91
+ format("Preprocessing", file)
92
+ end
93
+
94
+ def format_pbxcp(file)
95
+ format("Copying", file)
96
+ end
97
+
98
+ def format_test_run_started(name)
99
+ heading("Test Suite", name, "started")
100
+ end
101
+
102
+ def format_test_suite_started(name)
103
+ heading("", name, "")
104
+ end
105
+
106
+
107
+ private
108
+
109
+ def heading(prefix, text, description)
110
+ [prefix, white(text), description].join(" ").strip
111
+ end
112
+
113
+ def format(command, argument_text="", success=true)
114
+ [status_symbol(success ? :completion : :fail), white(command), argument_text].join(" ").strip
115
+ end
116
+
117
+ def format_test(test_case, success=true)
118
+ [status_symbol(success ? :pass : :fail), test_case].join(" ").strip
119
+ end
120
+
121
+ def status_symbol(status)
122
+ case status
123
+ when :pass
124
+ green(use_unicode? ? PASS : ASCII_PASS)
125
+ when :fail
126
+ red(use_unicode? ? FAIL : ASCII_FAIL)
127
+ when :error
128
+ red(use_unicode? ? ERROR : ASCII_ERROR)
129
+ when :completion
130
+ yellow(use_unicode? ? COMPLETION : ASCII_COMPLETION)
131
+ else
132
+ ""
133
+ end
134
+ end
135
+
136
+ end
137
+ end
@@ -0,0 +1,283 @@
1
+ module XCPretty
2
+
3
+ module Matchers
4
+
5
+ # @regex Captured groups
6
+ # $1 file_path
7
+ # $2 file_name
8
+ ANALYZE_MATCHER = /^Analyze(?:Shallow)?\s(.*\/(.*\.m))*/
9
+
10
+ # @regex Captured groups
11
+ # $1 target
12
+ # $2 project
13
+ # $3 configuration
14
+ BUILD_TARGET_MATCHER = /^=== BUILD TARGET\s(.*)\sOF PROJECT\s(.*)\sWITH.*CONFIGURATION\s(.*)\s===/
15
+
16
+ # @regex Nothing returned here for now
17
+ CHECK_DEPENDENCIES_MATCHER = /^Check dependencies/
18
+
19
+ # @regex Nothing returned here for now
20
+ CLEAN_REMOVE_MATCHER = /^Clean.Remove/
21
+
22
+ # @regex Captured groups
23
+ # $1 target
24
+ # $2 project
25
+ # $3 configuration
26
+ CLEAN_TARGET_MATCHER = /^=== CLEAN TARGET\s(.*)\sOF PROJECT\s(.*)\sWITH CONFIGURATION\s(.*)\s===/
27
+
28
+ # @regex Captured groups
29
+ # $1 = file
30
+ CODESIGN_MATCHER = /^CodeSign\s((?:\\ |[^ ])*)$/
31
+
32
+ # @regex Captured groups
33
+ # $1 = file
34
+ CODESIGN_FRAMEWORK_MATCHER = /^CodeSign\s((?:\\ |[^ ])*.framework)\/Versions/
35
+
36
+ # @regex Captured groups
37
+ # $1 file_path
38
+ # $2 file_name (e.g. KWNull.m)
39
+ COMPILE_MATCHER = /^CompileC\s.*\s(.*\/(.*\.m))\s.*/
40
+
41
+ # @regex Captured groups
42
+ # $1 = file_path
43
+ # $2 = file_name
44
+ # $3 = reason
45
+ COMPILE_ERROR_MATCHER = /^(.+\/(.*\.[h,m,c]).*):\serror:\s(.*)$/
46
+
47
+ # @regex Captured groups
48
+ # $1 file_path
49
+ # $2 file_name (e.g. MainMenu.xib)
50
+ COMPILE_XIB_MATCHER = /^CompileXIB\s(.*\/(.*\.xib))/
51
+
52
+ # @regex Captured groups
53
+ # $1 file
54
+ COPY_STRINGS_MATCHER = /^CopyStringsFile.*\/(.*.strings)/
55
+
56
+ # @regex Captured groups
57
+ # $1 resource
58
+ CPRESOURCE_MATCHER = /^CpResource\s(.*)\s\//
59
+
60
+ # @regex Captured groups
61
+ # $1 cursor (with whitespaces and tildes)
62
+ CURSOR_MATCHER = /^([\s~]*\^[\s~]*)$/
63
+
64
+ # @regex Captured groups
65
+ #
66
+ EXECUTED_MATCHER = /^Executed/
67
+
68
+ # @regex Captured groups
69
+ # $1 = file
70
+ # $2 = test_suite
71
+ # $3 = test_case
72
+ # $4 = reason
73
+ FAILING_TEST_MATCHER = /^(.+:\d+):\serror:\s[\+\-]\[(.*)\s(.*)\]\s:(?:\s'.*'\s\[FAILED\],)?\s(.*)/
74
+
75
+ # @regex Captured groups
76
+ # $1 = dsym
77
+ GENERATE_DSYM_MATCHER = /^GenerateDSYMFile \/.*\/(.*\.dSYM)/
78
+
79
+ # @regex Captured groups
80
+ # $1 = library
81
+ LIBTOOL_MATCHER = /^Libtool.*\/(.*\.a)/
82
+
83
+ # @regex Captured groups
84
+ # $1 = target
85
+ # $2 = build_variants (normal, profile, debug)
86
+ # $3 = architecture
87
+ LINKING_MATCHER = /^Ld \/.*\/(.*) (.*) (.*)$/
88
+
89
+ # @regex Captured groups
90
+ # $1 = suite
91
+ # $2 = test_case
92
+ # $3 = time
93
+ PASSING_TEST_MATCHER = /^Test Case\s'-\[(.*)\s(.*)\]'\spassed\s\((\d*\.\d{3})\sseconds\)/
94
+
95
+ # @regex Captured groups
96
+ # $1 = script_name
97
+ PHASE_SCRIPT_EXECUTION_MATCHER = /^PhaseScriptExecution\s(.*)\s\//
98
+
99
+ # @regex Captured groups
100
+ PODS_ERROR_MATCHER = /^error:\s(.*)/
101
+
102
+ # @regex Captured groups
103
+ # $1 = file
104
+ PROCESS_PCH_MATCHER = /^ProcessPCH\s.*\s(.*.pch)/
105
+
106
+ # @regex Captured groups
107
+ # $1 = file
108
+ PREPROCESS_MATCHER = /^Preprocess\s(?:(?:\\ |[^ ])*)\s((?:\\ |[^ ])*)$/
109
+
110
+ # @regex Captured groups
111
+ # $1 = file
112
+ PBXCP_MATCHER = /^PBXCp\s((?:\\ |[^ ])*)/
113
+
114
+ # @regex Captured groups
115
+ # $1 = file
116
+ PROCESS_INFO_PLIST_MATCHER = /^ProcessInfoPlistFile\s.*\.plist\s(.*\/+(.*\.plist))/
117
+ # @regex Captured groups
118
+ # $1 = suite
119
+ # $2 = time
120
+ TESTS_RUN_COMPLETION_MATCHER = /Test Suite '(?:.*\/)?(.*[ox]ctest.*)' finished at (.*)/
121
+
122
+ # @regex Captured groups
123
+ # $1 = suite
124
+ # $2 = time
125
+ TESTS_RUN_START_MATCHER = /Test Suite '(?:.*\/)?(.*[ox]ctest.*)' started at(.*)/
126
+
127
+ # @regex Captured groups
128
+ # $1 test suite name
129
+ TEST_SUITE_START_MATCHER = /Test Suite '(.*)' started at/
130
+ end
131
+
132
+ class Parser
133
+
134
+ include Matchers
135
+ attr_reader :formatter
136
+
137
+ def initialize(formatter)
138
+ @formatter = formatter
139
+ end
140
+
141
+ def parse(text)
142
+ update_test_state(text)
143
+ update_error_state(text)
144
+
145
+ return format_error if should_format_error?
146
+
147
+ case text
148
+ when ANALYZE_MATCHER
149
+ formatter.format_analyze($2, $1)
150
+ when BUILD_TARGET_MATCHER
151
+ formatter.format_build_target($1, $2, $3)
152
+ when CLEAN_REMOVE_MATCHER
153
+ formatter.format_clean_remove
154
+ when CLEAN_TARGET_MATCHER
155
+ formatter.format_clean_target($1, $2, $3)
156
+ when COPY_STRINGS_MATCHER
157
+ formatter.format_copy_strings_file($1)
158
+ when CHECK_DEPENDENCIES_MATCHER
159
+ formatter.format_check_dependencies
160
+ when COMPILE_MATCHER
161
+ formatter.format_compile($2, $1)
162
+ when COMPILE_XIB_MATCHER
163
+ formatter.format_compile_xib($2, $1)
164
+ when CPRESOURCE_MATCHER
165
+ formatter.format_cpresource($1)
166
+ when EXECUTED_MATCHER
167
+ format_summary_if_needed(text)
168
+ when FAILING_TEST_MATCHER
169
+ formatter.format_failing_test($2, $3, $4, $1)
170
+ when GENERATE_DSYM_MATCHER
171
+ formatter.format_generate_dsym($1)
172
+ when LIBTOOL_MATCHER
173
+ formatter.format_libtool($1)
174
+ when LINKING_MATCHER
175
+ formatter.format_linking($1, $2, $3)
176
+ when PASSING_TEST_MATCHER
177
+ formatter.format_passing_test($1, $2, $3)
178
+ when PODS_ERROR_MATCHER
179
+ formatter.format_error($1)
180
+ when PROCESS_INFO_PLIST_MATCHER
181
+ formatter.format_process_info_plist(*unescaped($2, $1))
182
+ when PHASE_SCRIPT_EXECUTION_MATCHER
183
+ formatter.format_phase_script_execution(*unescaped($1))
184
+ when PROCESS_PCH_MATCHER
185
+ formatter.format_process_pch($1)
186
+ when CODESIGN_FRAMEWORK_MATCHER
187
+ formatter.format_codesign($1)
188
+ when CODESIGN_MATCHER
189
+ formatter.format_codesign($1)
190
+ when PREPROCESS_MATCHER
191
+ formatter.format_preprocess($1)
192
+ when PBXCP_MATCHER
193
+ formatter.format_pbxcp($1)
194
+ when TESTS_RUN_COMPLETION_MATCHER
195
+ formatter.format_test_run_finished($1, $2)
196
+ when TESTS_RUN_START_MATCHER
197
+ formatter.format_test_run_started($1)
198
+ when TEST_SUITE_START_MATCHER
199
+ formatter.format_test_suite_started($1)
200
+ else
201
+ ""
202
+ end
203
+ end
204
+
205
+ private
206
+
207
+ def update_test_state(text)
208
+ case text
209
+ when TESTS_RUN_START_MATCHER
210
+ @tests_done = false
211
+ @formatted_summary = false
212
+ @failures = {}
213
+ when TESTS_RUN_COMPLETION_MATCHER
214
+ @tests_done = true
215
+ when FAILING_TEST_MATCHER
216
+ store_failure($1, $2, $3, $4)
217
+ end
218
+ end
219
+
220
+ # @ return Hash { :file_name, :file_path, :reason, :line }
221
+ def update_error_state(text)
222
+ if text =~ COMPILE_ERROR_MATCHER
223
+ @formatting_error = true
224
+ current_error[:reason] = $3
225
+ current_error[:file_path] = $1
226
+ current_error[:file_name] = $2
227
+ elsif text =~ CURSOR_MATCHER
228
+ @formatting_error = false
229
+ current_error[:cursor] = $1.chomp
230
+ else
231
+ current_error[:line] = text.chomp if @formatting_error
232
+ end
233
+ end
234
+
235
+ # TODO: clean up the mess around all this
236
+ def should_format_error?
237
+ current_error[:reason] && current_error[:cursor] && current_error[:line]
238
+ end
239
+
240
+ def current_error
241
+ @current_error ||= {}
242
+ end
243
+
244
+ def format_error
245
+ error = current_error.dup
246
+ @current_error = {}
247
+ formatter.format_compile_error(error[:file_name],
248
+ error[:file_path],
249
+ error[:reason],
250
+ error[:line],
251
+ error[:cursor])
252
+ end
253
+
254
+ def store_failure(file, test_suite, test_case, reason)
255
+ failures_per_suite[test_suite] ||= []
256
+ failures_per_suite[test_suite] << {
257
+ :file => file,
258
+ :reason => reason,
259
+ :test_case => test_case,
260
+ }
261
+ end
262
+
263
+ def failures_per_suite
264
+ @failures ||= {}
265
+ end
266
+
267
+ def format_summary_if_needed(executed_message)
268
+ return "" unless should_format_summary?
269
+
270
+ @formatted_summary = true
271
+ formatter.format_test_summary(executed_message, failures_per_suite)
272
+ end
273
+
274
+ def should_format_summary?
275
+ @tests_done && !@formatted_summary
276
+ end
277
+
278
+ def unescaped(*escaped_values)
279
+ escaped_values.map { |v| v.gsub('\\', '') }
280
+ end
281
+
282
+ end
283
+ end