Skip to content

[image_picker] Add native tests for image, metadata, photo-asset, and PHPicker save utilities - #12536

Open
victogomez-cs wants to merge 2 commits into
flutter:mainfrom
victogomez-cs:image_picker_coverage_1_util_tests
Open

[image_picker] Add native tests for image, metadata, photo-asset, and PHPicker save utilities#12536
victogomez-cs wants to merge 2 commits into
flutter:mainfrom
victogomez-cs:image_picker_coverage_1_util_tests

Conversation

@victogomez-cs

@victogomez-cs victogomez-cs commented Aug 21, 2026

Copy link
Copy Markdown

Adds native unit tests for previously untested paths in FLTImagePickerImageUtil, FLTImagePickerMetaDataUtil, FLTImagePickerPhotoAssetUtil, and FLTPHPickerSaveImageToPathOperation before the Objective-C → Swift migration. Production code is unchanged.

This is a tests-only change, so it does not bump the package version or CHANGELOG.

Native RunnerTests go from 72 tests to 88 tests (+16).

New test cases

ImageUtilTests:

  • testScaledGIFImage_UsesClampedDelayWhenUnclampedDelayMissing — GIF scaling uses the clamped delay when unclamped delay is missing

MetaDataUtilTests:

  • testGetImageMIMETypeFromImageDataUnknownReturnsOther — unrecognized image bytes map to the Other MIME type
  • testConvertImageIgnoresQualityForPNG — PNG conversion ignores JPEG quality and stays PNG
  • testConvertImageDefaultsNonJPEGNonPNGToJPEG — GIF and other non-JPEG/PNG data convert to JPEG

PhotoAssetUtilTests:

  • testGetAssetFromImagePickerInfoShouldReturnNilIfNotAvailable — picker info without a PHAsset returns nil
  • testGetAssetFromImagePickerInfoShouldReturnAssetIfPresent — picker info with a PHAsset returns that asset
  • testSaveVideoFromURLReturnsNilWhenSourceIsUnreadable — missing source file returns nil
  • testSaveVideoFromURLCopiesReadableFile — a readable video is copied to a new path
  • testSaveVideoFromURLReturnsNilWhenCopyFails — copy failure returns nil
  • testSaveImageWithOriginalImageDataNilUsesDefaultJPEGnil original data saves as .jpg
  • testCreateFileReturnsPathWhenWriteFails — create-file still returns a path when the write fails

PickerSaveImageToPathOperationTests:

  • testInitWithNilResultReturnsNilnil PHPicker result does not create an operation
  • testStartWhenCancelledFinishesWithoutSaving — a cancelled operation finishes without calling the save callback
  • testSaveVideoCopiesFile — a video item is copied to the saved path
  • testSaveVideoFailsWhenLoadReturnsError — a load error is reported as invalid_image
  • testSaveVideoFailsWhenCopyFails — a copy error is reported as flutter_image_picker_copy_video_error

First part of image_picker_ios coverage backfill before the Obj-C → Swift migration for flutter/flutter#119107

Pre-Review Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

Footnotes

  1. Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. 2

@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label Aug 21, 2026
@victogomez-cs victogomez-cs changed the title [image_picker_ios] Add native tests for image, metadata, photo-asset, and PHPicker save utilities [image_picker] Add native tests for image, metadata, photo-asset, and PHPicker save utilities Aug 21, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request adds comprehensive unit tests for image, metadata, photo asset, and path operation utilities in the iOS image picker package. The review feedback highlights opportunities to improve test robustness and hygiene, specifically by cleaning up temporary files and guarding against potential crashes caused by passing nil URLs to file management APIs.

Comment on lines +46 to +49
XCTAssertNotNil(destination);
XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:destination.path]);
[[NSFileManager defaultManager] removeItemAtPath:sourcePath error:nil];
[[NSFileManager defaultManager] removeItemAtURL:destination error:nil];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

If saveVideoFromURL: returns nil, destination will be nil. Passing a nil URL to removeItemAtURL:error: throws an NSInvalidArgumentException and will crash the test runner instead of failing the test gracefully. We should guard the cleanup call and the file existence check to ensure they only run if destination is non-nil.

  XCTAssertNotNil(destination);
  if (destination) {
    XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:destination.path]);
  }
  [[NSFileManager defaultManager] removeItemAtPath:sourcePath error:nil];
  if (destination) {
    [[NSFileManager defaultManager] removeItemAtURL:destination error:nil];
  }

@victogomez-cs victogomez-cs Aug 21, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed! Good catch, XCTAssertNotNil doesn’t abort the test, so removeItemAtURL: could be called with nil and throw. Guarded the existence check and cleanup so they only run when destination is non-nil

Comment on lines +84 to +85
XCTAssertEqualObjects([NSURL fileURLWithPath:savedPath].pathExtension, @"jpg");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The temporary file created at savedPath is not cleaned up after the test completes, which leaks files in the temporary directory. We should remove the file at savedPath at the end of the test.

  XCTAssertEqualObjects([NSURL fileURLWithPath:savedPath].pathExtension, @"jpg");
  if (savedPath) {
    [[NSFileManager defaultManager] removeItemAtPath:savedPath error:nil];
  }
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed and fixed. The test now removes savedPath after the assertion.

Comment on lines +301 to +305
savedPathBlock:^(NSString *savedPath, FlutterError *error) {
XCTAssertNil(error);
XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:savedPath]);
[pathExpectation fulfill];
}];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The temporary file created at savedPath by the operation is not cleaned up, leaking files in the temporary directory. We should delete the file at savedPath inside the completion block.

Suggested change
savedPathBlock:^(NSString *savedPath, FlutterError *error) {
XCTAssertNil(error);
XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:savedPath]);
[pathExpectation fulfill];
}];
savedPathBlock:^(NSString *savedPath, FlutterError *error) {
XCTAssertNil(error);
XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:savedPath]);
if (savedPath) {
[[NSFileManager defaultManager] removeItemAtPath:savedPath error:nil];
}
[pathExpectation fulfill];
}];

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed and fixed. The copied file is now deleted after the operation finishes (in addition to the source .mov).

…onTests to ensure temporary files are removed after assertions. This prevents potential file clutter during test execution.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant