using MaBibli.Client.Scan; using ZXing.Common; using ZXing.OneD; namespace MaBibli.Tests; /// /// Tests du décodage pur (aucune caméra, aucun navigateur) : on encode un EAN-13 avec /// ZXing, on le convertit en buffer RGBA comme le ferait getImageData, et on /// vérifie le trajet aller-retour. Aucune image externe n'est nécessaire. /// public class IsbnScannerTests { // Les ISBN de vérification du projet (voir CLAUDE.md). [Theory] [InlineData("9782070612758")] // Le Petit Prince [InlineData("9782253004226")] // Germinal [InlineData("9782080704092")] // Le Horla [InlineData("9780262033848")] // Introduction to Algorithms public void Decode_un_EAN13_genere(string isbn) { var (rgba, largeur, hauteur) = ImageEan13(isbn); Assert.Equal(isbn, IsbnScanner.TryDecode(rgba, largeur, hauteur)); } [Fact] public void Decode_aussi_un_EAN8() { // Pas un ISBN, mais le format est dans les hints : le décodeur doit le lire, // c'est la couche appelante qui écarte les codes non-ISBN. var matrice = new EAN8Writer().encode("96385074", ZXing.BarcodeFormat.EAN_8, 260, 160); var (rgba, largeur, hauteur) = VersRgba(matrice); Assert.Equal("96385074", IsbnScanner.TryDecode(rgba, largeur, hauteur)); } [Fact] public void Renvoie_null_sur_une_frame_sans_code_barres() { // Cas très majoritaire en usage réel : la caméra filme autre chose. // ZXing doit rendre null, jamais lever d'exception. const int largeur = 640, hauteur = 480; var rgba = new byte[largeur * hauteur * 4]; var alea = new Random(1234); alea.NextBytes(rgba); Assert.Null(IsbnScanner.TryDecode(rgba, largeur, hauteur)); } [Fact] public void Renvoie_null_sur_une_image_uniforme() { var rgba = new byte[320 * 200 * 4]; Array.Fill(rgba, (byte)255); Assert.Null(IsbnScanner.TryDecode(rgba, 320, 200)); } [Theory] [InlineData(0, 100)] [InlineData(100, 0)] [InlineData(-5, 100)] public void Renvoie_null_sur_des_dimensions_absurdes(int largeur, int hauteur) => Assert.Null(IsbnScanner.TryDecode(new byte[4000], largeur, hauteur)); [Fact] public void Renvoie_null_si_le_buffer_est_trop_court() { // Une frame tronquée ne doit pas faire tomber la boucle de scan. Assert.Null(IsbnScanner.TryDecode(new byte[100], 640, 480)); } private static (byte[] Rgba, int Largeur, int Hauteur) ImageEan13(string isbn) => VersRgba(new EAN13Writer().encode(isbn, ZXing.BarcodeFormat.EAN_13, 380, 160)); /// /// Convertit une BitMatrix en buffer RGBA, exactement la forme que le canvas /// du navigateur fournit à C# (4 octets par pixel, opaque). /// private static (byte[] Rgba, int Largeur, int Hauteur) VersRgba(BitMatrix matrice) { var largeur = matrice.Width; var hauteur = matrice.Height; var rgba = new byte[largeur * hauteur * 4]; for (var y = 0; y < hauteur; y++) { for (var x = 0; x < largeur; x++) { var valeur = matrice[x, y] ? (byte)0 : (byte)255; var i = ((y * largeur) + x) * 4; rgba[i] = valeur; rgba[i + 1] = valeur; rgba[i + 2] = valeur; rgba[i + 3] = 255; } } return (rgba, largeur, hauteur); } }