EcritureWavTest.kt 128 lignes · 4943 octets
package fr.ebii.card2vcf.audio

import java.io.File
import java.nio.ByteBuffer
import java.nio.ByteOrder
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith

class EcritureWavTest {

    @Test
    fun enTeteRiffCorrect() {
        val fichier = File.createTempFile("test_wav", ".wav")
        try {
            val ecriture = EcritureWav(fichier, 16_000)
            // 160 échantillons = 10 ms à 16 kHz
            val echantillons = ShortArray(160) { (it % 500).toShort() }
            ecriture.ecrireEchantillons(echantillons, echantillons.size)
            ecriture.fermer()

            val octets = fichier.readBytes()
            val buf = ByteBuffer.wrap(octets).order(ByteOrder.LITTLE_ENDIAN)

            // Marqueur RIFF
            assertEquals('R', buf.get().toInt().toChar())
            assertEquals('I', buf.get().toInt().toChar())
            assertEquals('F', buf.get().toInt().toChar())
            assertEquals('F', buf.get().toInt().toChar())

            // Taille RIFF = taille fichier - 8
            val tailleRiff = buf.int
            assertEquals(octets.size - 8, tailleRiff)

            // WAVE
            assertEquals('W', buf.get().toInt().toChar())
            assertEquals('A', buf.get().toInt().toChar())
            assertEquals('V', buf.get().toInt().toChar())
            assertEquals('E', buf.get().toInt().toChar())

            // Chunk fmt
            assertEquals('f', buf.get().toInt().toChar())
            assertEquals('m', buf.get().toInt().toChar())
            assertEquals('t', buf.get().toInt().toChar())
            assertEquals(' ', buf.get().toInt().toChar())
            assertEquals(16, buf.int)           // taille chunk fmt = 16
            assertEquals(1, buf.short.toInt())  // format PCM = 1
            assertEquals(1, buf.short.toInt())  // mono = 1 canal
            assertEquals(16_000, buf.int)       // fréquence d'échantillonnage
            assertEquals(32_000, buf.int)       // byte rate = 16000 * 1 * 16/8
            assertEquals(2, buf.short.toInt())  // block align = 1 * 16/8
            assertEquals(16, buf.short.toInt()) // bits par échantillon

            // Chunk data
            assertEquals('d', buf.get().toInt().toChar())
            assertEquals('a', buf.get().toInt().toChar())
            assertEquals('t', buf.get().toInt().toChar())
            assertEquals('a', buf.get().toInt().toChar())

            val tailleData = buf.int
            assertEquals(echantillons.size * 2, tailleData)
            assertEquals(octets.size - 44, tailleData)
        } finally {
            fichier.delete()
        }
    }

    @Test
    fun octetsDataRetournes() {
        val fichier = File.createTempFile("test_data", ".wav")
        try {
            val ecriture = EcritureWav(fichier, 16_000)
            // 1 seconde = 16 000 échantillons → 32 000 octets
            val echantillons = ShortArray(16_000)
            ecriture.ecrireEchantillons(echantillons, echantillons.size)
            val octetsEcrits = ecriture.fermer()
            assertEquals(32_000L, octetsEcrits)
        } finally {
            fichier.delete()
        }
    }

    @Test
    fun fichiertailleCoherente() {
        val fichier = File.createTempFile("test_taille", ".wav")
        try {
            val ecriture = EcritureWav(fichier, 16_000)
            val echantillons = ShortArray(800) // 50 ms
            ecriture.ecrireEchantillons(echantillons, echantillons.size)
            ecriture.fermer()
            // 44 octets d'en-tête + 800 * 2 = 1644 octets
            assertEquals(44 + 800 * 2, fichier.length().toInt())
        } finally {
            fichier.delete()
        }
    }

    @Test
    fun fermerLanceExceptionSiTropGrand() {
        val fichier = File.createTempFile("test_check_taille", ".wav")
        try {
            val ecriture = EcritureWav(fichier, 16_000)
            // Injecte une taille trop grande via réflexion (écrire 2 Go en test est impraticable)
            val champ = EcritureWav::class.java.getDeclaredField("octetsData")
            champ.isAccessible = true
            champ.setLong(ecriture, Int.MAX_VALUE.toLong() + 1L)
            assertFailsWith<IllegalStateException> { ecriture.fermer() }
        } finally {
            fichier.delete()
        }
    }

    @Test
    fun ecritureEnPlusieursAppels() {
        val fichier = File.createTempFile("test_multi", ".wav")
        try {
            val ecriture = EcritureWav(fichier, 16_000)
            ecriture.ecrireEchantillons(ShortArray(100), 100)
            ecriture.ecrireEchantillons(ShortArray(200), 200)
            ecriture.ecrireEchantillons(ShortArray(50), 50)
            val octetsEcrits = ecriture.fermer()
            assertEquals((100 + 200 + 50) * 2L, octetsEcrits)
            assertEquals(44 + (100 + 200 + 50) * 2, fichier.length().toInt())
        } finally {
            fichier.delete()
        }
    }
}