import XCTest @testable import DropTwoCore final class FileNameParserTests: XCTestCase { // MARK: - Erfolgreiches Parsen func testParsesStandardFileName() { let result = FileNameParser.parse("SOMOS-9x16-v3-DE.mp4") guard case .parsed(let parsed) = result.outcome else { return XCTFail("Erwartete .parsed, bekam \(result.outcome)") } XCTAssertEqual(parsed.projectName, "SOMOS") XCTAssertEqual(parsed.sourceFormatToken, "9x16") XCTAssertEqual(parsed.remainder, "v3-DE") XCTAssertEqual(parsed.fileExtension, "mp4") XCTAssertEqual(parsed.originalFileName, "SOMOS-9x16-v3-DE.mp4") XCTAssertEqual(parsed.targetFileName, "SOMOS-4x5-v3-DE.mp4") } func testProjectNameWithHyphenIsPreserved() { let result = FileNameParser.parse("Somos-Pendant-9x16-v3-DE.mp4") guard case .parsed(let parsed) = result.outcome else { return XCTFail("Erwartete .parsed, bekam \(result.outcome)") } XCTAssertEqual(parsed.projectName, "Somos-Pendant") XCTAssertEqual(parsed.targetFileName, "Somos-Pendant-4x5-v3-DE.mp4") } func testLanguageSegmentWithHyphenIsPreserved() { let result = FileNameParser.parse("SOMOS-9x16-v3-EN-US.mp4") guard case .parsed(let parsed) = result.outcome else { return XCTFail("Erwartete .parsed, bekam \(result.outcome)") } XCTAssertEqual(parsed.projectName, "SOMOS") XCTAssertEqual(parsed.remainder, "v3-EN-US") XCTAssertEqual(parsed.targetFileName, "SOMOS-4x5-v3-EN-US.mp4") } func testCaseInsensitiveFormatTokenIsRecognized() { let result = FileNameParser.parse("somos-9X16-v3-de.mp4") guard case .parsed(let parsed) = result.outcome else { return XCTFail("Erwartete .parsed, bekam \(result.outcome)") } // Sonst unveränderte Schreibweise bleibt erhalten. XCTAssertEqual(parsed.projectName, "somos") XCTAssertEqual(parsed.sourceFormatToken, "9X16") XCTAssertEqual(parsed.remainder, "v3-de") XCTAssertEqual(parsed.targetFileName, "somos-4x5-v3-de.mp4") } func testFileExtensionIsPreservedVerbatim() { for ext in ["mp4", "mov", "mxf", "MOV"] { let fileName = "SOMOS-9x16-v3-DE.\(ext)" let result = FileNameParser.parse(fileName) guard case .parsed(let parsed) = result.outcome else { return XCTFail("Erwartete .parsed für \(fileName), bekam \(result.outcome)") } XCTAssertEqual(parsed.fileExtension, ext) XCTAssertEqual(parsed.targetFileName, "SOMOS-4x5-v3-DE.\(ext)") } } // MARK: - Skip func testAlreadyTargetFormatIsSkipped() { let result = FileNameParser.parse("SOMOS-4x5-v3-DE.mp4") XCTAssertEqual(result.outcome, .skipped(.alreadyTargetFormat)) } // MARK: - Rejection func testMissingFormatSegmentIsRejected() { let result = FileNameParser.parse("SOMOS-v3-DE.mp4") XCTAssertEqual(result.outcome, .rejected(.formatSegmentMissing)) } func testFinderDuplicateIsRejected() { let result = FileNameParser.parse("SOMOS-9x16-v3-DE (1).mp4") XCTAssertEqual(result.outcome, .rejected(.finderDuplicate)) } func testFinderDuplicateTakesPriorityOverMissingFormatSegment() { // Beide Aussagen wären technisch wahr; die handlungsleitende // Meldung (falsche Kopie erwischt) muss gewinnen. let result = FileNameParser.parse("SOMOS-v3-DE (1).mp4") XCTAssertEqual(result.outcome, .rejected(.finderDuplicate)) } // MARK: - a) Rechtestes Vorkommen gewinnt func testRightmostFormatOccurrenceWins() { let result = FileNameParser.parse("Kampagne-9x16-Teaser-9x16-v3-DE.mp4") guard case .parsed(let parsed) = result.outcome else { return XCTFail("Erwartete .parsed, bekam \(result.outcome)") } XCTAssertEqual(parsed.projectName, "Kampagne-9x16-Teaser") XCTAssertEqual(parsed.remainder, "v3-DE") XCTAssertEqual(parsed.targetFileName, "Kampagne-9x16-Teaser-4x5-v3-DE.mp4") } func testRightmostAlreadyTargetFormatOccurrenceWins() { let result = FileNameParser.parse("Kampagne-4x5-Teaser-4x5-v3-DE.mp4") XCTAssertEqual(result.outcome, .skipped(.alreadyTargetFormat)) } // MARK: - b) Projekt und Rest müssen existieren func testRejectsWhenNoProjectSegment() { let result = FileNameParser.parse("9x16-v3-DE.mp4") XCTAssertEqual(result.outcome, .rejected(.formatSegmentMissing)) } func testRejectsWhenNoRemainderSegment() { let result = FileNameParser.parse("SOMOS-9x16.mp4") XCTAssertEqual(result.outcome, .rejected(.formatSegmentMissing)) } // MARK: - c) Format-Segment in der Ausgabe immer klein geschrieben func testTargetFormatTokenIsAlwaysLowercase() { let result = FileNameParser.parse("SOMOS-9X16-v3-DE.mp4") guard case .parsed(let parsed) = result.outcome else { return XCTFail("Erwartete .parsed, bekam \(result.outcome)") } XCTAssertEqual(parsed.sourceFormatToken, "9X16") XCTAssertTrue(parsed.targetFileName.contains("-4x5-")) XCTAssertFalse(parsed.targetFileName.contains("4X16")) XCTAssertEqual(parsed.targetFileName, "SOMOS-4x5-v3-DE.mp4") } }