Skip to content
Merged
Prev Previous commit
Next Next commit
Simplify tests
  • Loading branch information
stuartmorgan-g committed Jun 30, 2025
commit 1963bb362c96ae7b98d7f1013df819a5b142e299
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,8 @@ - (void)testSeekToWhilePausedStartsDisplayLinkTemporarily {
StubFVPDisplayLinkFactory *stubDisplayLinkFactory =
[[StubFVPDisplayLinkFactory alloc] initWithDisplayLink:mockDisplayLink];
AVPlayerItemVideoOutput *mockVideoOutput = OCMPartialMock([[AVPlayerItemVideoOutput alloc] init]);
// Display link and frame updater wire-up is currently done in FVPVideoPlayerPlugin, so create
// the player via the plugin instead of directly to include that logic in the test.
FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc]
initWithAVFactory:[[StubFVPAVFactory alloc] initWithPlayer:nil output:mockVideoOutput]
displayLinkFactory:stubDisplayLinkFactory
Expand All @@ -310,8 +312,6 @@ - (void)testSeekToWhilePausedStartsDisplayLinkTemporarily {
viewType:FVPPlatformVideoViewTypeTextureView];
FlutterError *createError;
NSNumber *playerIdentifier = [videoPlayerPlugin createWithOptions:create error:&createError];

// TODO(stuartmorgan): Rework this test to only create the player, not the whole plugin.
FVPTextureBasedVideoPlayer *player =
(FVPTextureBasedVideoPlayer *)videoPlayerPlugin.playersByIdentifier[playerIdentifier];

Expand Down Expand Up @@ -411,6 +411,8 @@ - (void)testSeekToWhilePlayingDoesNotStopDisplayLink {
StubFVPDisplayLinkFactory *stubDisplayLinkFactory =
[[StubFVPDisplayLinkFactory alloc] initWithDisplayLink:mockDisplayLink];
AVPlayerItemVideoOutput *mockVideoOutput = OCMPartialMock([[AVPlayerItemVideoOutput alloc] init]);
// Display link and frame updater wire-up is currently done in FVPVideoPlayerPlugin, so create
// the player via the plugin instead of directly to include that logic in the test.
FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc]
initWithAVFactory:[[StubFVPAVFactory alloc] initWithPlayer:nil output:mockVideoOutput]
displayLinkFactory:stubDisplayLinkFactory
Expand All @@ -429,8 +431,6 @@ - (void)testSeekToWhilePlayingDoesNotStopDisplayLink {
viewType:FVPPlatformVideoViewTypeTextureView];
FlutterError *createError;
NSNumber *playerIdentifier = [videoPlayerPlugin createWithOptions:create error:&createError];

// TODO(stuartmorgan): Rework this test to only create the player, not the whole plugin.
FVPTextureBasedVideoPlayer *player =
(FVPTextureBasedVideoPlayer *)videoPlayerPlugin.playersByIdentifier[playerIdentifier];

Expand Down Expand Up @@ -474,6 +474,8 @@ - (void)testPauseWhileWaitingForFrameDoesNotStopDisplayLink {
StubFVPDisplayLinkFactory *stubDisplayLinkFactory =
[[StubFVPDisplayLinkFactory alloc] initWithDisplayLink:mockDisplayLink];
AVPlayerItemVideoOutput *mockVideoOutput = OCMPartialMock([[AVPlayerItemVideoOutput alloc] init]);
// Display link and frame updater wire-up is currently done in FVPVideoPlayerPlugin, so create
// the player via the plugin instead of directly to include that logic in the test.
FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc]
initWithAVFactory:[[StubFVPAVFactory alloc] initWithPlayer:nil output:mockVideoOutput]
displayLinkFactory:stubDisplayLinkFactory
Expand All @@ -492,8 +494,6 @@ - (void)testPauseWhileWaitingForFrameDoesNotStopDisplayLink {
viewType:FVPPlatformVideoViewTypeTextureView];
FlutterError *createError;
NSNumber *playerIdentifier = [videoPlayerPlugin createWithOptions:create error:&createError];

