xcpretty-security-patched 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) 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 +12 -0
  7. data/CHANGELOG.md +269 -0
  8. data/CONTRIBUTING.md +64 -0
  9. data/Gemfile +9 -0
  10. data/LICENSE.txt +61 -0
  11. data/README.md +95 -0
  12. data/Rakefile +18 -0
  13. data/assets/report.html.erb +173 -0
  14. data/bin/xcpretty +90 -0
  15. data/features/assets/RACCommandSpec_enabled_signal_should_send_YES_while_executing_is_YES.png +0 -0
  16. data/features/assets/apple_raw.png +0 -0
  17. data/features/custom_formatter.feature +15 -0
  18. data/features/custom_reporter.feature +29 -0
  19. data/features/fixtures/xcodebuild.log +5963 -0
  20. data/features/html_report.feature +54 -0
  21. data/features/json_compilation_database_report.feature +33 -0
  22. data/features/junit_report.feature +49 -0
  23. data/features/knock_format.feature +11 -0
  24. data/features/simple_format.feature +238 -0
  25. data/features/steps/custom_reporter_steps.rb +16 -0
  26. data/features/steps/formatting_steps.rb +386 -0
  27. data/features/steps/html_steps.rb +32 -0
  28. data/features/steps/json_steps.rb +45 -0
  29. data/features/steps/junit_steps.rb +39 -0
  30. data/features/steps/report_steps.rb +27 -0
  31. data/features/steps/xcpretty_steps.rb +31 -0
  32. data/features/support/env.rb +123 -0
  33. data/features/tap_format.feature +31 -0
  34. data/features/test_format.feature +49 -0
  35. data/features/xcpretty.feature +14 -0
  36. data/lib/xcpretty/ansi.rb +72 -0
  37. data/lib/xcpretty/formatters/formatter.rb +200 -0
  38. data/lib/xcpretty/formatters/knock.rb +35 -0
  39. data/lib/xcpretty/formatters/rspec.rb +33 -0
  40. data/lib/xcpretty/formatters/simple.rb +200 -0
  41. data/lib/xcpretty/formatters/tap.rb +40 -0
  42. data/lib/xcpretty/parser.rb +596 -0
  43. data/lib/xcpretty/printer.rb +28 -0
  44. data/lib/xcpretty/reporters/html.rb +93 -0
  45. data/lib/xcpretty/reporters/json_compilation_database.rb +51 -0
  46. data/lib/xcpretty/reporters/junit.rb +102 -0
  47. data/lib/xcpretty/reporters/reporter.rb +62 -0
  48. data/lib/xcpretty/snippet.rb +38 -0
  49. data/lib/xcpretty/syntax.rb +58 -0
  50. data/lib/xcpretty/term.rb +14 -0
  51. data/lib/xcpretty/version.rb +4 -0
  52. data/lib/xcpretty.rb +38 -0
  53. data/spec/fixtures/NSStringTests.m +64 -0
  54. data/spec/fixtures/constants.rb +707 -0
  55. data/spec/fixtures/custom_formatter.rb +18 -0
  56. data/spec/fixtures/custom_reporter.rb +30 -0
  57. data/spec/fixtures/oneliner.m +1 -0
  58. data/spec/fixtures/raw_kiwi_compilation_fail.txt +24 -0
  59. data/spec/fixtures/raw_kiwi_fail.txt +1896 -0
  60. data/spec/fixtures/raw_specta_fail.txt +3110 -0
  61. data/spec/spec_helper.rb +7 -0
  62. data/spec/support/matchers/colors.rb +21 -0
  63. data/spec/xcpretty/ansi_spec.rb +47 -0
  64. data/spec/xcpretty/formatters/formatter_spec.rb +151 -0
  65. data/spec/xcpretty/formatters/rspec_spec.rb +56 -0
  66. data/spec/xcpretty/formatters/simple_spec.rb +178 -0
  67. data/spec/xcpretty/parser_spec.rb +636 -0
  68. data/spec/xcpretty/printer_spec.rb +55 -0
  69. data/spec/xcpretty/reporters/junit_spec.rb +20 -0
  70. data/spec/xcpretty/reporters/reporter_spec.rb +40 -0
  71. data/spec/xcpretty/snippet_spec.rb +46 -0
  72. data/spec/xcpretty/syntax_spec.rb +39 -0
  73. data/spec/xcpretty/term_spec.rb +26 -0
  74. data/xcpretty.gemspec +37 -0
  75. 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
+