xcpretty 0.0.6 → 0.0.7

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