xcknife 0.6.6 → 0.13.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.
data/TestDumper/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # TestDumper - EXPERIMENTAL
2
2
 
3
- Utility that replaces xctool for enumerating tests. It requires the `build-for-testing` feature Xcode8 introduced on xcodebuild. In particular, it leverages the xctestrun file (see `man xcodebuild.xctestrun`).
3
+ Utility that replaces xctool for enumerating tests. It requires the `build-for-testing` feature Xcode 8 introduced on xcodebuild. In particular, it leverages the xctestrun file (see `man xcodebuild.xctestrun`).
4
4
 
5
5
  ## Building.
6
6
 
@@ -17,6 +17,7 @@ $ xcknife-test-dumper --help
17
17
  Usage: xcknife-test-dumper [options] derived_data_folder output_file [device_id]
18
18
  -d, --debug Debug mode enabled
19
19
  -r, --retry-count COUNT Max retry count for simulator output
20
+ -x, --simctl-timeout SECONDS Max allowed time in seconds for simctl commands
20
21
  -t OUTPUT_FOLDER, Sets temporary Output folder
21
22
  --temporary-output
22
23
  -s, --scheme XCSCHEME_FILE Reads environments variables from the xcscheme file
@@ -181,7 +181,7 @@
181
181
  isa = PBXProject;
182
182
  attributes = {
183
183
  LastSwiftUpdateCheck = 0700;
184
- LastUpgradeCheck = 0700;
184
+ LastUpgradeCheck = 1010;
185
185
  ORGANIZATIONNAME = "Square, Inc";
186
186
  TargetAttributes = {
187
187
  F60C68B91B8D038300CC8521 = {
@@ -198,7 +198,7 @@
198
198
  };
199
199
  };
200
200
  };
201
- buildConfigurationList = F60C68B41B8D038300CC8521 /* Build configuration list for PBXProject "toolc" */;
201
+ buildConfigurationList = F60C68B41B8D038300CC8521 /* Build configuration list for PBXProject "TestDumper" */;
202
202
  compatibilityVersion = "Xcode 3.2";
203
203
  developmentRegion = English;
204
204
  hasScannedForEncodings = 0;
@@ -288,13 +288,23 @@
288
288
  CLANG_CXX_LIBRARY = "libc++";
289
289
  CLANG_ENABLE_MODULES = YES;
290
290
  CLANG_ENABLE_OBJC_ARC = YES;
291
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
291
292
  CLANG_WARN_BOOL_CONVERSION = YES;
293
+ CLANG_WARN_COMMA = YES;
292
294
  CLANG_WARN_CONSTANT_CONVERSION = YES;
295
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
293
296
  CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
294
297
  CLANG_WARN_EMPTY_BODY = YES;
295
298
  CLANG_WARN_ENUM_CONVERSION = YES;
299
+ CLANG_WARN_INFINITE_RECURSION = YES;
296
300
  CLANG_WARN_INT_CONVERSION = YES;
301
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
302
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
303
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
297
304
  CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
305
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
306
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
307
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
298
308
  CLANG_WARN_UNREACHABLE_CODE = YES;
299
309
  CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
300
310
  "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@@ -337,13 +347,23 @@
337
347
  CLANG_CXX_LIBRARY = "libc++";
338
348
  CLANG_ENABLE_MODULES = YES;
339
349
  CLANG_ENABLE_OBJC_ARC = YES;
350
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
340
351
  CLANG_WARN_BOOL_CONVERSION = YES;
352
+ CLANG_WARN_COMMA = YES;
341
353
  CLANG_WARN_CONSTANT_CONVERSION = YES;
354
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
342
355
  CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
343
356
  CLANG_WARN_EMPTY_BODY = YES;
344
357
  CLANG_WARN_ENUM_CONVERSION = YES;
358
+ CLANG_WARN_INFINITE_RECURSION = YES;
345
359
  CLANG_WARN_INT_CONVERSION = YES;
360
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
361
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
362
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
346
363
  CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
364
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
365
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
366
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
347
367
  CLANG_WARN_UNREACHABLE_CODE = YES;
348
368
  CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
349
369
  "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@@ -373,12 +393,13 @@
