xcpretty-security-patched 0.3.0
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.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.hound.yml +2 -0
- data/.kick +17 -0
- data/.rubocop.yml +239 -0
- data/.travis.yml +12 -0
- data/CHANGELOG.md +269 -0
- data/CONTRIBUTING.md +64 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +61 -0
- data/README.md +95 -0
- data/Rakefile +18 -0
- data/assets/report.html.erb +173 -0
- data/bin/xcpretty +90 -0
- data/features/assets/RACCommandSpec_enabled_signal_should_send_YES_while_executing_is_YES.png +0 -0
- data/features/assets/apple_raw.png +0 -0
- data/features/custom_formatter.feature +15 -0
- data/features/custom_reporter.feature +29 -0
- data/features/fixtures/xcodebuild.log +5963 -0
- data/features/html_report.feature +54 -0
- data/features/json_compilation_database_report.feature +33 -0
- data/features/junit_report.feature +49 -0
- data/features/knock_format.feature +11 -0
- data/features/simple_format.feature +238 -0
- data/features/steps/custom_reporter_steps.rb +16 -0
- data/features/steps/formatting_steps.rb +386 -0
- data/features/steps/html_steps.rb +32 -0
- data/features/steps/json_steps.rb +45 -0
- data/features/steps/junit_steps.rb +39 -0
- data/features/steps/report_steps.rb +27 -0
- data/features/steps/xcpretty_steps.rb +31 -0
- data/features/support/env.rb +123 -0
- data/features/tap_format.feature +31 -0
- data/features/test_format.feature +49 -0
- data/features/xcpretty.feature +14 -0
- data/lib/xcpretty/ansi.rb +72 -0
- data/lib/xcpretty/formatters/formatter.rb +200 -0
- data/lib/xcpretty/formatters/knock.rb +35 -0
- data/lib/xcpretty/formatters/rspec.rb +33 -0
- data/lib/xcpretty/formatters/simple.rb +200 -0
- data/lib/xcpretty/formatters/tap.rb +40 -0
- data/lib/xcpretty/parser.rb +596 -0
- data/lib/xcpretty/printer.rb +28 -0
- data/lib/xcpretty/reporters/html.rb +93 -0
- data/lib/xcpretty/reporters/json_compilation_database.rb +51 -0
- data/lib/xcpretty/reporters/junit.rb +102 -0
- data/lib/xcpretty/reporters/reporter.rb +62 -0
- data/lib/xcpretty/snippet.rb +38 -0
- data/lib/xcpretty/syntax.rb +58 -0
- data/lib/xcpretty/term.rb +14 -0
- data/lib/xcpretty/version.rb +4 -0
- data/lib/xcpretty.rb +38 -0
- data/spec/fixtures/NSStringTests.m +64 -0
- data/spec/fixtures/constants.rb +707 -0
- data/spec/fixtures/custom_formatter.rb +18 -0
- data/spec/fixtures/custom_reporter.rb +30 -0
- data/spec/fixtures/oneliner.m +1 -0
- data/spec/fixtures/raw_kiwi_compilation_fail.txt +24 -0
- data/spec/fixtures/raw_kiwi_fail.txt +1896 -0
- data/spec/fixtures/raw_specta_fail.txt +3110 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/support/matchers/colors.rb +21 -0
- data/spec/xcpretty/ansi_spec.rb +47 -0
- data/spec/xcpretty/formatters/formatter_spec.rb +151 -0
- data/spec/xcpretty/formatters/rspec_spec.rb +56 -0
- data/spec/xcpretty/formatters/simple_spec.rb +178 -0
- data/spec/xcpretty/parser_spec.rb +636 -0
- data/spec/xcpretty/printer_spec.rb +55 -0
- data/spec/xcpretty/reporters/junit_spec.rb +20 -0
- data/spec/xcpretty/reporters/reporter_spec.rb +40 -0
- data/spec/xcpretty/snippet_spec.rb +46 -0
- data/spec/xcpretty/syntax_spec.rb +39 -0
- data/spec/xcpretty/term_spec.rb +26 -0
- data/xcpretty.gemspec +37 -0
- metadata +250 -0
@@ -0,0 +1,596 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module XCPretty
|
4
|
+
|
5
|
+
module Matchers
|
6
|
+
|
7
|
+
# @regex Captured groups
|
8
|
+
# $1 file_path
|
9
|
+
# $2 file_name
|
10
|
+
ANALYZE_MATCHER = /^Analyze(?:Shallow)?\s(.*\/(.*\.(?:m|mm|cc|cpp|c|cxx)))\s*/
|
11
|
+
|
12
|
+
# @regex Captured groups
|
13
|
+
# $1 target
|
14
|
+
# $2 project
|
15
|
+
# $3 configuration
|
16
|
+
BUILD_TARGET_MATCHER = /^=== BUILD TARGET\s(.*)\sOF PROJECT\s(.*)\sWITH.*CONFIGURATION\s(.*)\s===/
|
17
|
+
|
18
|
+
# @regex Captured groups
|
19
|
+
# $1 target
|
20
|
+
# $2 project
|
21
|
+
# $3 configuration
|
22
|
+
AGGREGATE_TARGET_MATCHER = /^=== BUILD AGGREGATE TARGET\s(.*)\sOF PROJECT\s(.*)\sWITH.*CONFIGURATION\s(.*)\s===/
|
23
|
+
|
24
|
+
# @regex Captured groups
|
25
|
+
# $1 target
|
26
|
+
# $2 project
|
27
|
+
# $3 configuration
|
28
|
+
ANALYZE_TARGET_MATCHER = /^=== ANALYZE TARGET\s(.*)\sOF PROJECT\s(.*)\sWITH.*CONFIGURATION\s(.*)\s===/
|
29
|
+
|
30
|
+
# @regex Nothing returned here for now
|
31
|
+
CHECK_DEPENDENCIES_MATCHER = /^Check dependencies/
|
32
|
+
|
33
|
+
# @regex Captured groups
|
34
|
+
# $1 command path
|
35
|
+
# $2 arguments
|
36
|
+
SHELL_COMMAND_MATCHER = /^\s{4}(cd|setenv|(?:[\w\/:\\\s\-.]+?\/)?[\w\-]+)\s(.*)$/
|
37
|
+
|
38
|
+
# @regex Nothing returned here for now
|
39
|
+
CLEAN_REMOVE_MATCHER = /^Clean.Remove/
|
40
|
+
|
41
|
+
# @regex Captured groups
|
42
|
+
# $1 target
|
43
|
+
# $2 project
|
44
|
+
# $3 configuration
|
45
|
+
CLEAN_TARGET_MATCHER = /^=== CLEAN TARGET\s(.*)\sOF PROJECT\s(.*)\sWITH CONFIGURATION\s(.*)\s===/
|
46
|
+
|
47
|
+
# @regex Captured groups
|
48
|
+
# $1 = file
|
49
|
+
CODESIGN_MATCHER = /^CodeSign\s((?:\\ |[^ ])*)$/
|
50
|
+
|
51
|
+
# @regex Captured groups
|
52
|
+
# $1 = file
|
53
|
+
CODESIGN_FRAMEWORK_MATCHER = /^CodeSign\s((?:\\ |[^ ])*.framework)\/Versions/
|
54
|
+
|
55
|
+
# @regex Captured groups
|
56
|
+
# $1 file_path
|
57
|
+
# $2 file_name (e.g. KWNull.m)
|
58
|
+
COMPILE_MATCHER = /^Compile[\w]+\s.+?\s((?:\\.|[^ ])+\/((?:\\.|[^ ])+\.(?:m|mm|c|cc|cpp|cxx|swift)))\s.*/
|
59
|
+
|
60
|
+
# @regex Captured groups
|
61
|
+
# $1 compiler_command
|
62
|
+
# $2 file_path
|
63
|
+
COMPILE_COMMAND_MATCHER = /^\s*(.*clang\s.*\s\-c\s(.*\.(?:m|mm|c|cc|cpp|cxx))\s.*\.o)$/
|
64
|
+
|
65
|
+
# @regex Captured groups
|
66
|
+
# $1 file_path
|
67
|
+
# $2 file_name (e.g. MainMenu.xib)
|
68
|
+
COMPILE_XIB_MATCHER = /^CompileXIB\s(.*\/(.*\.xib))/
|
69
|
+
|
70
|
+
# @regex Captured groups
|
71
|
+
# $1 file_path
|
72
|
+
# $2 file_name (e.g. Main.storyboard)
|
73
|
+
COMPILE_STORYBOARD_MATCHER = /^CompileStoryboard\s(.*\/([^\/].*\.storyboard))/
|
74
|
+
|
75
|
+
# @regex Captured groups
|
76
|
+
# $1 source file
|
77
|
+
# $2 target file
|
78
|
+
COPY_HEADER_MATCHER = /^CpHeader\s(.*\.h)\s(.*\.h)/
|
79
|
+
|
80
|
+
# @regex Captured groups
|
81
|
+
# $1 source file
|
82
|
+
# $2 target file
|
83
|
+
COPY_PLIST_MATCHER = /^CopyPlistFile\s(.*\.plist)\s(.*\.plist)/
|
84
|
+
|
85
|
+
# $1 file
|
86
|
+
COPY_STRINGS_MATCHER = /^CopyStringsFile.*\/(.*.strings)/
|
87
|
+
|
88
|
+
# @regex Captured groups
|
89
|
+
# $1 resource
|
90
|
+
CPRESOURCE_MATCHER = /^CpResource\s(.*)\s\//
|
91
|
+
|
92
|
+
# @regex Captured groups
|
93
|
+
#
|
94
|
+
EXECUTED_MATCHER = /^\s*Executed/
|
95
|
+
|
96
|
+
# @regex Captured groups
|
97
|
+
# $1 = file
|
98
|
+
# $2 = test_suite
|
99
|
+
# $3 = test_case
|
100
|
+
# $4 = reason
|
101
|
+
FAILING_TEST_MATCHER = /^\s*(.+:\d+):\serror:\s[\+\-]\[(.*)\s(.*)\]\s:(?:\s'.*'\s\[FAILED\],)?\s(.*)/
|
102
|
+
|
103
|
+
# @regex Captured groups
|
104
|
+
# $1 = file
|
105
|
+
# $2 = reason
|
106
|
+
UI_FAILING_TEST_MATCHER = /^\s{4}t = \s+\d+\.\d+s\s+Assertion Failure: (.*:\d+): (.*)$/
|
107
|
+
|
108
|
+
# @regex Captured groups
|
109
|
+
RESTARTING_TESTS_MATCHER = /^Restarting after unexpected exit or crash in.+$/
|
110
|
+
|
111
|
+
# @regex Captured groups
|
112
|
+
# $1 = dsym
|
113
|
+
GENERATE_DSYM_MATCHER = /^GenerateDSYMFile \/.*\/(.*\.dSYM)/
|
114
|
+
|
115
|
+
# @regex Captured groups
|
116
|
+
# $1 = library
|
117
|
+
LIBTOOL_MATCHER = /^Libtool.*\/(.*\.a)/
|
118
|
+
|
119
|
+
# @regex Captured groups
|
120
|
+
# $1 = target
|
121
|
+
# $2 = build_variants (normal, profile, debug)
|
122
|
+
# $3 = architecture
|
123
|
+
LINKING_MATCHER = /^Ld \/?.*\/(.*?) (.*) (.*)$/
|
124
|
+
|
125
|
+
# @regex Captured groups
|
126
|
+
# $1 = suite
|
127
|
+
# $2 = test_case
|
128
|
+
# $3 = time
|
129
|
+
TEST_CASE_PASSED_MATCHER = /^\s*Test Case\s'-\[(.*)\s(.*)\]'\spassed\s\((\d*\.\d{3})\sseconds\)/
|
130
|
+
|
131
|
+
|
132
|
+
# @regex Captured groups
|
133
|
+
# $1 = suite
|
134
|
+
# $2 = test_case
|
135
|
+
TEST_CASE_STARTED_MATCHER = /^Test Case '-\[(.*) (.*)\]' started.$/
|
136
|
+
|
137
|
+
# @regex Captured groups
|
138
|
+
# $1 = suite
|
139
|
+
# $2 = test_case
|
140
|
+
TEST_CASE_PENDING_MATCHER = /^Test Case\s'-\[(.*)\s(.*)PENDING\]'\spassed/
|
141
|
+
|
142
|
+
# @regex Captured groups
|
143
|
+
# $1 = suite
|
144
|
+
# $2 = test_case
|
145
|
+
# $3 = time
|
146
|
+
TEST_CASE_MEASURED_MATCHER = /^[^:]*:[^:]*:\sTest Case\s'-\[(.*)\s(.*)\]'\smeasured\s\[Time,\sseconds\]\saverage:\s(\d*\.\d{3}),/
|
147
|
+
|
148
|
+
PHASE_SUCCESS_MATCHER = /^\*\*\s(.*)\sSUCCEEDED\s\*\*/
|
149
|
+
|
150
|
+
# @regex Captured groups
|
151
|
+
# $1 = script_name
|
152
|
+
PHASE_SCRIPT_EXECUTION_MATCHER = /^PhaseScriptExecution\s((\\\ |\S)*)\s/
|
153
|
+
|
154
|
+
# @regex Captured groups
|
155
|
+
# $1 = file
|
156
|
+
PROCESS_PCH_MATCHER = /^ProcessPCH\s.*\s(.*.pch)/
|
157
|
+
|
158
|
+
# @regex Captured groups
|
159
|
+
# $1 file_path
|
160
|
+
PROCESS_PCH_COMMAND_MATCHER = /^\s*.*\/usr\/bin\/clang\s.*\s\-c\s(.*)\s\-o\s.*/
|
161
|
+
|
162
|
+
# @regex Captured groups
|
163
|
+
# $1 = file
|
164
|
+
PREPROCESS_MATCHER = /^Preprocess\s(?:(?:\\ |[^ ])*)\s((?:\\ |[^ ])*)$/
|
165
|
+
|
166
|
+
# @regex Captured groups
|
167
|
+
# $1 = file
|
168
|
+
PBXCP_MATCHER = /^PBXCp\s((?:\\ |[^ ])*)/
|
169
|
+
|
170
|
+
# @regex Captured groups
|
171
|
+
# $1 = file
|
172
|
+
PROCESS_INFO_PLIST_MATCHER = /^ProcessInfoPlistFile\s.*\.plist\s(.*\/+(.*\.plist))/
|
173
|
+
|
174
|
+
# @regex Captured groups
|
175
|
+
# $1 = suite
|
176
|
+
# $2 = time
|
177
|
+
TESTS_RUN_COMPLETION_MATCHER = /^\s*Test Suite '(?:.*\/)?(.*[ox]ctest.*)' (finished|passed|failed) at (.*)/
|
178
|
+
|
179
|
+
# @regex Captured groups
|
180
|
+
# $1 = suite
|
181
|
+
# $2 = time
|
182
|
+
TEST_SUITE_STARTED_MATCHER = /^\s*Test Suite '(?:.*\/)?(.*[ox]ctest.*)' started at(.*)/
|
183
|
+
|
184
|
+
# @regex Captured groups
|
185
|
+
# $1 test suite name
|
186
|
+
TEST_SUITE_START_MATCHER = /^\s*Test Suite '(.*)' started at/
|
187
|
+
|
188
|
+
# @regex Captured groups
|
189
|
+
# $1 file_name
|
190
|
+
TIFFUTIL_MATCHER = /^TiffUtil\s(.*)/
|
191
|
+
|
192
|
+
# @regex Captured groups
|
193
|
+
# $1 file_path
|
194
|
+
# $2 file_name
|
195
|
+
TOUCH_MATCHER = /^Touch\s(.*\/(.+))/
|
196
|
+
|
197
|
+
# @regex Captured groups
|
198
|
+
# $1 file_path
|
199
|
+
WRITE_FILE_MATCHER = /^write-file\s(.*)/
|
200
|
+
|
201
|
+
# @regex Captured groups
|
202
|
+
WRITE_AUXILIARY_FILES = /^Write auxiliary files/
|
203
|
+
|
204
|
+
module Warnings
|
205
|
+
# $1 = file_path
|
206
|
+
# $2 = file_name
|
207
|
+
# $3 = reason
|
208
|
+
COMPILE_WARNING_MATCHER = /^(\/.+\/(.*):.*:.*):\swarning:\s(.*)$/
|
209
|
+
|
210
|
+
# $1 = ld prefix
|
211
|
+
# $2 = warning message
|
212
|
+
LD_WARNING_MATCHER = /^(ld: )warning: (.*)/
|
213
|
+
|
214
|
+
# @regex Captured groups
|
215
|
+
# $1 = whole warning
|
216
|
+
GENERIC_WARNING_MATCHER = /^warning:\s(.*)$/
|
217
|
+
|
218
|
+
# @regex Captured groups
|
219
|
+
# $1 = whole warning
|
220
|
+
WILL_NOT_BE_CODE_SIGNED_MATCHER = /^(.* will not be code signed because .*)$/
|
221
|
+
end
|
222
|
+
|
223
|
+
module Errors
|
224
|
+
# @regex Captured groups
|
225
|
+
# $1 = whole error
|
226
|
+
CLANG_ERROR_MATCHER = /^(clang: error:.*)$/
|
227
|
+
|
228
|
+
# @regex Captured groups
|
229
|
+
# $1 = whole error
|
230
|
+
CHECK_DEPENDENCIES_ERRORS_MATCHER = /^(Code\s?Sign error:.*|Code signing is required for product type .* in SDK .*|No profile matching .* found:.*|Provisioning profile .* doesn't .*|Swift is unavailable on .*|.?Use Legacy Swift Language Version.*)$/
|
231
|
+
|
232
|
+
# @regex Captured groups
|
233
|
+
# $1 = whole error
|
234
|
+
PROVISIONING_PROFILE_REQUIRED_MATCHER = /^(.*requires a provisioning profile.*)$/
|
235
|
+
|
236
|
+
# @regex Captured groups
|
237
|
+
# $1 = whole error
|
238
|
+
NO_CERTIFICATE_MATCHER = /^(No certificate matching.*)$/
|
239
|
+
|
240
|
+
# @regex Captured groups
|
241
|
+
# $1 = file_path
|
242
|
+
# $2 = file_name
|
243
|
+
# $3 = reason
|
244
|
+
COMPILE_ERROR_MATCHER = /^(\/.+\/(.*):.*:.*):\s(?:fatal\s)?error:\s(.*)$/
|
245
|
+
|
246
|
+
# @regex Captured groups
|
247
|
+
# $1 cursor (with whitespaces and tildes)
|
248
|
+
CURSOR_MATCHER = /^([\s~]*\^[\s~]*)$/
|
249
|
+
|
250
|
+
# @regex Captured groups
|
251
|
+
# $1 = whole error.
|
252
|
+
# it varies a lot, not sure if it makes sense to catch everything separately
|
253
|
+
FATAL_ERROR_MATCHER = /^(fatal error:.*)$/
|
254
|
+
|
255
|
+
# @regex Captured groups
|
256
|
+
# $1 = whole error.
|
257
|
+
# $2 = file path
|
258
|
+
FILE_MISSING_ERROR_MATCHER = /^<unknown>:0:\s(error:\s.*)\s'(\/.+\/.*\..*)'$/
|
259
|
+
|
260
|
+
# @regex Captured groups
|
261
|
+
# $1 = whole error
|
262
|
+
LD_ERROR_MATCHER = /^(ld:.*)/
|
263
|
+
|
264
|
+
# @regex Captured groups
|
265
|
+
# $1 file path
|
266
|
+
LINKER_DUPLICATE_SYMBOLS_LOCATION_MATCHER = /^\s+(\/.*\.o[\)]?)$/
|
267
|
+
|
268
|
+
# @regex Captured groups
|
269
|
+
# $1 reason
|
270
|
+
LINKER_DUPLICATE_SYMBOLS_MATCHER = /^(duplicate symbol .*):$/
|
271
|
+
|
272
|
+
# @regex Captured groups
|
273
|
+
# $1 symbol location
|
274
|
+
LINKER_UNDEFINED_SYMBOL_LOCATION_MATCHER = /^(.* in .*\.o)$/
|
275
|
+
|
276
|
+
# @regex Captured groups
|
277
|
+
# $1 reason
|
278
|
+
LINKER_UNDEFINED_SYMBOLS_MATCHER = /^(Undefined symbols for architecture .*):$/
|
279
|
+
|
280
|
+
# @regex Captured groups
|
281
|
+
# $1 reason
|
282
|
+
PODS_ERROR_MATCHER = /^(error:\s.*)/
|
283
|
+
|
284
|
+
# @regex Captured groups
|
285
|
+
# $1 = reference
|
286
|
+
SYMBOL_REFERENCED_FROM_MATCHER = /\s+"(.*)", referenced from:$/
|
287
|
+
|
288
|
+
# @regex Captured groups
|
289
|
+
# $1 = error reason
|
290
|
+
MODULE_INCLUDES_ERROR_MATCHER = /^\<module-includes\>:.*?:.*?:\s(?:fatal\s)?(error:\s.*)$/
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
class Parser
|
295
|
+
|
296
|
+
include Matchers
|
297
|
+
include Matchers::Errors
|
298
|
+
include Matchers::Warnings
|
299
|
+
|
300
|
+
attr_reader :formatter
|
301
|
+
|
302
|
+
def initialize(formatter)
|
303
|
+
@formatter = formatter
|
304
|
+
end
|
305
|
+
|
306
|
+
def parse(text)
|
307
|
+
update_test_state(text)
|
308
|
+
update_error_state(text)
|
309
|
+
update_linker_failure_state(text)
|
310
|
+
|
311
|
+
return format_compile_error if should_format_error?
|
312
|
+
return format_compile_warning if should_format_warning?
|
313
|
+
return format_undefined_symbols if should_format_undefined_symbols?
|
314
|
+
return format_duplicate_symbols if should_format_duplicate_symbols?
|
315
|
+
|
316
|
+
case text
|
317
|
+
when ANALYZE_MATCHER
|
318
|
+
formatter.format_analyze($2, $1)
|
319
|
+
when BUILD_TARGET_MATCHER
|
320
|
+
formatter.format_build_target($1, $2, $3)
|
321
|
+
when AGGREGATE_TARGET_MATCHER
|
322
|
+
formatter.format_aggregate_target($1, $2, $3)
|
323
|
+
when ANALYZE_TARGET_MATCHER
|
324
|
+
formatter.format_analyze_target($1, $2, $3)
|
325
|
+
when CLEAN_REMOVE_MATCHER
|
326
|
+
formatter.format_clean_remove
|
327
|
+
when CLEAN_TARGET_MATCHER
|
328
|
+
formatter.format_clean_target($1, $2, $3)
|
329
|
+
when COPY_STRINGS_MATCHER
|
330
|
+
formatter.format_copy_strings_file($1)
|
331
|
+
when CHECK_DEPENDENCIES_MATCHER
|
332
|
+
formatter.format_check_dependencies
|
333
|
+
when CLANG_ERROR_MATCHER
|
334
|
+
formatter.format_error($1)
|
335
|
+
when CODESIGN_FRAMEWORK_MATCHER
|
336
|
+
formatter.format_codesign($1)
|
337
|
+
when CODESIGN_MATCHER
|
338
|
+
formatter.format_codesign($1)
|
339
|
+
when CHECK_DEPENDENCIES_ERRORS_MATCHER
|
340
|
+
formatter.format_error($1)
|
341
|
+
when PROVISIONING_PROFILE_REQUIRED_MATCHER
|
342
|
+
formatter.format_error($1)
|
343
|
+
when NO_CERTIFICATE_MATCHER
|
344
|
+
formatter.format_error($1)
|
345
|
+
when COMPILE_MATCHER
|
346
|
+
formatter.format_compile($2, $1)
|
347
|
+
when COMPILE_COMMAND_MATCHER
|
348
|
+
formatter.format_compile_command($1, $2)
|
349
|
+
when COMPILE_XIB_MATCHER
|
350
|
+
formatter.format_compile_xib($2, $1)
|
351
|
+
when COMPILE_STORYBOARD_MATCHER
|
352
|
+
formatter.format_compile_storyboard($2, $1)
|
353
|
+
when COPY_HEADER_MATCHER
|
354
|
+
formatter.format_copy_header_file($1, $2)
|
355
|
+
when COPY_PLIST_MATCHER
|
356
|
+
formatter.format_copy_plist_file($1, $2)
|
357
|
+
when CPRESOURCE_MATCHER
|
358
|
+
formatter.format_cpresource($1)
|
359
|
+
when EXECUTED_MATCHER
|
360
|
+
format_summary_if_needed(text)
|
361
|
+
when RESTARTING_TESTS_MATCHER
|
362
|
+
formatter.format_failing_test(@test_suite, @test_case, "Test crashed", "n/a")
|
363
|
+
when UI_FAILING_TEST_MATCHER
|
364
|
+
formatter.format_failing_test(@test_suite, @test_case, $2, $1)
|
365
|
+
when FAILING_TEST_MATCHER
|
366
|
+
formatter.format_failing_test($2, $3, $4, $1)
|
367
|
+
when FATAL_ERROR_MATCHER
|
368
|
+
formatter.format_error($1)
|
369
|
+
when FILE_MISSING_ERROR_MATCHER
|
370
|
+
formatter.format_file_missing_error($1, $2)
|
371
|
+
when GENERATE_DSYM_MATCHER
|
372
|
+
formatter.format_generate_dsym($1)
|
373
|
+
when LD_WARNING_MATCHER
|
374
|
+
formatter.format_ld_warning($1 + $2)
|
375
|
+
when LD_ERROR_MATCHER
|
376
|
+
formatter.format_error($1)
|
377
|
+
when LIBTOOL_MATCHER
|
378
|
+
formatter.format_libtool($1)
|
379
|
+
when LINKING_MATCHER
|
380
|
+
formatter.format_linking($1, $2, $3)
|
381
|
+
when MODULE_INCLUDES_ERROR_MATCHER
|
382
|
+
formatter.format_error($1)
|
383
|
+
when TEST_CASE_MEASURED_MATCHER
|
384
|
+
formatter.format_measuring_test($1, $2, $3)
|
385
|
+
when TEST_CASE_PENDING_MATCHER
|
386
|
+
formatter.format_pending_test($1, $2)
|
387
|
+
when TEST_CASE_PASSED_MATCHER
|
388
|
+
formatter.format_passing_test($1, $2, $3)
|
389
|
+
when PODS_ERROR_MATCHER
|
390
|
+
formatter.format_error($1)
|
391
|
+
when PROCESS_INFO_PLIST_MATCHER
|
392
|
+
formatter.format_process_info_plist(*unescaped($2, $1))
|
393
|
+
when PHASE_SCRIPT_EXECUTION_MATCHER
|
394
|
+
formatter.format_phase_script_execution(*unescaped($1))
|
395
|
+
when PHASE_SUCCESS_MATCHER
|
396
|
+
formatter.format_phase_success($1)
|
397
|
+
when PROCESS_PCH_MATCHER
|
398
|
+
formatter.format_process_pch($1)
|
399
|
+
when PROCESS_PCH_COMMAND_MATCHER
|
400
|
+
formatter.format_process_pch_command($1)
|
401
|
+
when PREPROCESS_MATCHER
|
402
|
+
formatter.format_preprocess($1)
|
403
|
+
when PBXCP_MATCHER
|
404
|
+
formatter.format_pbxcp($1)
|
405
|
+
when TESTS_RUN_COMPLETION_MATCHER
|
406
|
+
formatter.format_test_run_finished($1, $3)
|
407
|
+
when TEST_SUITE_STARTED_MATCHER
|
408
|
+
formatter.format_test_run_started($1)
|
409
|
+
when TEST_SUITE_START_MATCHER
|
410
|
+
formatter.format_test_suite_started($1)
|
411
|
+
when TIFFUTIL_MATCHER
|
412
|
+
formatter.format_tiffutil($1)
|
413
|
+
when TOUCH_MATCHER
|
414
|
+
formatter.format_touch($1, $2)
|
415
|
+
when WRITE_FILE_MATCHER
|
416
|
+
formatter.format_write_file($1)
|
417
|
+
when WRITE_AUXILIARY_FILES
|
418
|
+
formatter.format_write_auxiliary_files
|
419
|
+
when SHELL_COMMAND_MATCHER
|
420
|
+
formatter.format_shell_command($1, $2)
|
421
|
+
when GENERIC_WARNING_MATCHER
|
422
|
+
formatter.format_warning($1)
|
423
|
+
when WILL_NOT_BE_CODE_SIGNED_MATCHER
|
424
|
+
formatter.format_will_not_be_code_signed($1)
|
425
|
+
else
|
426
|
+
formatter.format_other(text)
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
private
|
431
|
+
|
432
|
+
def update_test_state(text)
|
433
|
+
case text
|
434
|
+
when TEST_SUITE_STARTED_MATCHER
|
435
|
+
@tests_done = false
|
436
|
+
@formatted_summary = false
|
437
|
+
@failures = {}
|
438
|
+
when TEST_CASE_STARTED_MATCHER
|
439
|
+
@test_suite = $1
|
440
|
+
@test_case = $2
|
441
|
+
when TESTS_RUN_COMPLETION_MATCHER
|
442
|
+
@tests_done = true
|
443
|
+
when FAILING_TEST_MATCHER
|
444
|
+
store_failure(file: $1, test_suite: $2, test_case: $3, reason: $4)
|
445
|
+
when UI_FAILING_TEST_MATCHER
|
446
|
+
store_failure(file: $1, test_suite: @test_suite, test_case: @test_case, reason: $2)
|
447
|
+
when RESTARTING_TESTS_MATCHER
|
448
|
+
store_failure(file: "n/a", test_suite: @test_suite, test_case: @test_case, reason: "Test crashed")
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
# @ return Hash { :file_name, :file_path, :reason, :line }
|
453
|
+
def update_error_state(text)
|
454
|
+
update_error = lambda {
|
455
|
+
current_issue[:reason] = $3
|
456
|
+
current_issue[:file_path] = $1
|
457
|
+
current_issue[:file_name] = $2
|
458
|
+
}
|
459
|
+
if text =~ COMPILE_ERROR_MATCHER
|
460
|
+
@formatting_error = true
|
461
|
+
update_error.call
|
462
|
+
elsif text =~ COMPILE_WARNING_MATCHER
|
463
|
+
@formatting_warning = true
|
464
|
+
update_error.call
|
465
|
+
elsif text =~ CURSOR_MATCHER
|
466
|
+
current_issue[:cursor] = $1.chomp
|
467
|
+
elsif @formatting_error || @formatting_warning
|
468
|
+
current_issue[:line] = text.chomp
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
def update_linker_failure_state(text)
|
473
|
+
if text =~ LINKER_UNDEFINED_SYMBOLS_MATCHER ||
|
474
|
+
text =~ LINKER_DUPLICATE_SYMBOLS_MATCHER
|
475
|
+
|
476
|
+
current_linker_failure[:message] = $1
|
477
|
+
@formatting_linker_failure = true
|
478
|
+
end
|
479
|
+
return unless @formatting_linker_failure
|
480
|
+
|
481
|
+
case text
|
482
|
+
when SYMBOL_REFERENCED_FROM_MATCHER
|
483
|
+
current_linker_failure[:symbol] = $1
|
484
|
+
when LINKER_UNDEFINED_SYMBOL_LOCATION_MATCHER
|
485
|
+
current_linker_failure[:reference] = text.strip
|
486
|
+
when LINKER_DUPLICATE_SYMBOLS_LOCATION_MATCHER
|
487
|
+
current_linker_failure[:files] << $1
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
# TODO: clean up the mess around all this
|
492
|
+
def should_format_error?
|
493
|
+
@formatting_error && error_or_warning_is_present
|
494
|
+
end
|
495
|
+
|
496
|
+
def should_format_warning?
|
497
|
+
@formatting_warning && error_or_warning_is_present
|
498
|
+
end
|
499
|
+
|
500
|
+
def error_or_warning_is_present
|
501
|
+
current_issue[:reason] && current_issue[:cursor] && current_issue[:line]
|
502
|
+
end
|
503
|
+
|
504
|
+
def should_format_undefined_symbols?
|
505
|
+
current_linker_failure[:message] && current_linker_failure[:symbol] && current_linker_failure[:reference]
|
506
|
+
end
|
507
|
+
|
508
|
+
def should_format_duplicate_symbols?
|
509
|
+
current_linker_failure[:message] && current_linker_failure[:files].count > 1
|
510
|
+
end
|
511
|
+
|
512
|
+
def current_issue
|
513
|
+
@current_issue ||= {}
|
514
|
+
end
|
515
|
+
|
516
|
+
def current_linker_failure
|
517
|
+
@linker_failure ||= {files: []}
|
518
|
+
end
|
519
|
+
|
520
|
+
def format_compile_error
|
521
|
+
error = current_issue.dup
|
522
|
+
@current_issue = {}
|
523
|
+
@formatting_error = false
|
524
|
+
formatter.format_compile_error(error[:file_name],
|
525
|
+
error[:file_path],
|
526
|
+
error[:reason],
|
527
|
+
error[:line],
|
528
|
+
error[:cursor])
|
529
|
+
end
|
530
|
+
|
531
|
+
def format_compile_warning
|
532
|
+
warning = current_issue.dup
|
533
|
+
@current_issue = {}
|
534
|
+
@formatting_warning = false
|
535
|
+
formatter.format_compile_warning(warning[:file_name],
|
536
|
+
warning[:file_path],
|
537
|
+
warning[:reason],
|
538
|
+
warning[:line],
|
539
|
+
warning[:cursor])
|
540
|
+
end
|
541
|
+
|
542
|
+
def format_undefined_symbols
|
543
|
+
result = formatter.format_undefined_symbols(
|
544
|
+
current_linker_failure[:message],
|
545
|
+
current_linker_failure[:symbol],
|
546
|
+
current_linker_failure[:reference]
|
547
|
+
)
|
548
|
+
reset_linker_format_state
|
549
|
+
result
|
550
|
+
end
|
551
|
+
|
552
|
+
def format_duplicate_symbols
|
553
|
+
result = formatter.format_duplicate_symbols(
|
554
|
+
current_linker_failure[:message],
|
555
|
+
current_linker_failure[:files]
|
556
|
+
)
|
557
|
+
reset_linker_format_state
|
558
|
+
result
|
559
|
+
end
|
560
|
+
|
561
|
+
def reset_linker_format_state
|
562
|
+
@linker_failure = nil
|
563
|
+
@formatting_linker_failure = false
|
564
|
+
end
|
565
|
+
|
566
|
+
def store_failure(file: nil, test_suite: nil, test_case: nil, reason: nil)
|
567
|
+
failures_per_suite[test_suite] ||= []
|
568
|
+
failures_per_suite[test_suite] << {
|
569
|
+
file_path: file,
|
570
|
+
reason: reason,
|
571
|
+
test_case: test_case
|
572
|
+
}
|
573
|
+
end
|
574
|
+
|
575
|
+
def failures_per_suite
|
576
|
+
@failures ||= {}
|
577
|
+
end
|
578
|
+
|
579
|
+
def format_summary_if_needed(executed_message)
|
580
|
+
return "" unless should_format_summary?
|
581
|
+
|
582
|
+
@formatted_summary = true
|
583
|
+
formatter.format_test_summary(executed_message, failures_per_suite)
|
584
|
+
end
|
585
|
+
|
586
|
+
def should_format_summary?
|
587
|
+
@tests_done && !@formatted_summary
|
588
|
+
end
|
589
|
+
|
590
|
+
def unescaped(*escaped_values)
|
591
|
+
escaped_values.map { |v| v.delete('\\') }
|
592
|
+
end
|
593
|
+
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
@@ -0,0 +1,28 @@
|
|
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 finish
|
15
|
+
@formatter.finish
|
16
|
+
end
|
17
|
+
|
18
|
+
def pretty_print(text)
|
19
|
+
formatted_text = formatter.pretty_format(text)
|
20
|
+
unless formatted_text.empty?
|
21
|
+
STDOUT.print(formatted_text + formatter.optional_newline)
|
22
|
+
STDOUT.flush
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module XCPretty
|
2
|
+
class HTML < Reporter
|
3
|
+
|
4
|
+
FILEPATH = 'build/reports/tests.html'
|
5
|
+
TEMPLATE = File.expand_path('../../../../assets/report.html.erb', __FILE__)
|
6
|
+
SCREENSHOT_DIR = 'build/reports'
|
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
|
+
super(options)
|
19
|
+
@test_suites = {}
|
20
|
+
@collect_screenshots = options[:screenshots]
|
21
|
+
end
|
22
|
+
|
23
|
+
def handle(line)
|
24
|
+
@parser.parse(line)
|
25
|
+
end
|
26
|
+
|
27
|
+
def format_failing_test(suite, test_case, reason, file)
|
28
|
+
add_test(suite, name: test_case, failing: true,
|
29
|
+
reason: reason, file: file,
|
30
|
+
snippet: formatted_snippet(file),
|
31
|
+
screenshots: [])
|
32
|
+
end
|
33
|
+
|
34
|
+
def format_passing_test(suite, test_case, time)
|
35
|
+
add_test(suite, name: test_case, time: time, screenshots: [])
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def formatted_snippet(filepath)
|
41
|
+
snippet = Snippet.from_filepath(filepath)
|
42
|
+
Syntax.highlight_html(snippet)
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_test(suite_name, data)
|
46
|
+
@test_count += 1
|
47
|
+
@test_suites[suite_name] ||= {tests: []}
|
48
|
+
@test_suites[suite_name][:tests] << data
|
49
|
+
if data[:failing]
|
50
|
+
@test_suites[suite_name][:failing] = true
|
51
|
+
@fail_count += 1
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def write_report
|
56
|
+
if @collect_screenshots
|
57
|
+
load_screenshots
|
58
|
+
end
|
59
|
+
File.open(@filepath, 'w') do |f|
|
60
|
+
# WAT: get rid of these locals. BTW Cucumber fails if you remove them
|
61
|
+
test_suites = @test_suites
|
62
|
+
fail_count = @fail_count
|
63
|
+
test_count = @test_count
|
64
|
+
erb = ERB.new(File.open(TEMPLATE, 'r').read)
|
65
|
+
f.write erb.result(binding)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def load_screenshots
|
70
|
+
Dir.foreach(SCREENSHOT_DIR) do |item|
|
71
|
+
next if item == '.' || item == '..' || File.extname(item) != '.png'
|
72
|
+
|
73
|
+
test = find_test(item)
|
74
|
+
next if test.nil?
|
75
|
+
|
76
|
+
test[:screenshots] << item
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def find_test(image_name)
|
81
|
+
@test_suites.each do |name, info|
|
82
|
+
info[:tests].each do |test, index|
|
83
|
+
combined_name = name + '_' + test[:name]
|
84
|
+
test_name_matches = image_name.start_with?(test[:name])
|
85
|
+
combined_name_matches = image_name.start_with?(combined_name)
|
86
|
+
return test if test_name_matches || combined_name_matches
|
87
|
+
end
|
88
|
+
end
|
89
|
+
nil
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|