TesseractModelesAbsentsTest.kt 87 lignes · 2956 octets
package fr.ebii.card2vcf.ocr

import android.content.Context
import androidx.test.core.app.ApplicationProvider
import fr.ebii.card2vcf.modeles.PreferencesModeles
import org.junit.Before
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import java.io.File
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertTrue

/**
 * Comportement quand aucun modèle n'est installé — le cas nominal d'une installation
 * F-Droid neuve. Réservé à la saveur `fdroid` : la saveur `direct` embarque les
 * traineddata dans ses assets, l'absence y est donc impossible à reproduire.
 */
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [31])
class TesseractModelesAbsentsTest {

    private lateinit var context: Context
    private lateinit var prefs: PreferencesModeles

    @Before
    fun setUp() {
        context = ApplicationProvider.getApplicationContext()
        context.filesDir.deleteRecursively()
        prefs = PreferencesModeles(context)
    }

    private fun moteur() = TesseractOcrEngine(context, prefs)

    private fun poserModele(langue: String) {
        val dossier = File(context.filesDir, "tesseract/tessdata").apply { mkdirs() }
        File(dossier, "$langue.traineddata").writeBytes(ByteArray(20_000))
    }

    @Test
    fun `la saveur fdroid n'embarque aucun traineddata`() {
        val assets = context.assets.list("tesseract/tessdata").orEmpty()
        assertTrue(
            assets.none { it.endsWith(".traineddata") },
            "assets inattendus dans la saveur fdroid : ${assets.joinToString()}",
        )
    }

    @Test
    fun `sans aucun modele l'exception nomme les langues attendues`() {
        val erreur = assertFailsWith<ModelesManquantsException> { moteur().languesActives() }

        assertEquals(listOf("fra", "eng"), erreur.langues)
    }

    @Test
    fun `l'exception des modeles manquants reste une OcrException`() {
        // ScanCarteViewModel attrape OcrException : la sous-classe doit y entrer.
        val erreur = assertFailsWith<ModelesManquantsException> { moteur().languesActives() }
        assertTrue(erreur is OcrException)
    }

    @Test
    fun `seules les langues presentes sont chargees`() {
        poserModele("fra")

        assertEquals(listOf("fra"), moteur().languesActives())
    }

    @Test
    fun `une langue selectionnee mais absente n'empeche pas les autres`() {
        poserModele("fra")
        prefs.setLanguesSelectionnees(setOf("fra", "pol"))

        assertEquals(listOf("fra"), moteur().languesActives())
    }

    @Test
    fun `un fichier tronque ne compte pas comme un modele`() {
        val dossier = File(context.filesDir, "tesseract/tessdata").apply { mkdirs() }
        File(dossier, "fra.traineddata").writeBytes(ByteArray(12))

        assertFailsWith<ModelesManquantsException> { moteur().languesActives() }
    }
}