373
393
  F60C68D11B8D038300CC8521 /* Debug */ = {
374
394
  isa = XCBuildConfiguration;
375
395
  buildSettings = {
396
+ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
376
397
  CLANG_ENABLE_MODULES = YES;
398
+ CODE_SIGN_IDENTITY = "";
377
399
  DEFINES_MODULE = YES;
378
400
  DYLIB_COMPATIBILITY_VERSION = 1;
379
401
  DYLIB_CURRENT_VERSION = 1;
380
402
  DYLIB_INSTALL_NAME_BASE = "@rpath";
381
- EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
382
403
  FRAMEWORK_SEARCH_PATHS = (
383
404
  "$(inherited)",
384
405
  "$(SDKROOT)/../../Library/Frameworks/",
@@ -399,12 +420,13 @@
399
420
  F60C68D21B8D038300CC8521 /* Release */ = {
400
421
  isa = XCBuildConfiguration;
401
422
  buildSettings = {
423
+ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
402
424
  CLANG_ENABLE_MODULES = YES;
425
+ CODE_SIGN_IDENTITY = "";
403
426
  DEFINES_MODULE = YES;
404
427
  DYLIB_COMPATIBILITY_VERSION = 1;
405
428
  DYLIB_CURRENT_VERSION = 1;
406
429
  DYLIB_INSTALL_NAME_BASE = "@rpath";
407
- EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
408
430
  FRAMEWORK_SEARCH_PATHS = (
409
431
  "$(inherited)",
410
432
  "$(SDKROOT)/../../Library/Frameworks/",
@@ -483,7 +505,7 @@
483
505
  /* End XCBuildConfiguration section */
484
506
 
485
507
  /* Begin XCConfigurationList section */
486
- F60C68B41B8D038300CC8521 /* Build configuration list for PBXProject "toolc" */ = {
508
+ F60C68B41B8D038300CC8521 /* Build configuration list for PBXProject "TestDumper" */ = {
487
509
  isa = XCConfigurationList;
488
510
  buildConfigurations = (
489
511
  F60C68CE1B8D038300CC8521 /* Debug */,
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>IDEDidComputeMac32BitWarning</key>
6
+ <true/>
7
+ </dict>
8
+ </plist>
@@ -1,6 +1,6 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <Scheme
3
- LastUpgradeVersion = "0800"
3
+ LastUpgradeVersion = "1010"
4
4
  version = "1.3">
5
5
  <BuildAction
6
6
  parallelizeBuildables = "YES"
@@ -7,13 +7,9 @@
7
7
  //
8
8
 
9
9
  @import Dispatch;
10
+ @import Foundation;
10
11
  @import XCTest;
11
12
 
12
-
13
-
14
-
15
- @class NSSet, NSString, NSURL, NSUUID;
16
-
17
13
  @interface XCTestConfiguration : NSObject <NSSecureCoding>
18
14
  {
19
15
  NSURL *_testBundleURL;
@@ -71,6 +67,46 @@
71
67
 
72
68
  #include <dlfcn.h>
73
69
 
70
+ // Logging
71
+ FILE *logFile;
72
+
73
+ void initializeLogFile(const char *logFilePath)
74
+ {
75
+ logFile = fopen(logFilePath, "w");
76
+ }
77
+
78
+ void logDebug(NSString *, ...) NS_FORMAT_FUNCTION(1, 2);
79
+ void logDebug(NSString *msg, ...)
80
+ {
81
+ assert(logFile);
82
+ va_list varargs;
83
+ va_start(varargs, msg);
84
+ msg = [[NSString alloc] initWithFormat:msg arguments:varargs];
85
+ va_end(varargs);
86
+ fprintf(logFile, "%s\n", msg.UTF8String);
87
+
88
+ NSLog(@"%@", msg);
89
+ }
90
+
91
+ void logInit()
92
+ {
93
+ logDebug(@"Starting TestDumper...");
94
+ logDebug(@"Environment Variables:");
95
+ logDebug(@"%@", NSProcessInfo.processInfo.environment.description);
96
+ logDebug(@"Command Line Arguments:");
97
+ logDebug(@"%@", NSProcessInfo.processInfo.arguments.description);
98
+
99
+ logDebug(@"--------------------------------");
100
+ }
101
+
102
+ OS_NORETURN
103
+ void logEnd(Boolean success)
104
+ {
105
+ int exitCode = success ? EXIT_SUCCESS : EXIT_FAILURE;
106
+ logDebug(@"EndingTestDumper...\nExiting with status %d", exitCode);
107
+ fclose(logFile);
108
+ exit(exitCode);
109
+ }
74
110
 
75
111
  // Used for a structured log, just like Xctool's.
76
112
  // Example: https://github.com/square/xcknife/blob/master/example/xcknife-exemplar.json-stream
@@ -81,10 +117,10 @@ static void PrintJSON(FILE *outFile, id JSONObject)
81
117
 
82
118
  if (error) {
83
119
  fprintf(outFile, "{ \"message\" : \"Error while serializing to JSON. Check out simulator logs for details\" }");
84
- NSLog(@"ERROR: Error generating JSON for object: %s: %s\n",
120
+ logDebug(@"ERROR: Error generating JSON for object: %s: %s\n",
85
121
  [[JSONObject description] UTF8String],
86
122
  [[error localizedFailureReason] UTF8String]);
87
- exit(1);
123
+ logEnd(false);
88
124
  }
89
125
 
90
126
  fwrite([data bytes], 1, [data length], outFile);
@@ -114,58 +150,60 @@ static void PrintTestClass(FILE *outFile, NSString *testClass) {
114
150
  @"totalDuration" : @"0"});
115
151
  }
116
152
 
117
- void enumerateTests();
153
+ void enumerateTests(NSString *);
118
154
 
119
155
  const int TEST_TARGET_LEVEL = 0;
120
156
  const int TEST_CLASS_LEVEL = 1;
121
157
  const int TEST_METHOD_LEVEL = 2;
158
+ FILE *noteFile;
122
159
 
123
160
  __attribute__((constructor))
124
161
  void initialize() {
125
162
  NSLog(@"Starting TestDumper");
163
+ const char *logFilePath = [[[NSProcessInfo processInfo] arguments][3] UTF8String];
164
+ initializeLogFile(logFilePath);
165
+ logInit();
166
+ NSString *testBundlePath = [[NSProcessInfo processInfo] arguments][4];
126
167
  NSString *testDumperOutputPath = NSProcessInfo.processInfo.environment[@"TestDumperOutputPath"];
127
168
  NSFileManager *fileManager = [NSFileManager defaultManager];
128
169
 
129
170
  if ([fileManager fileExistsAtPath:testDumperOutputPath]) {
130
- NSLog(@"File already exists %@. Stopping", testDumperOutputPath);
131
- exit(0);
171
+ logDebug(@"File already exists %@. Stopping", testDumperOutputPath);
172
+ logEnd(true);
132
173
  }
133
- NSString *testType = [NSString stringWithUTF8String: getenv("XCTEST_TYPE")];
134
174
 
175
+ NSString *testType = [NSString stringWithUTF8String: getenv("XCTEST_TYPE")];
135
176
  if ([testType isEqualToString: @"APPTEST"]) {
136
177
  [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidFinishLaunchingNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
137
- enumerateTests();
178
+ enumerateTests(testBundlePath);
138
179
  }];
139
180
  } else {
140
- enumerateTests();
181
+ enumerateTests(testBundlePath);
141
182
  }
142
183
  }
143
184
 
144
-
145
- void enumerateTests() {
146
- XCTestConfiguration *config = [[XCTestConfiguration alloc] init];
147
- NSString *testType = [NSString stringWithUTF8String: getenv("XCTEST_TYPE")];
148
- NSString *testTarget = [NSString stringWithUTF8String: getenv("XCTEST_TARGET")];
149
-
150
- if ([testType isEqualToString: @"APPTEST"]) {
151
- config.testBundleURL = [NSURL fileURLWithPath:NSProcessInfo.processInfo.environment[@"XCInjectBundle"]];
152
- config.targetApplicationPath = NSProcessInfo.processInfo.environment[@"XCInjectBundleInto"];
153
-
154
- NSString *configPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"%ul.xctestconfiguration", arc4random()]];
155
-
156
- NSLog(@"Writing config to %@", configPath);
157
-
158
- NSData *data = [NSKeyedArchiver archivedDataWithRootObject:config];
159
-
160
- [data writeToFile:configPath atomically:true];
161
-
162
- setenv("XCTestConfigurationFilePath", configPath.UTF8String, YES);
163
-
164
- dlopen(getenv("IDE_INJECTION_PATH"), RTLD_GLOBAL);
185
+ void enumerateTests(NSString *testBundlePath) {
186
+ logDebug(@"Listing all test bundles");
187
+ for (NSBundle *bundle in NSBundle.allBundles) {
188
+ logDebug(@"Found a test bundle named: %@", bundle.bundlePath);
165
189
  }
166
- NSString *testBundle = [[[NSProcessInfo processInfo] arguments] lastObject];
167
- [[NSBundle bundleWithPath:testBundle] load];
168
-
190
+ logDebug(@"Finished listing all test bundles");
191
+
192
+ NSBundle* testBundleObj = [NSBundle bundleWithPath:testBundlePath];
193
+ [testBundleObj load];
194
+ logDebug(@"test bundle loaded");
195
+
196
+ logDebug(@"Listing all test bundles");
197
+ for (NSBundle *bundle in NSBundle.allBundles) {
198
+ logDebug(@"Found a test bundle named: %@", bundle.bundlePath);
199
+ }
200
+ logDebug(@"Finished listing all test bundles");
201
+
202
+ NSString *testType = [NSString stringWithUTF8String: getenv("XCTEST_TYPE")];
203
+ NSString *testTarget = [[[testBundlePath componentsSeparatedByString:@"/"] lastObject] componentsSeparatedByString:@"."][0];
204
+
205
+ logDebug(@"The test target is: %@ of type %@", testTarget, testType);
206
+
169
207
  FILE *outFile;
170
208
  NSString *testDumperOutputPath = NSProcessInfo.processInfo.environment[@"TestDumperOutputPath"];
171
209
 
@@ -175,17 +213,18 @@ void enumerateTests() {
175
213
  outFile = fopen(testDumperOutputPath.UTF8String, "w+");
176
214
  }
177
215
 
178
- NSLog(@"Opened %@ with fd %p", testDumperOutputPath, outFile);
216
+ logDebug(@"Opened %@ with fd %p", testDumperOutputPath, outFile);
179
217
  if (outFile == NULL) {
180
- NSLog(@"File already exists %@. Stopping", testDumperOutputPath);
181
- exit(0);
218
+ logDebug(@"File already exists at %@. Stopping", testDumperOutputPath);
219
+ logEnd(true);
182
220
  }
183
-
221
+
184
222
  PrintDumpStart(outFile, testType);
185
- [[XCTestSuite defaultTestSuite] printTestsWithLevel:0 withTarget: testTarget withParent: nil outputFile:outFile];
223
+ XCTestSuite* testSuite = [XCTestSuite defaultTestSuite];
224
+ [testSuite printTestsWithLevel:0 withTarget: testTarget withParent: nil outputFile:outFile];
186
225
  PrintDumpEnd(outFile, testType);
187
226
  fclose(outFile);
188
- exit(0);
227
+ logEnd(true);
189
228
  }
190
229
 
191
230
 
@@ -208,7 +247,7 @@ void enumerateTests() {
208
247
  // nothing to do here
209
248
  break;
210
249
  default:
211
- NSLog(@"Uknown level %ld", level);
250
+ logDebug(@"Unknown test level %ld for test %@", level, t.debugDescription);
212
251
 
213
252
  }
214
253
  if (level == TEST_METHOD_LEVEL) {
data/bin/xcknife CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
2
4
  require 'xcknife'
3
5
 
4
6
  XCKnife::Runner.invoke
data/bin/xcknife-min CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- # encoding: utf-8
2
+ # frozen_string_literal: true
3
3
 
4
4
  # Script for cleaning up historical events, so that we only store the ones we need
5
5
  require 'set'
@@ -7,25 +7,22 @@ require 'json' unless defined?(::JSON)
7
7
 
8
8
  INTERESTING_EVENTS = %w[begin-ocunit end-test].to_set
9
9
  def cleanup(input_file_name, output_file_name)
10
- if input_file_name.nil? or output_file_name.nil?
11
- return puts "Usage: xcknife-min [input] [output]"
12
- end
10
+ return puts 'Usage: xcknife-min [input] [output]' if input_file_name.nil? || output_file_name.nil?
11
+
13
12
  lines = IO.readlines(input_file_name)
14
13
  lines_written = 0
15
14
  total = lines.size
16
- File.open(output_file_name, "w") do |f|
15
+ File.open(output_file_name, 'w') do |f|
17
16
  lines.each do |line|
18
- data = JSON.load(line)
19
- if INTERESTING_EVENTS.include?(data["event"])
20
- lines_written += 1
21
- %w[output sdk timestamp exceptions result succeeded methodName].each do |k|
22
- data.delete(k)
23
- end
24
- if data["test"]
25
- data["test"] = "1"
26
- end
27
- f.puts(data.to_json)
17
+ data = JSON.parse(line)
18
+ next unless INTERESTING_EVENTS.include?(data['event'])
19
+
20
+ lines_written += 1
21
+ %w[output sdk timestamp exceptions result succeeded methodName].each do |k|
22
+ data.delete(k)
28
23
  end
24
+ data['test'] = '1' if data['test']
25
+ f.puts(data.to_json)
29
26
  end
30
27
  end
31
28
  lines_removed = total - lines_written
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
2
4
  require 'xcknife'
3
5
 
4
6
  XCKnife::TestDumper.invoke
@@ -1,13 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../lib/xcknife'
2
4
  require 'pp'
3
5
 
4
6
  # Gem usage of xcknife. Functionaly equivalent to
5
7
  # $ xcknife -p CommonTestTarget -p CommonTestTarget,iPadTestTarget 6 example/xcknife-exemplar-historical-data.json-stream example/xcknife-exemplar.json-stream
6
- include XCKnife::XCToolCmdHelper
8
+
7
9
  TARGET_PARTITIONS = {
8
- "AllTests" => ["CommonTestTarget", "iPadTestTarget"],
9
- "OnlyCommon" => ["CommonTestTarget"]
10
- }
10
+ 'AllTests' => %w[CommonTestTarget iPadTestTarget],
11
+ 'OnlyCommon' => ['CommonTestTarget']
12
+ }.freeze
11
13
 
12
14
  def run(historical_file, current_file)
13
15
  test_target_names = TARGET_PARTITIONS.keys
@@ -20,16 +22,16 @@ def run(historical_file, current_file)
20
22
  puts "imbalances = #{result.test_time_imbalances.to_h.inspect}"
21
23
  shard_number = 0
22
24
  puts "size = #{partition_sets.size}"
23
- puts "sizes = #{partition_sets.map(&:size).join(", ")}"
25
+ puts "sizes = #{partition_sets.map(&:size).join(', ')}"
24
26
  partition_sets.each_with_index do |partition_set, i|
25
27
  target_name = test_target_names[i]
26
28
  partition_set.each do |partition|
27
29
  puts "target name for worker #{shard_number} = #{target_name}"
28
- puts "only is: #{xctool_only_arguments(partition).inspect}"
29
- puts "skip-only is: #{xcodebuild_skip_arguments(partition, result.test_time_for_partitions).inspect}"
30
+ puts "only is: #{XCKnife::XCToolCmdHelper.xctool_only_arguments(partition).inspect}"
31
+ puts "skip-only is: #{XCKnife::XCToolCmdHelper.xcodebuild_skip_arguments(partition, result.test_time_for_partitions).inspect}"
30
32
  shard_number += 1
31
33
  end
32
34
  end
33
35
  end
34
36
 
35
- run("xcknife-exemplar-historical-data.json-stream", "xcknife-exemplar.json-stream")
37
+ run('xcknife-exemplar-historical-data.json-stream', 'xcknife-exemplar.json-stream')
@@ -1,12 +1,12 @@
1
- {"bundleName":"CommonTestTarget.xctest","deviceName":"iPad Air","event":"begin-ocunit","targetName":"CommonTestTarget","testType":"logic-test","sdkName":"iphonesimulator9.2"}
1
+ {"bundleName":"CommonTestTarget.xctest","deviceName":"iPad Air","event":"begin-ocunit","targetName":"CommonTestTarget","testType":"logic-test","sdkName":"iphonesimulator13.6"}
2
2
  {"test":"1","className":"CommonTestClass","event":"end-test","totalDuration":0.1075069904327393}
3
3
  {"test":"1","className":"CommonTestClass","event":"end-test","totalDuration":0.303464949131012}
4
4
  {"test":"1","className":"CommonTestClass","event":"end-test","totalDuration":0.2003870010375977}
5
- {"bundleName":"iPadTestTarget.xctest","deviceName":"iPad Air","event":"begin-ocunit","targetName":"iPadTestTarget","testType":"application-test","sdkName":"iphonesimulator9.2"}
5
+ {"bundleName":"iPadTestTarget.xctest","deviceName":"iPad Air","event":"begin-ocunit","targetName":"iPadTestTarget","testType":"application-test","sdkName":"iphonesimulator13.6"}
6
6
  {"test":"1","className":"iPadTestClassOne","event":"end-test","totalDuration":1.001249969005585}
7
7
  {"test":"1","className":"iPadTestClassThree","event":"end-test","totalDuration":0.5002140402793884}
8
8
  {"test":"1","className":"iPadTestClassTwo","event":"end-test","totalDuration":5.001157999038696}
9
- {"bundleName":"iPhoneTestTarget.xctest","deviceName":"iPad Air","event":"begin-ocunit","targetName":"iPhoneTestTarget","testType":"application-test","sdkName":"iphonesimulator9.2"}
9
+ {"bundleName":"iPhoneTestTarget.xctest","deviceName":"iPad Air","event":"begin-ocunit","targetName":"iPhoneTestTarget","testType":"application-test","sdkName":"iphonesimulator13.6"}
10
10
  {"test":"1","className":"iPhoneTestClassAlpha","event":"end-test","totalDuration":0.2037490010261536}
11
11
  {"test":"1","className":"iPhoneTestClassBeta","event":"end-test","totalDuration":0.2012439966201782}
12
12
  {"test":"1","className":"iPhoneTestClassDelta","event":"end-test","totalDuration":0.1004489660263062}