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.
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
+