// TODO(stuartmorgan): Rework this test to only create the player, not the whole plugin.
FVPTextureBasedVideoPlayer *player =
(FVPTextureBasedVideoPlayer *)videoPlayerPlugin.playersByIdentifier[playerIdentifier];

Expand Down Expand Up @@ -583,59 +583,36 @@ - (void)testBufferingStateFromPlayer {
}

- (void)testVideoControls {
NSObject<FlutterPluginRegistrar> *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar));
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rest of the changes in this file are just cleanup for cases that used to test via the plugin, but were really just testing player functionality so could be easily switched to creating a player instance directly instead of creating and driving the player via the plugin (which after my change was creating the player via the plugin, looking it up, and then driving it via the player anyway). See 1963bb3 for that cleanup, isolated as a separate commit.


FVPVideoPlayerPlugin *videoPlayerPlugin =
(FVPVideoPlayerPlugin *)[[FVPVideoPlayerPlugin alloc] initWithRegistrar:registrar];

NSDictionary<NSString *, id> *videoInitialization =
[self testPlugin:videoPlayerPlugin
uri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4"];
[self sanityTestURI:@"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4"];
XCTAssertEqualObjects(videoInitialization[@"height"], @720);
XCTAssertEqualObjects(videoInitialization[@"width"], @1280);
XCTAssertEqualWithAccuracy([videoInitialization[@"duration"] intValue], 4000, 200);
}

- (void)testAudioControls {
NSObject<FlutterPluginRegistrar> *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar));

FVPVideoPlayerPlugin *videoPlayerPlugin =
(FVPVideoPlayerPlugin *)[[FVPVideoPlayerPlugin alloc] initWithRegistrar:registrar];

NSDictionary<NSString *, id> *audioInitialization =
[self testPlugin:videoPlayerPlugin
uri:@"https://flutter.github.io/assets-for-api-docs/assets/audio/rooster.mp3"];
NSDictionary<NSString *, id> *audioInitialization = [self
sanityTestURI:@"https://flutter.github.io/assets-for-api-docs/assets/audio/rooster.mp3"];
XCTAssertEqualObjects(audioInitialization[@"height"], @0);
XCTAssertEqualObjects(audioInitialization[@"width"], @0);
// Perfect precision not guaranteed.
XCTAssertEqualWithAccuracy([audioInitialization[@"duration"] intValue], 5400, 200);
}

- (void)testHLSControls {
NSObject<FlutterPluginRegistrar> *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar));

FVPVideoPlayerPlugin *videoPlayerPlugin =
(FVPVideoPlayerPlugin *)[[FVPVideoPlayerPlugin alloc] initWithRegistrar:registrar];

NSDictionary<NSString *, id> *videoInitialization =
[self testPlugin:videoPlayerPlugin
uri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/hls/bee.m3u8"];
NSDictionary<NSString *, id> *videoInitialization = [self
sanityTestURI:@"https://flutter.github.io/assets-for-api-docs/assets/videos/hls/bee.m3u8"];
XCTAssertEqualObjects(videoInitialization[@"height"], @720);
XCTAssertEqualObjects(videoInitialization[@"width"], @1280);
XCTAssertEqualWithAccuracy([videoInitialization[@"duration"] intValue], 4000, 200);
}

- (void)testAudioOnlyHLSControls {
XCTSkip(@"Flaky; see https://github.com/flutter/flutter/issues/164381");
NSObject<FlutterPluginRegistrar> *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar));

FVPVideoPlayerPlugin *videoPlayerPlugin =
(FVPVideoPlayerPlugin *)[[FVPVideoPlayerPlugin alloc] initWithRegistrar:registrar];

NSDictionary<NSString *, id> *videoInitialization =
[self testPlugin:videoPlayerPlugin
uri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/hls/"
@"bee_audio_only.m3u8"];
[self sanityTestURI:@"https://flutter.github.io/assets-for-api-docs/assets/videos/hls/"
@"bee_audio_only.m3u8"];
XCTAssertEqualObjects(videoInitialization[@"height"], @0);
XCTAssertEqualObjects(videoInitialization[@"width"], @0);
XCTAssertEqualWithAccuracy([videoInitialization[@"duration"] intValue], 4000, 200);
Expand All @@ -655,40 +632,22 @@ - (void)testTransformFix {
#endif

- (void)testSeekToleranceWhenNotSeekingToEnd {
NSObject<FlutterPluginRegistrar> *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar));

