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);
}
}