FBSDKShareKit/FBSDKShareKitTests/Content/ShareVideoTests.swift (225 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 ShareVideoTests: XCTestCase {
// swiftlint:disable implicitly_unwrapped_optional
var video: ShareVideo!
var errorFactory: TestErrorFactory!
// swiftlint:enable implicitly_unwrapped_optional
override func setUp() {
super.setUp()
errorFactory = TestErrorFactory()
ShareVideo.setDependencies(.init(errorFactory: errorFactory))
}
override func tearDown() {
errorFactory = nil
ShareVideo.resetDependencies()
video = nil
super.tearDown()
}
func testDefaultDependencies() throws {
ShareVideo.resetDependencies()
let dependencies = try ShareVideo.getDependencies()
XCTAssertTrue(dependencies.errorFactory is ErrorFactory, .usesConcreteErrorFactoryByDefault)
}
func testCustomDependencies() throws {
let dependencies = try ShareVideo.getDependencies()
XCTAssertIdentical(dependencies.errorFactory, errorFactory, .usesCustomErrorFactory)
}
func testCreatingWithData() {
video = ShareVideo(data: Data())
XCTAssertNotNil(video.data, .hasOnlyDataSource)
XCTAssertNil(video.videoAsset, .hasOnlyDataSource)
XCTAssertNil(video.videoURL, .hasOnlyDataSource)
}
func testCreatingWithAsset() {
video = ShareVideo(videoAsset: PHAsset())
XCTAssertNotNil(video.videoAsset, .hasOnlyAssetSource)
XCTAssertNil(video.data, .hasOnlyAssetSource)
XCTAssertNil(video.videoURL, .hasOnlyAssetSource)
}
func testCreatingWithURL() {
video = ShareVideo(videoURL: SampleURLs.valid)
XCTAssertNotNil(video.videoURL, .hasOnlyURLSource)
XCTAssertNil(video.data, .hasOnlyURLSource)
XCTAssertNil(video.videoAsset, .hasOnlyURLSource)
}
func testChangingSource() {
video = ShareVideo(data: Data(), previewPhoto: SharePhoto())
XCTAssertNotNil(video.previewPhoto, .canHavePreviewPhoto)
video.videoAsset = PHAsset()
XCTAssertNil(video.data, .otherSourcesClearedWhenChangingSource)
XCTAssertNil(video.previewPhoto, .previewPhotoClearedWhenChangingSource)
// Add back preview photo
video.previewPhoto = SharePhoto()
XCTAssertNotNil(video.previewPhoto, .canHavePreviewPhoto)
video.videoURL = SampleURLs.valid
XCTAssertNil(video.videoAsset, .otherSourcesClearedWhenChangingSource)
XCTAssertNil(video.previewPhoto, .previewPhotoClearedWhenChangingSource)
// Add back preview photo
video.previewPhoto = SharePhoto()
XCTAssertNotNil(video.previewPhoto, .canHavePreviewPhoto)
video.data = Data()
XCTAssertNil(video.videoURL, .otherSourcesClearedWhenChangingSource)
XCTAssertNil(video.previewPhoto, .previewPhotoClearedWhenChangingSource)
}
func testValidatingWithoutSource() {
video = ShareVideo()
XCTAssertThrowsError(try video.validate(options: []), .failsValidationWithoutSource) { error in
guard let sdkError = error as? TestSDKError else {
return XCTFail(.failsValidationWithoutSource)
}
XCTAssertEqual(sdkError.domain, ShareErrorDomain, .failsValidationWithoutSource)
XCTAssertEqual(sdkError.name, "video", .failsValidationWithoutSource)
XCTAssertIdentical(sdkError.value as AnyObject, video, .failsValidationWithoutSource)
XCTAssertEqual(
sdkError.message,
"Must have an asset, data, or videoURL value.",
.failsValidationWithoutSource
)
XCTAssertNil(sdkError.underlyingError, .failsValidationWithoutSource)
}
}
func testValidationFailureWithDataSource() {
let data = Data()
video = ShareVideo(data: data, previewPhoto: nil)
XCTAssertThrowsError(
try video.validate(options: []),
.failsBadOptionsValidationWithDataSource
) { error in
guard let sdkError = error as? TestSDKError else {
return XCTFail(.failsBadOptionsValidationWithDataSource)
}
XCTAssertEqual(sdkError.domain, ShareErrorDomain, .failsBadOptionsValidationWithDataSource)
XCTAssertEqual(sdkError.name, "data", .failsBadOptionsValidationWithDataSource)
XCTAssertEqual(sdkError.value as? Data, data, .failsBadOptionsValidationWithDataSource)
XCTAssertEqual(
sdkError.message,
"Cannot share video data.",
.failsBadOptionsValidationWithDataSource
)
XCTAssertNil(sdkError.underlyingError, .failsBadOptionsValidationWithDataSource)
}
}
func testValidationSuccessWithDataSource() {
video = ShareVideo(data: Data(), previewPhoto: nil)
XCTAssertNoThrow(try video.validate(options: .videoData), .passesValidationWithDataSource)
}
func testValidationFailureWithAssetSource() {
let asset = TestPHAsset()
asset.stubbedMediaType = .audio
video = ShareVideo(videoAsset: asset, previewPhoto: nil)
XCTAssertThrowsError(
try video.validate(options: []),
.failsBadMediaTypeValidationWithAssetSource
) { error in
guard let sdkError = error as? TestSDKError else {
return XCTFail(.failsBadMediaTypeValidationWithAssetSource)
}
XCTAssertEqual(sdkError.domain, ShareErrorDomain, .failsBadMediaTypeValidationWithAssetSource)
XCTAssertEqual(sdkError.name, "videoAsset", .failsBadMediaTypeValidationWithAssetSource)
XCTAssertIdentical(sdkError.value as AnyObject, asset, .failsBadMediaTypeValidationWithAssetSource)
XCTAssertEqual(
sdkError.message,
"Must refer to a video file.",
.failsBadMediaTypeValidationWithAssetSource
)
XCTAssertNil(sdkError.underlyingError, .failsBadMediaTypeValidationWithAssetSource)
}
}
func testValidationSuccessWithAssetSource() {
let asset = TestPHAsset()
asset.stubbedMediaType = .video
video = ShareVideo(videoAsset: asset, previewPhoto: nil)
XCTAssertNoThrow(try video.validate(options: .videoData), .passesValidationWithAssetSource)
}
func testValidationFailureWithRemoteURLSource() {
let url = URL.remoteVideo
video = ShareVideo(videoURL: url, previewPhoto: nil)
XCTAssertThrowsError(
try video.validate(options: []),
.failsValidationWithRemoteURLSource
) { error in
guard let sdkError = error as? TestSDKError else {
return XCTFail(.failsValidationWithRemoteURLSource)
}
XCTAssertEqual(sdkError.domain, ShareErrorDomain, .failsValidationWithRemoteURLSource)
XCTAssertEqual(sdkError.name, "videoURL", .failsValidationWithRemoteURLSource)
XCTAssertEqual(sdkError.value as? URL, url, .failsValidationWithRemoteURLSource)
XCTAssertEqual(
sdkError.message,
"Must refer to an asset file.",
.failsValidationWithRemoteURLSource
)
XCTAssertNil(sdkError.underlyingError, .failsValidationWithRemoteURLSource)
}
}
func testValidationFailureWithFileURLSource() {
let url = URL.localVideo
video = ShareVideo(videoURL: url, previewPhoto: nil)
XCTAssertThrowsError(
try video.validate(options: []),
.failsValidationWithFileURLSource
) { error in
guard let sdkError = error as? TestSDKError else {
return XCTFail(.failsValidationWithFileURLSource)
}
XCTAssertEqual(sdkError.domain, ShareErrorDomain, .failsValidationWithFileURLSource)
XCTAssertEqual(sdkError.name, "videoURL", .failsValidationWithFileURLSource)
XCTAssertEqual(sdkError.value as? URL, url, .failsValidationWithFileURLSource)
XCTAssertEqual(
sdkError.message,
"Must refer to an asset file.",
.failsValidationWithFileURLSource
)
XCTAssertNil(sdkError.underlyingError, .failsValidationWithFileURLSource)
}
}
func testValidationSuccessWithAssetLibraryURLSource() throws {
video = ShareVideo(videoURL: .videoAsset, previewPhoto: nil)
XCTAssertNoThrow(try video.validate(options: []))
}
func testValidationSuccessWithFileURLSource() throws {
video = ShareVideo(videoURL: .localVideo, previewPhoto: nil)
XCTAssertNoThrow(try video.validate(options: .videoData))
}
}
// 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 hasOnlyDataSource = "A video with a data source should only have a data source"
static let hasOnlyAssetSource = "A video with an asset source should only have an asset source"
static let hasOnlyURLSource = "A video with a URL source should only have a URL source"
static let canHavePreviewPhoto = "A video should be able to have a preview photo"
static let otherSourcesClearedWhenChangingSource = "Changing a video source should clear other sources"
static let previewPhotoClearedWhenChangingSource = "Changing a video source should clear the preview photo"
static let failsValidationWithoutSource = "Validating a video without a source should throw an error"
static let failsBadOptionsValidationWithDataSource = """
Validating a data source video without using the video data bridge option should throw an error
"""
static let passesValidationWithDataSource = """
Validating a data source video with the video data bridge option should not throw an error
"""
static let failsBadMediaTypeValidationWithAssetSource = """
Validating an asset source video without the video media type should throw an error
"""
static let passesValidationWithAssetSource = """
Validating an asset source video with the video media type should not throw an error
"""
static let failsValidationWithRemoteURLSource = """
Validating a URL source video with a remote URL should throw an error
"""
static let failsValidationWithFileURLSource = """
Validating a URL source video with a file URL without using the video data bridge option should throw an error
"""
static let passesValidationWithAssetLibraryURLSource = """
Validating a URL source video with an asset library URL should not throw an error
"""
static let passesValidationWithFileURLSource = """
Validating a URL source video with a file URL and the video data bridge option should not throw an error
"""
}
// MARK: - Test Values
fileprivate extension URL {
// swiftlint:disable force_unwrapping
static let videoAsset = URL(string: "assets-library://blah-blah-blah/video.mpg")!
static let remoteVideo = URL(string: "https://facebook.com/myVideo.mpg")!
static let localVideo = URL(string: "file:///Users/anyone/myVideo.mpg")!
// swiftlint:enable force_unwrapping
}