StubAVPlayer *stubAVPlayer = [[StubAVPlayer alloc] init];
StubFVPAVFactory *stubAVFactory = [[StubFVPAVFactory alloc] initWithPlayer:stubAVPlayer
output:nil];
FVPVideoPlayerPlugin *pluginWithMockAVPlayer =
[[FVPVideoPlayerPlugin alloc] initWithAVFactory:stubAVFactory
displayLinkFactory:nil
viewProvider:[[StubViewProvider alloc] initWithView:nil]
registrar:registrar];

FlutterError *initializationError;
[pluginWithMockAVPlayer initialize:&initializationError];
XCTAssertNil(initializationError);

FVPCreationOptions *create = [FVPCreationOptions
makeWithAsset:nil
uri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4"
packageName:nil
formatHint:nil
httpHeaders:@{}
viewType:FVPPlatformVideoViewTypeTextureView];
FlutterError *createError;
NSNumber *playerIdentifier = [pluginWithMockAVPlayer createWithOptions:create error:&createError];

// TODO(stuartmorgan): Rework this test to only create the player, not the whole plugin.
FVPTextureBasedVideoPlayer *player =
(FVPTextureBasedVideoPlayer *)pluginWithMockAVPlayer.playersByIdentifier[playerIdentifier];

XCTestExpectation *initializedExpectation =
FVPVideoPlayer *player = [[FVPVideoPlayer alloc]
initWithURL:
[NSURL
URLWithString:@"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4"]
httpHeaders:@{}
avFactory:stubAVFactory
viewProvider:[[StubViewProvider alloc] initWithView:nil]];

XCTestExpectation *seekExpectation =
[self expectationWithDescription:@"seekTo has zero tolerance when seeking not to end"];
[player seekTo:1234
completion:^(FlutterError *_Nullable error) {
[initializedExpectation fulfill];
[seekExpectation fulfill];
}];

[self waitForExpectationsWithTimeout:30.0 handler:nil];
Expand All @@ -697,64 +656,37 @@ - (void)testSeekToleranceWhenNotSeekingToEnd {
}

- (void)testSeekToleranceWhenSeekingToEnd {
NSObject<FlutterPluginRegistrar> *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar));

StubAVPlayer *stubAVPlayer = [[StubAVPlayer alloc] init];
StubFVPAVFactory *stubAVFactory = [[StubFVPAVFactory alloc] initWithPlayer:stubAVPlayer
output:nil];
FVPVideoPlayerPlugin *pluginWithMockAVPlayer =
[[FVPVideoPlayerPlugin alloc] initWithAVFactory:stubAVFactory
displayLinkFactory:nil
viewProvider:[[StubViewProvider alloc] initWithView:nil]
registrar:registrar];

FlutterError *initializationError;
[pluginWithMockAVPlayer initialize:&initializationError];
XCTAssertNil(initializationError);

FVPCreationOptions *create = [FVPCreationOptions
makeWithAsset:nil
uri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4"
packageName:nil
formatHint:nil
httpHeaders:@{}
viewType:FVPPlatformVideoViewTypeTextureView];
FlutterError *createError;
NSNumber *playerIdentifier = [pluginWithMockAVPlayer createWithOptions:create error:&createError];

// TODO(stuartmorgan): Rework this test to only create the player, not the whole plugin.
FVPTextureBasedVideoPlayer *player =
(FVPTextureBasedVideoPlayer *)pluginWithMockAVPlayer.playersByIdentifier[playerIdentifier];

XCTestExpectation *initializedExpectation =
FVPVideoPlayer *player = [[FVPVideoPlayer alloc]
initWithURL:
[NSURL
URLWithString:@"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4"]
httpHeaders:@{}
avFactory:stubAVFactory
viewProvider:[[StubViewProvider alloc] initWithView:nil]];

