EnregistrementNoteViewModelTest.swift 103 lignes · 4468 octets
import XCTest
@testable import Card2vcf

/// Tests TDD du ViewModel d'enregistrement de note vocale.
///
/// PREUVES DE ROUGEUR :
///
/// Test 1 : testSujetParDefaut
/// En remplaçant le corps de `sujetParDefaut` par `return ""`, le test échoue avec :
///   XCTAssertTrue failed — "Notes du" not found in ""
///
/// Test 2 : testMessageConfirmationModeServeurEnvoye
/// En remplaçant le corps de `messageConfirmation` par `return ""`, le test échoue avec :
///   XCTAssertTrue failed — "serveur" not found in ""
@MainActor
final class EnregistrementNoteViewModelTest: XCTestCase {

    // MARK: - sujetParDefaut (PREUVE DE ROUGEUR #1)

    func testSujetParDefaut() {
        // Date fixe : 17 septembre 2026 à 14h30
        var components = DateComponents()
        components.year = 2026
        components.month = 9
        components.day = 17
        components.hour = 14
        components.minute = 30
        let date = Calendar(identifier: .gregorian).date(from: components)!

        let sujet = EnregistrementNoteViewModel.sujetParDefaut(maintenant: date)

        // Rouge sans l'implémentation : XCTAssertTrue failed — "Notes du" not found in ""
        XCTAssertTrue(sujet.hasPrefix("Notes du"),
                      "Le sujet doit commencer par 'Notes du', obtenu : \(sujet)")
        XCTAssertTrue(sujet.contains("17/09/2026"),
                      "Le sujet doit contenir la date jj/MM/yyyy, obtenu : \(sujet)")
        XCTAssertTrue(sujet.contains("14:30"),
                      "Le sujet doit contenir l'heure HH:mm, obtenu : \(sujet)")
    }

    func testSujetParDefautFormatPadding() {
        // Vérifie que jour, mois, heure et minute sont sur 2 chiffres (05/01/2026 09:03)
        var components = DateComponents()
        components.year = 2026
        components.month = 1
        components.day = 5
        components.hour = 9
        components.minute = 3
        let date = Calendar(identifier: .gregorian).date(from: components)!

        let sujet = EnregistrementNoteViewModel.sujetParDefaut(maintenant: date)
        XCTAssertTrue(sujet.contains("05/01/2026"), "Jour et mois sur 2 chiffres, obtenu : \(sujet)")
        XCTAssertTrue(sujet.contains("09:03"), "Heure et minute sur 2 chiffres, obtenu : \(sujet)")
    }

    // MARK: - messageConfirmation (PREUVE DE ROUGEUR #2)

    func testMessageConfirmationModeServeurEnvoye() {
        let msg = EnregistrementNoteViewModel.messageConfirmation(mode: .serveur, envoye: true)

        // Rouge sans l'implémentation : XCTAssertTrue failed — "serveur" not found in ""
        XCTAssertTrue(msg.lowercased().contains("serveur"),
                      "Le message doit mentionner le serveur, obtenu : \(msg)")
        let indicateurEnCours = msg.lowercased().contains("transcription")
            || msg.lowercased().contains("cours")
        XCTAssertTrue(indicateurEnCours,
                      "Le message doit indiquer que la transcription est en cours, obtenu : \(msg)")
    }

    func testMessageConfirmationModeServeurNonEnvoye() {
        let msg = EnregistrementNoteViewModel.messageConfirmation(mode: .serveur, envoye: false)
        XCTAssertTrue(msg.lowercased().contains("synchronisation"),
                      "Le message doit mentionner la synchronisation, obtenu : \(msg)")
    }

    func testMessageConfirmationModeAppareil() {
        let msg = EnregistrementNoteViewModel.messageConfirmation(mode: .appareil, envoye: false)
        XCTAssertFalse(msg.isEmpty, "Le message ne doit pas être vide")
        XCTAssertFalse(msg.lowercased().contains("serveur"),
                       "Mode appareil : pas de mention du serveur, obtenu : \(msg)")
    }

    func testMessageConfirmationModeAppareilIgnoreEnvoye() {
        // En mode appareil, envoye=true ou false → même message
        let m1 = EnregistrementNoteViewModel.messageConfirmation(mode: .appareil, envoye: true)
        let m2 = EnregistrementNoteViewModel.messageConfirmation(mode: .appareil, envoye: false)
        XCTAssertEqual(m1, m2, "Mode appareil : le flag envoye ne change pas le message")
    }

    // MARK: - dureeFormatee

    func testDureeFormatee() async {
        let vm = makeViewModel()
        // La durée initiale doit être 00:00
        XCTAssertEqual("00:00", vm.dureeFormatee)
    }

    // MARK: - helpers

    private func makeViewModel() -> EnregistrementNoteViewModel {
        EnregistrementNoteViewModel(sauvegarder: { _, _, _, _ in false })
    }
}