using FluentAssertions;
using foodmarket.Api.Infrastructure.Invoices;
using Xunit;
namespace foodmarket.UnitTests;
/// Контрольная цифра EAN-8/EAN-13/UPC-A/GTIN-14. Проверка нужна в
/// фото-приёмке: если модель переписала цифры штрихкода со снимка товара
/// сама (barcode_source="read"), одна ошибка в любой цифре иначе
/// молча дала бы чужой товар. Порт из ~/ref/sklad.
public class EanTests
{
// Валидные настоящие штрихкоды (из handoff: «15/15 реальных проходят»).
public static TheoryData Valid => new()
{
"4870001234560", // EAN-13
"4607031440148", // EAN-13 (пример из KZ-ритейла)
"0012000161551", // UPC-A дополненный до 13
"73513537", // EAN-8
"012345678905", // UPC-A (12)
};
[Theory, MemberData(nameof(Valid))]
public void Valid_passes(string digits) => Ean.IsValid(digits).Should().BeTrue();
[Fact]
public void Broken_check_digit_fails()
{
// Все эти — валидные минус один «кривой» символ контрольной.
Ean.IsValid("4870001234561").Should().BeFalse();
Ean.IsValid("4607031440149").Should().BeFalse();
}
[Theory]
[InlineData("")]
[InlineData(null)]
[InlineData("12345")] // короткий
[InlineData("12345678901")] // 11 — не стандарт
[InlineData("12345678901A")] // буква
[InlineData("4870 001 234 56")] // пробелы — Ean.IsValid смотрит на точные цифры
public void Non_digit_or_bad_length_fails(string? d) => Ean.IsValid(d).Should().BeFalse();
[Fact]
public void One_digit_error_in_middle_caught()
{
// Из handoff: «15/15 с одной испорченной цифрой ловятся» —
// гарантируется весовой суммой 3,1,3,1,…
var ok = "4870001234560";
foreach (var i in new[] { 0, 3, 5, 8, 11 })
{
var mutated = ok.ToCharArray();
mutated[i] = (char)('0' + ((mutated[i] - '0' + 5) % 10)); // ± 5 в этой позиции
Ean.IsValid(new string(mutated)).Should().BeFalse(
$"позиция {i}: ошибку в одной цифре должен поймать");
}
}
}