XCTestExpectation *seekExpectation =
[self expectationWithDescription:@"seekTo has non-zero tolerance when seeking to end"];
// The duration of this video is "0" due to the non standard initiliatazion process.
[player seekTo:0
completion:^(FlutterError *_Nullable error) {
[initializedExpectation fulfill];
[seekExpectation fulfill];
}];
[self waitForExpectationsWithTimeout:30.0 handler:nil];
XCTAssertGreaterThan([stubAVPlayer.beforeTolerance intValue], 0);
XCTAssertGreaterThan([stubAVPlayer.afterTolerance intValue], 0);
}

- (NSDictionary<NSString *, id> *)testPlugin:(FVPVideoPlayerPlugin *)videoPlayerPlugin
uri:(NSString *)uri {
FlutterError *error;
[videoPlayerPlugin initialize:&error];
XCTAssertNil(error);

FVPCreationOptions *create =
[FVPCreationOptions makeWithAsset:nil
uri:uri
packageName:nil
formatHint:nil
httpHeaders:@{}
viewType:FVPPlatformVideoViewTypeTextureView];
NSNumber *playerIdentifier = [videoPlayerPlugin createWithOptions:create error:&error];

// TODO(stuartmorgan): Rework this test to only create the player, not the whole plugin.
FVPVideoPlayer *player = videoPlayerPlugin.playersByIdentifier[playerIdentifier];
/// Sanity checks a video player playing the given URL with the actual AVPlayer. This is essentially
/// a mini integration test of the player component.
- (NSDictionary<NSString *, id> *)sanityTestURI:(NSString *)uri {
FVPVideoPlayer *player =
[[FVPVideoPlayer alloc] initWithURL:[NSURL URLWithString:uri]
httpHeaders:@{}
avFactory:[[FVPDefaultAVFactory alloc] init]
viewProvider:[[StubViewProvider alloc] initWithView:nil]];
XCTAssertNotNil(player);

XCTestExpectation *initializedExpectation = [self expectationWithDescription:@"initialized"];
Expand All @@ -776,6 +708,7 @@ - (void)testSeekToleranceWhenSeekingToEnd {
XCTAssertEqual(avPlayer.timeControlStatus, AVPlayerTimeControlStatusPaused);

// Change playback speed.
FlutterError *error;
[player setPlaybackSpeed:2 error:&error];
XCTAssertNil(error);
[player playWithError:&error];
Expand Down Expand Up @@ -963,27 +896,13 @@ - (void)testFailedToLoadVideoEventShouldBeAlwaysSent {
}

- (void)testUpdatePlayingStateShouldNotResetRate {
NSObject<FlutterPluginRegistrar> *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar));

FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc]
initWithAVFactory:[[StubFVPAVFactory alloc] initWithPlayer:nil output:nil]
displayLinkFactory:nil
viewProvider:[[StubViewProvider alloc] initWithView:nil]
registrar:registrar];

FlutterError *error;
[videoPlayerPlugin initialize:&error];
XCTAssertNil(error);
FVPCreationOptions *create = [FVPCreationOptions
makeWithAsset:nil
uri:@"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4"
packageName:nil
formatHint:nil
httpHeaders:@{}
viewType:FVPPlatformVideoViewTypeTextureView];
NSNumber *playerIdentifier = [videoPlayerPlugin createWithOptions:create error:&error];
// TODO(stuartmorgan): Rework this test to only create the player, not the whole plugin.
FVPVideoPlayer *player = videoPlayerPlugin.playersByIdentifier[playerIdentifier];
FVPVideoPlayer *player = [[FVPVideoPlayer alloc]
initWithURL:
[NSURL
URLWithString:@"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4"]
httpHeaders:@{}
avFactory:[[StubFVPAVFactory alloc] initWithPlayer:nil output:nil]
viewProvider:[[StubViewProvider alloc] initWithView:nil]];

XCTestExpectation *initializedExpectation = [self expectationWithDescription:@"initialized"];
[player onListenWithArguments:nil
Expand All @@ -994,6 +913,7 @@ - (void)testUpdatePlayingStateShouldNotResetRate {
}];
[self waitForExpectationsWithTimeout:10 handler:nil];

FlutterError *error;
[player setPlaybackSpeed:2 error:&error];
[player playWithError:&error];
XCTAssertEqual(player.player.rate, 2);
Expand Down