using Sunfish.Qr;
using Xunit;
using ZXing;
using ZXing.Common;
using ZXing.QrCode;
namespace Sunfish.Tests;
/// <summary>El QR propio se comprueba leyendolo con un decodificador independiente (ZXing, solo en pruebas).</summary>
public class QrTests
{
private static string? Decode(QrCode qr, int scale = 4, int quiet = 4)
{
int size = (qr.Size + quiet * 2) * scale;
var pixels = new byte[size * size];
Array.Fill(pixels, (byte)255);
for (int y = 0; y < qr.Size; y++)
for (int x = 0; x < qr.Size; x++)
if (qr[x, y])
for (int dy = 0; dy < scale; dy++)
for (int dx = 0; dx < scale; dx++)
pixels[((y + quiet) * scale + dy) * size + (x + quiet) * scale + dx] = 0;
var source = new RGBLuminanceSource(pixels, size, size, RGBLuminanceSource.BitmapFormat.Gray8);
var hints = new Dictionary<DecodeHintType, object> { [DecodeHintType.PURE_BARCODE] = true, [DecodeHintType.CHARACTER_SET] = "UTF-8" };
return new QRCodeReader().decode(new BinaryBitmap(new HybridBinarizer(source)), hints)?.Text;
}
[Theory]
[InlineData("http://192.168.1.20:8080/")]
[InlineData("http://[fe80::1234:5678:9abc:def0]:8080/fotos/")]
[InlineData("ftp://192.168.1.20:2121/pub/")]
[InlineData("Sunfish ñ é ü")]
public void ShortTextsDecode(string text)
{
var qr = QrCode.Encode(text);
Assert.Equal(text, Decode(qr));
}
[Theory]
[InlineData(50)]
[InlineData(150)] // version 7+ (informacion de version)
[InlineData(400)] // varios bloques de longitudes distintas
[InlineData(1200)]
public void LongerTextsDecode(int length)
{
string text = string.Concat(Enumerable.Range(0, length).Select(i => (char)('a' + i * 7 % 26)));
var qr = QrCode.Encode(text);
Assert.Equal(text, Decode(qr));
}
[Fact]
public void AllEccLevelsAndMasksDecode()
{
var masks = new HashSet<int>();
foreach (var ecc in Enum.GetValues<QrEcc>())
for (int i = 0; i < 40; i++)
{
string text = "http://10.0.0." + i + ":8080/" + new string('x', i);
var qr = QrCode.Encode(text, ecc);
Assert.True(qr.Ecc >= ecc);
masks.Add(qr.Mask);
Assert.Equal(text, Decode(qr));
}
Assert.True(masks.Count >= 4); // la eleccion de mascara no es siempre la misma
}
[Fact]
public void UsesTheSmallestVersionAndRaisesEcc()
{
var qr = QrCode.Encode("http://192.168.1.20:8080/");
Assert.Equal(2, qr.Version);
Assert.Equal(25, qr.Size);
Assert.True(qr.Ecc >= QrEcc.Medium);
}
[Fact]
public void TooLongThrows() =>
Assert.Throws<ArgumentException>(() => QrCode.Encode(new string('a', 3000)));
}