@@ -266,5 +266,325 @@ - (void)testEndScreenLoading {
266
266
OCMVerify ([self .mAPM endScreenLoadingCPWithEndTimestampMUS: endScreenLoadingCPWithEndTimestampMUS]);
267
267
}
268
268
269
+ - (void )testIsScreenRenderEnabled {
270
+ XCTestExpectation *expectation = [self expectationWithDescription: @" Call completion handler" ];
271
+
272
+ BOOL isScreenRenderEnabled = YES ;
273
+ OCMStub ([self .mAPM isScreenRenderingOperational ]).andReturn (isScreenRenderEnabled);
274
+
275
+ [self .api isScreenRenderEnabledWithCompletion: ^(NSNumber *isEnabledNumber, FlutterError *error) {
276
+ [expectation fulfill ];
277
+
278
+ XCTAssertEqualObjects (isEnabledNumber, @(isScreenRenderEnabled));
279
+ XCTAssertNil (error);
280
+ }];
281
+
282
+ [self waitForExpectations: @[expectation] timeout: 5.0 ];
283
+ }
284
+
285
+ - (void )testIsScreenRenderEnabledWhenDisabled {
286
+ XCTestExpectation *expectation = [self expectationWithDescription: @" Call completion handler" ];
287
+
288
+ BOOL isScreenRenderEnabled = NO ;
289
+ OCMStub ([self .mAPM isScreenRenderingOperational ]).andReturn (isScreenRenderEnabled);
290
+
291
+ [self .api isScreenRenderEnabledWithCompletion: ^(NSNumber *isEnabledNumber, FlutterError *error) {
292
+ [expectation fulfill ];
293
+
294
+ XCTAssertEqualObjects (isEnabledNumber, @(isScreenRenderEnabled));
295
+ XCTAssertNil (error);
296
+ }];
297
+
298
+ [self waitForExpectations: @[expectation] timeout: 5.0 ];
299
+ }
300
+
301
+ - (void )testSetScreenRenderEnabled {
302
+ NSNumber *isEnabled = @1 ;
303
+ FlutterError *error;
304
+
305
+ [self .api setScreenRenderEnabledIsEnabled: isEnabled error: &error];
306
+
307
+ OCMVerify ([self .mAPM setScreenRenderingEnabled: YES ]);
308
+ }
309
+
310
+ - (void )testSetScreenRenderDisabled {
311
+ NSNumber *isEnabled = @0 ;
312
+ FlutterError *error;
313
+
314
+ [self .api setScreenRenderEnabledIsEnabled: isEnabled error: &error];
315
+
316
+ OCMVerify ([self .mAPM setScreenRenderingEnabled: NO ]);
317
+ }
318
+
319
+ - (void )testDeviceRefreshRate {
320
+ XCTestExpectation *expectation = [self expectationWithDescription: @" Call completion handler" ];
321
+
322
+ // Mock UIScreen for iOS 10.3+
323
+ id mockScreen = OCMClassMock ([UIScreen class ]);
324
+ OCMStub ([mockScreen mainScreen ]).andReturn (mockScreen);
325
+ OCMStub ([mockScreen maximumFramesPerSecond ]).andReturn (120.0 );
326
+
327
+ [self .api deviceRefreshRateWithCompletion: ^(NSNumber *refreshRate, FlutterError *error) {
328
+ [expectation fulfill ];
329
+
330
+ XCTAssertEqualObjects (refreshRate, @(120.0 ));
331
+ XCTAssertNil (error);
332
+ }];
333
+
334
+ [self waitForExpectations: @[expectation] timeout: 5.0 ];
335
+
336
+ [mockScreen stopMocking ];
337
+ }
338
+
339
+ - (void )testDeviceRefreshRateFallback {
340
+ XCTestExpectation *expectation = [self expectationWithDescription: @" Call completion handler" ];
341
+
342
+ // Note: Testing the fallback behavior for iOS < 10.3 is challenging in unit tests
343
+ // since we can't easily mock the iOS version check. In a real scenario, this would
344
+ // return 60.0 for older iOS versions. For now, we'll test the normal case.
345
+
346
+ // Mock UIScreen to return 60.0 (typical fallback value)
347
+ id mockScreen = OCMClassMock ([UIScreen class ]);
348
+ OCMStub ([mockScreen mainScreen ]).andReturn (mockScreen);
349
+ OCMStub ([mockScreen maximumFramesPerSecond ]).andReturn (60.0 );
350
+
351
+ [self .api deviceRefreshRateWithCompletion: ^(NSNumber *refreshRate, FlutterError *error) {
352
+ [expectation fulfill ];
353
+
354
+ XCTAssertEqualObjects (refreshRate, @(60.0 ));
355
+ XCTAssertNil (error);
356
+ }];
357
+
358
+ [self waitForExpectations: @[expectation] timeout: 5.0 ];
359
+
360
+ [mockScreen stopMocking ];
361
+ }
362
+
363
+ - (void )testEndScreenRenderForAutoUiTrace {
364
+ FlutterError *error;
365
+
366
+ // Create mock frame data
367
+ NSDictionary *frameData = @{
368
+ @" frameData" : @[
369
+ @[@(1000.0 ), @(16.67 )], // Frame 1: start time 1000.0µs, duration 16.67µs
370
+ @[@(1016.67 ), @(33.33 )], // Frame 2: start time 1016.67µs, duration 33.33µs
371
+ @[@(1050.0 ), @(50.0 )] // Frame 3: start time 1050.0µs, duration 50.0µs
372
+ ]
373
+ };
374
+
375
+ [self .api endScreenRenderForAutoUiTraceData: frameData error: &error];
376
+
377
+ // Verify that endAutoUITraceCPWithFrames was called
378
+ OCMVerify ([self .mAPM endAutoUITraceCPWithFrames: [OCMArg checkWithBlock: ^BOOL (NSArray <IBGFrameInfo *> *frames) {
379
+ // Verify that we have the correct number of frames
380
+ XCTAssertEqual (frames.count , 3 );
381
+
382
+ // Verify the first frame
383
+ IBGFrameInfo *firstFrame = frames[0 ];
384
+ XCTAssertEqual (firstFrame.startTimestampInMicroseconds , 1000.0 );
385
+ XCTAssertEqual (firstFrame.durationInMicroseconds , 16.67 );
386
+
387
+ // Verify the second frame
388
+ IBGFrameInfo *secondFrame = frames[1 ];
389
+ XCTAssertEqual (secondFrame.startTimestampInMicroseconds , 1016.67 );
390
+ XCTAssertEqual (secondFrame.durationInMicroseconds , 33.33 );
391
+
392
+ // Verify the third frame
393
+ IBGFrameInfo *thirdFrame = frames[2 ];
394
+ XCTAssertEqual (thirdFrame.startTimestampInMicroseconds , 1050.0 );
395
+ XCTAssertEqual (thirdFrame.durationInMicroseconds , 50.0 );
396
+
397
+ return YES ;
398
+ }]]);
399
+ }
400
+
401
+ - (void )testEndScreenRenderForCustomUiTrace {
402
+ FlutterError *error;
403
+
404
+ // Create mock frame data
405
+ NSDictionary *frameData = @{
406
+ @" frameData" : @[
407
+ @[@(2000.0 ), @(20.0 )], // Frame 1: start time 2000.0µs, duration 20.0µs
408
+ @[@(2020.0 ), @(25.0 )] // Frame 2: start time 2020.0µs, duration 25.0µs
409
+ ]
410
+ };
411
+
412
+ [self .api endScreenRenderForCustomUiTraceData: frameData error: &error];
413
+
414
+ // Verify that endCustomUITraceCPWithFrames was called
415
+ OCMVerify ([self .mAPM endCustomUITraceCPWithFrames: [OCMArg checkWithBlock: ^BOOL (NSArray <IBGFrameInfo *> *frames) {
416
+ // Verify that we have the correct number of frames
417
+ XCTAssertEqual (frames.count , 2 );
418
+
419
+ // Verify the first frame
420
+ IBGFrameInfo *firstFrame = frames[0 ];
421
+ XCTAssertEqual (firstFrame.startTimestampInMicroseconds , 2000.0 );
422
+ XCTAssertEqual (firstFrame.durationInMicroseconds , 20.0 );
423
+
424
+ // Verify the second frame
425
+ IBGFrameInfo *secondFrame = frames[1 ];
426
+ XCTAssertEqual (secondFrame.startTimestampInMicroseconds , 2020.0 );
427
+ XCTAssertEqual (secondFrame.durationInMicroseconds , 25.0 );
428
+
429
+ return YES ;
430
+ }]]);
431
+ }
432
+
433
+ - (void )testEndScreenRenderForAutoUiTraceWithEmptyFrameData {
434
+ FlutterError *error;
435
+
436
+ // Create empty frame data
437
+ NSDictionary *frameData = @{
438
+ @" frameData" : @[]
439
+ };
440
+
441
+ [self .api endScreenRenderForAutoUiTraceData: frameData error: &error];
442
+
443
+ // Verify that endAutoUITraceCPWithFrames was called with empty array
444
+ OCMVerify ([self .mAPM endAutoUITraceCPWithFrames: [OCMArg checkWithBlock: ^BOOL (NSArray <IBGFrameInfo *> *frames) {
445
+ XCTAssertEqual (frames.count , 0 );
446
+ return YES ;
447
+ }]]);
448
+ }
449
+
450
+ - (void )testEndScreenRenderForCustomUiTraceWithEmptyFrameData {
451
+ FlutterError *error;
452
+
453
+ // Create empty frame data
454
+ NSDictionary *frameData = @{
455
+ @" frameData" : @[]
456
+ };
457
+
458
+ [self .api endScreenRenderForCustomUiTraceData: frameData error: &error];
459
+
460
+ // Verify that endCustomUITraceCPWithFrames was called with empty array
461
+ OCMVerify ([self .mAPM endCustomUITraceCPWithFrames: [OCMArg checkWithBlock: ^BOOL (NSArray <IBGFrameInfo *> *frames) {
462
+ XCTAssertEqual (frames.count , 0 );
463
+ return YES ;
464
+ }]]);
465
+ }
466
+
467
+ - (void )testEndScreenRenderForAutoUiTraceWithMalformedFrameData {
468
+ FlutterError *error;
469
+
470
+ // Create malformed frame data (missing values or extra values)
471
+ NSDictionary *frameData = @{
472
+ @" frameData" : @[
473
+ @[@(1000.0 )], // Frame with only one value (should be ignored)
474
+ @[@(1016.67 ), @(33.33 )], // Valid frame
475
+ @[@(1050.0 ), @(50.0 ), @(100.0 )] // Frame with extra values (should be ignored)
476
+ ]
477
+ };
478
+
479
+ [self .api endScreenRenderForAutoUiTraceData: frameData error: &error];
480
+
481
+ // Verify that endAutoUITraceCPWithFrames was called with only valid frames
482
+ OCMVerify ([self .mAPM endAutoUITraceCPWithFrames: [OCMArg checkWithBlock: ^BOOL (NSArray <IBGFrameInfo *> *frames) {
483
+ // Should only have 1 valid frame (first and third frames are ignored due to wrong count)
484
+ XCTAssertEqual (frames.count , 1 );
485
+
486
+ // Verify the valid frame
487
+ IBGFrameInfo *frame = frames[0 ];
488
+ XCTAssertEqual (frame.startTimestampInMicroseconds , 1016.67 );
489
+ XCTAssertEqual (frame.durationInMicroseconds , 33.33 );
490
+
491
+ return YES ;
492
+ }]]);
493
+ }
494
+
495
+ - (void )testEndScreenRenderForCustomUiTraceWithMalformedFrameData {
496
+ FlutterError *error;
497
+
498
+ // Create malformed frame data (missing values)
499
+ NSDictionary *frameData = @{
500
+ @" frameData" : @[
501
+ @[@(2000.0 )], // Frame with only one value (should be ignored)
502
+ @[@(2020.0 ), @(25.0 )] // Valid frame
503
+ ]
504
+ };
505
+
506
+ [self .api endScreenRenderForCustomUiTraceData: frameData error: &error];
507
+
508
+ // Verify that endCustomUITraceCPWithFrames was called with only valid frames
509
+ OCMVerify ([self .mAPM endCustomUITraceCPWithFrames: [OCMArg checkWithBlock: ^BOOL (NSArray <IBGFrameInfo *> *frames) {
510
+ // Should only have 1 valid frame
511
+ XCTAssertEqual (frames.count , 1 );
512
+
513
+ // Verify the valid frame
514
+ IBGFrameInfo *frame = frames[0 ];
515
+ XCTAssertEqual (frame.startTimestampInMicroseconds , 2020.0 );
516
+ XCTAssertEqual (frame.durationInMicroseconds , 25.0 );
517
+
518
+ return YES ;
519
+ }]]);
520
+ }
521
+
522
+ - (void )testEndScreenRenderForAutoUiTraceWithNilFrameData {
523
+ FlutterError *error;
524
+
525
+ // Create frame data with nil frameData
526
+ NSDictionary *frameData = @{
527
+ @" frameData" : [NSNull null ]
528
+ };
529
+
530
+ [self .api endScreenRenderForAutoUiTraceData: frameData error: &error];
531
+
532
+ // Verify that endAutoUITraceCPWithFrames was called with empty array
533
+ OCMVerify ([self .mAPM endAutoUITraceCPWithFrames: [OCMArg checkWithBlock: ^BOOL (NSArray <IBGFrameInfo *> *frames) {
534
+ XCTAssertEqual (frames.count , 0 );
535
+ return YES ;
536
+ }]]);
537
+ }
538
+
539
+ - (void )testEndScreenRenderForCustomUiTraceWithNilFrameData {
540
+ FlutterError *error;
541
+
542
+ // Create frame data with nil frameData
543
+ NSDictionary *frameData = @{
544
+ @" frameData" : [NSNull null ]
545
+ };
546
+
547
+ [self .api endScreenRenderForCustomUiTraceData: frameData error: &error];
548
+
549
+ // Verify that endCustomUITraceCPWithFrames was called with empty array
550
+ OCMVerify ([self .mAPM endCustomUITraceCPWithFrames: [OCMArg checkWithBlock: ^BOOL (NSArray <IBGFrameInfo *> *frames) {
551
+ XCTAssertEqual (frames.count , 0 );
552
+ return YES ;
553
+ }]]);
554
+ }
555
+
556
+ - (void )testEndScreenRenderForAutoUiTraceWithMissingFrameDataKey {
557
+ FlutterError *error;
558
+
559
+ // Create frame data without frameData key
560
+ NSDictionary *frameData = @{
561
+ @" otherKey" : @" someValue"
562
+ };
563
+
564
+ [self .api endScreenRenderForAutoUiTraceData: frameData error: &error];
565
+
566
+ // Verify that endAutoUITraceCPWithFrames was called with empty array
567
+ OCMVerify ([self .mAPM endAutoUITraceCPWithFrames: [OCMArg checkWithBlock: ^BOOL (NSArray <IBGFrameInfo *> *frames) {
568
+ XCTAssertEqual (frames.count , 0 );
569
+ return YES ;
570
+ }]]);
571
+ }
572
+
573
+ - (void )testEndScreenRenderForCustomUiTraceWithMissingFrameDataKey {
574
+ FlutterError *error;
575
+
576
+ // Create frame data without frameData key
577
+ NSDictionary *frameData = @{
578
+ @" otherKey" : @" someValue"
579
+ };
580
+
581
+ [self .api endScreenRenderForCustomUiTraceData: frameData error: &error];
582
+
583
+ // Verify that endCustomUITraceCPWithFrames was called with empty array
584
+ OCMVerify ([self .mAPM endCustomUITraceCPWithFrames: [OCMArg checkWithBlock: ^BOOL (NSArray <IBGFrameInfo *> *frames) {
585
+ XCTAssertEqual (frames.count , 0 );
586
+ return YES ;
587
+ }]]);
588
+ }
269
589
270
590
@end
0 commit comments