You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

142 lines
5.6 KiB

import CoreMedia
import XCTest
@testable import DropTwoCore
final class CropEngineTests: XCTestCase {
private var tempDirectory: URL!
override func setUpWithError() throws {
tempDirectory = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
try FileManager.default.createDirectory(at: tempDirectory, withIntermediateDirectories: true)
}
override func tearDownWithError() throws {
try? FileManager.default.removeItem(at: tempDirectory)
}
// MARK: - Geometrie (rein arithmetisch, kein Video nötig)
func testTargetSizeMatchesReadmeExamples() {
XCTAssertEqual(
CropEngine.targetSize(forSourceSize: CGSize(width: 1080, height: 1920)),
CGSize(width: 1080, height: 1350)
)
XCTAssertEqual(
CropEngine.targetSize(forSourceSize: CGSize(width: 2160, height: 3840)),
CGSize(width: 2160, height: 2700)
)
}
func testTargetSizeRoundsHeightToEvenNumber() {
let size = CropEngine.targetSize(forSourceSize: CGSize(width: 217, height: 386))
XCTAssertEqual(size.width, 217)
XCTAssertEqual(size.height.truncatingRemainder(dividingBy: 2), 0)
}
// MARK: - End-to-End gegen einen synthetischen Clip
func testCropsToTargetSizeAndKeepsAudioAndDuration() async throws {
let clip = try TestVideoFactory.makeNineBySixteenClip(in: tempDirectory)
let destination = tempDirectory.appendingPathComponent("out.mp4")
try await CropEngine.crop(sourceURL: clip.url, destinationURL: destination)
let resultInfo = try await VideoInspector.inspect(destination)
let expectedSize = CropEngine.targetSize(forSourceSize: clip.size)
XCTAssertEqual(resultInfo.pixelSize, expectedSize)
XCTAssertEqual(resultInfo.codec, .h264)
XCTAssertTrue(resultInfo.hasAudioTrack)
XCTAssertEqual(CMTimeGetSeconds(resultInfo.duration), clip.seconds, accuracy: 0.3)
}
func testCropsWithoutAudioTrack() async throws {
let clip = try TestVideoFactory.makeNineBySixteenClip(includeAudio: false, in: tempDirectory)
let destination = tempDirectory.appendingPathComponent("out.mp4")
try await CropEngine.crop(sourceURL: clip.url, destinationURL: destination)
let resultInfo = try await VideoInspector.inspect(destination)
XCTAssertFalse(resultInfo.hasAudioTrack)
}
func testReportsProgress() async throws {
let clip = try TestVideoFactory.makeNineBySixteenClip(in: tempDirectory)
let destination = tempDirectory.appendingPathComponent("out.mp4")
var reportedValues: [Double] = []
try await CropEngine.crop(sourceURL: clip.url, destinationURL: destination) { value in
reportedValues.append(value)
}
XCTAssertFalse(reportedValues.isEmpty)
XCTAssertEqual(reportedValues.last ?? 0, 1.0, accuracy: 0.15)
}
// MARK: - Ablehnungen
func testRejectsNonNineBySixteenSource() async throws {
let clip = try TestVideoFactory.makeClip(size: CGSize(width: 400, height: 400), in: tempDirectory)
let destination = tempDirectory.appendingPathComponent("out.mp4")
do {
try await CropEngine.crop(sourceURL: clip.url, destinationURL: destination)
XCTFail("Erwartete Ablehnung für eine Nicht-9:16-Quelle")
} catch CropEngineError.sourceNotNineBySixteen {
// erwartet
}
}
func testRejectsExistingDestinationWithoutOverwrite() async throws {
let clip = try TestVideoFactory.makeNineBySixteenClip(in: tempDirectory)
let destination = tempDirectory.appendingPathComponent("out.mp4")
FileManager.default.createFile(atPath: destination.path, contents: Data())
do {
try await CropEngine.crop(sourceURL: clip.url, destinationURL: destination)
XCTFail("Erwartete Ablehnung wegen bestehender Zieldatei")
} catch CropEngineError.destinationAlreadyExists {
// erwartet
}
}
func testOverwritesExistingDestinationWhenExplicitlyAllowed() async throws {
let clip = try TestVideoFactory.makeNineBySixteenClip(in: tempDirectory)
let destination = tempDirectory.appendingPathComponent("out.mp4")
FileManager.default.createFile(atPath: destination.path, contents: Data("platzhalter".utf8))
try await CropEngine.crop(
sourceURL: clip.url,
destinationURL: destination,
options: .init(overwrite: true)
)
let resultInfo = try await VideoInspector.inspect(destination)
XCTAssertEqual(resultInfo.pixelSize, CropEngine.targetSize(forSourceSize: clip.size))
}
func testRejectsUnsupportedContainer() async throws {
let clip = try TestVideoFactory.makeNineBySixteenClip(in: tempDirectory)
let destination = tempDirectory.appendingPathComponent("out.mxf")
do {
try await CropEngine.crop(sourceURL: clip.url, destinationURL: destination)
XCTFail("Erwartete Ablehnung für ein MXF-Ziel")
} catch CropEngineError.unsupportedContainer {
// erwartet
}
}
func testRejectsMovAsDestinationBecauseTargetIsFixedToMp4() async throws {
let clip = try TestVideoFactory.makeNineBySixteenClip(in: tempDirectory)
let destination = tempDirectory.appendingPathComponent("out.mov")
do {
try await CropEngine.crop(sourceURL: clip.url, destinationURL: destination)
XCTFail("Erwartete Ablehnung für ein MOV-Ziel — Zielformat ist fest auf MP4 gesetzt")
} catch CropEngineError.unsupportedContainer {
// erwartet
}
}
}

Powered by TurnKey Linux.