FBSDKShareKit/FBSDKShareKitTests/Content/SharePhotoTests.swift (203 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under the license found in the * LICENSE file in the root directory of this source tree. */ @testable import FBSDKShareKit import Photos import TestTools import XCTest final class SharePhotoTests: XCTestCase { // swiftlint:disable implicitly_unwrapped_optional var photo: SharePhoto! var errorFactory: TestErrorFactory! // swiftlint:enable implicitly_unwrapped_optional override func setUp() { super.setUp() errorFactory = TestErrorFactory() SharePhoto.setDependencies(.init(errorFactory: errorFactory)) } override func tearDown() { errorFactory = nil SharePhoto.resetDependencies() photo = nil super.tearDown() } func testDefaultDependencies() throws { SharePhoto.resetDependencies() let dependencies = try SharePhoto.getDependencies() XCTAssertTrue(dependencies.errorFactory is ErrorFactory, .usesConcreteErrorFactoryByDefault) } func testCustomDependencies() throws { let dependencies = try SharePhoto.getDependencies() XCTAssertIdentical(dependencies.errorFactory, errorFactory, .usesCustomErrorFactory) } func testCreatingWithImage() { photo = SharePhoto(image: UIImage(), isUserGenerated: true) XCTAssertNotNil(photo.image, .hasOnlyImageSource) XCTAssertNil(photo.photoAsset, .hasOnlyImageSource) XCTAssertNil(photo.imageURL, .hasOnlyImageSource) } func testCreatingWithAsset() { photo = SharePhoto(photoAsset: PHAsset(), isUserGenerated: true) XCTAssertNotNil(photo.photoAsset, .hasOnlyAssetSource) XCTAssertNil(photo.image, .hasOnlyAssetSource) XCTAssertNil(photo.imageURL, .hasOnlyAssetSource) } func testCreatingWithURL() { photo = SharePhoto(imageURL: SampleURLs.valid, isUserGenerated: true) XCTAssertNotNil(photo.imageURL, .hasOnlyURLSource) XCTAssertNil(photo.image, .hasOnlyURLSource) XCTAssertNil(photo.photoAsset, .hasOnlyURLSource) } func testChangingSource() { photo = SharePhoto(image: UIImage(), isUserGenerated: true) photo.photoAsset = PHAsset() XCTAssertNil(photo.image, .otherSourcesClearedWhenChangingSource) photo.imageURL = SampleURLs.valid XCTAssertNil(photo.photoAsset, .otherSourcesClearedWhenChangingSource) photo.image = UIImage() XCTAssertNil(photo.imageURL, .otherSourcesClearedWhenChangingSource) } func testValidatingWithoutSource() { photo = SharePhoto() XCTAssertThrowsError(try photo.validate(options: []), .failsValidationWithoutSource) { error in guard let sdkError = error as? TestSDKError else { return XCTFail(.failsValidationWithoutSource) } XCTAssertEqual(sdkError.domain, ShareErrorDomain, .failsValidationWithoutSource) XCTAssertEqual(sdkError.name, "photo", .failsValidationWithoutSource) XCTAssertIdentical(sdkError.value as AnyObject, photo, .failsValidationWithoutSource) XCTAssertEqual( sdkError.message, "Must have an asset, image, or imageURL value.", .failsValidationWithoutSource ) XCTAssertNil(sdkError.underlyingError, .failsValidationWithoutSource) } } func testPhotoImageURLValidationFailureWithoutURL() { photo = SharePhoto() XCTAssertThrowsError( try photo.validate(options: .photoImageURL), .failsPhotoImageURLOptionValidationWithoutURL ) { error in guard let sdkError = error as? TestSDKError else { return XCTFail(.failsPhotoImageURLOptionValidationWithoutURL) } XCTAssertEqual(sdkError.domain, ShareErrorDomain, .failsPhotoImageURLOptionValidationWithoutURL) XCTAssertEqual(sdkError.name, "photo", .failsPhotoImageURLOptionValidationWithoutURL) XCTAssertIdentical(sdkError.value as AnyObject, photo, .failsPhotoImageURLOptionValidationWithoutURL) XCTAssertEqual( sdkError.message, "imageURL is required.", .failsPhotoImageURLOptionValidationWithoutURL ) XCTAssertNil(sdkError.underlyingError, .failsPhotoImageURLOptionValidationWithoutURL) } } func testPhotoImageURLValidationFailureWithoutFileURL() { photo = SharePhoto(imageURL: .localImage, isUserGenerated: true) XCTAssertThrowsError( try photo.validate(options: .photoImageURL), .failsPhotoImageURLOptionValidationWithoutRemoteURL ) { error in guard let sdkError = error as? TestSDKError else { return XCTFail(.failsPhotoImageURLOptionValidationWithoutRemoteURL) } XCTAssertEqual(sdkError.domain, ShareErrorDomain, .failsPhotoImageURLOptionValidationWithoutRemoteURL) XCTAssertEqual(sdkError.name, "imageURL", .failsPhotoImageURLOptionValidationWithoutRemoteURL) XCTAssertEqual(sdkError.value as? URL, .localImage, .failsPhotoImageURLOptionValidationWithoutRemoteURL) XCTAssertEqual( sdkError.message, "Cannot refer to a local file resource.", .failsPhotoImageURLOptionValidationWithoutRemoteURL ) XCTAssertNil(sdkError.underlyingError, .failsPhotoImageURLOptionValidationWithoutRemoteURL) } } func testPhotoImageURLValidationSuccess() { photo = SharePhoto(imageURL: .remoteImage, isUserGenerated: true) XCTAssertNoThrow(try photo.validate(options: .photoImageURL), .passesPhotoImageURLOptionValidation) } func testAssetValidationFailureWithoutImageMediaType() { let asset = TestPHAsset() photo = SharePhoto(photoAsset: asset, isUserGenerated: true) XCTAssertThrowsError( try photo.validate(options: []), .failsAssetValidationWithoutImageMediaType ) { error in guard let sdkError = error as? TestSDKError else { return XCTFail(.failsAssetValidationWithoutImageMediaType) } XCTAssertEqual(sdkError.domain, ShareErrorDomain, .failsAssetValidationWithoutImageMediaType) XCTAssertEqual(sdkError.name, "photoAsset", .failsAssetValidationWithoutImageMediaType) XCTAssertIdentical(sdkError.value as AnyObject, asset, .failsAssetValidationWithoutImageMediaType) XCTAssertEqual( sdkError.message, "Must refer to a photo or other static image.", .failsAssetValidationWithoutImageMediaType ) XCTAssertNil(sdkError.underlyingError, .failsAssetValidationWithoutImageMediaType) } } func testAssetValidationSuccess() { let asset = TestPHAsset() asset.stubbedMediaType = .image photo = SharePhoto(photoAsset: asset, isUserGenerated: true) XCTAssertNoThrow(try photo.validate(options: []), .passesAssetValidation) } func testURLValidationFailure() { photo = SharePhoto(imageURL: .remoteImage, isUserGenerated: true) XCTAssertThrowsError( try photo.validate(options: []), .failsURLValidationWithoutFileURL ) { error in guard let sdkError = error as? TestSDKError else { return XCTFail(.failsURLValidationWithoutFileURL) } XCTAssertEqual(sdkError.domain, ShareErrorDomain, .failsURLValidationWithoutFileURL) XCTAssertEqual(sdkError.name, "imageURL", .failsURLValidationWithoutFileURL) XCTAssertEqual(sdkError.value as? URL, .remoteImage, .failsURLValidationWithoutFileURL) XCTAssertEqual( sdkError.message, "Must refer to a local file resource.", .failsURLValidationWithoutFileURL ) XCTAssertNil(sdkError.underlyingError, .failsURLValidationWithoutFileURL) } } func testURLValidationSuccess() { photo = SharePhoto(imageURL: .localImage, isUserGenerated: true) XCTAssertNoThrow(try photo.validate(options: []), .passesURLValidation) } func testImageValidation() { let image = UIImage() photo = SharePhoto(image: image, isUserGenerated: true) XCTAssertNoThrow(try photo.validate(options: []), .passesImageValidation) } } // MARK: - Assumptions fileprivate extension String { static let usesConcreteErrorFactoryByDefault = """ The default error factory dependency should be a concrete ErrorFactory """ static let usesCustomErrorFactory = "The error factory dependency should be configurable" static let hasOnlyImageSource = "A photo with an image source should only have an image source" static let hasOnlyAssetSource = "A photo with an asset source should only have an asset source" static let hasOnlyURLSource = "A photo with a URL source should only have a URL source" static let otherSourcesClearedWhenChangingSource = "Changing a photo source should clear other sources" static let failsValidationWithoutSource = "Validating a photo without a source should throw an error" static let failsPhotoImageURLOptionValidationWithoutURL = """ Validating a photo with the image photo URL option should fail without a URL """ static let failsPhotoImageURLOptionValidationWithoutRemoteURL = """ Validating a photo with the image photo URL option should fail without a remote URL """ static let passesPhotoImageURLOptionValidation = """ Validating a photo with the image photo URL option should pass with a file URL """ static let failsAssetValidationWithoutImageMediaType = """ Validating an asset photo without the image media type should throw an error """ static let passesAssetValidation = "Validating an asset photo with the image media type should pass" static let failsURLValidationWithoutFileURL = "Validating a URL photo should fail without a file URL" static let passesURLValidation = "Validating a URL photo should pass with a file URL" static let passesImageValidation = "Validating an image photo should pass" } // MARK: - Test Values fileprivate extension URL { // swiftlint:disable force_unwrapping static let remoteImage = URL(string: "https://facebook.com/myPhoto.png")! static let localImage = URL(string: "file:///Users/anyone/myPhoto.png")! // swiftlint:enable force_unwrapping }