Files
Geradores/UnitTest/GeneratorRoundTripTests.cs
Marco Santos d7ea8a9b9e Reescrita dos geradores: biblioteca IGenerator, minimal API e novo frontend
- GeradoresService: cada tipo passa a ser um IGenerator (NIF, NIPC, NISS, CC,
  passaporte, IBAN, NIB, cartões, referência MB, pessoa, telefone, código postal,
  email, matrícula, EAN, UUID) registado em GeneratorRegistry; remove DAL/EF
- GeradoresWS: minimal APIs em /api/v1 com OpenAPI + Scalar e health check
- UnitTest: testes de ida e volta, valores conhecidos, detecção e API
- geradoresfe: UI construída a partir dos metadados da API, validador livre,
  exportação CSV/JSON/TXT, nginx com API_UPSTREAM configurável
- Docker, docker-compose e Jenkinsfile actualizados

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 23:51:39 +01:00

108 lines
3.8 KiB
C#

using GeradoresService;
using GeradoresService.Core;
namespace UnitTest;
/// <summary>
/// Para cada gerador e cada valor de cada opção, os valores gerados têm de passar no próprio validador.
/// </summary>
public class GeneratorRoundTripTests
{
private static readonly GeneratorRegistry Registry = new();
public static TheoryData<string, string, string> AllOptionValues()
{
var data = new TheoryData<string, string, string>();
foreach (var g in Registry.All)
{
if (g.Options.Count == 0)
data.Add(g.Id, "", "");
foreach (var o in g.Options)
foreach (var c in o.Choices)
data.Add(g.Id, o.Key, c.Value);
}
return data;
}
[Theory]
[MemberData(nameof(AllOptionValues))]
public void Generated_values_are_valid(string generatorId, string optionKey, string optionValue)
{
var generator = Registry.Find(generatorId)!;
var options = new Dictionary<string, string?>();
if (optionKey != "")
options[optionKey] = optionValue;
var items = Registry.Generate(generator, 300, options, seed: 42);
Assert.All(items, item => Assert.False(string.IsNullOrWhiteSpace(item.Value)));
if (!generator.CanValidate)
return;
foreach (var item in items)
{
var result = generator.Validate(item.Value);
Assert.True(result.IsValid, $"{generatorId} gerou '{item.Value}' que não valida: {result.Message}");
}
}
[Fact]
public void Pessoa_fields_are_all_valid()
{
var pessoa = Registry.Find("pessoa")!;
foreach (var item in Registry.Generate(pessoa, 200, new Dictionary<string, string?>(), seed: 7))
{
var f = item.Fields!;
Assert.True(Registry.Find("nif")!.Validate(f["NIF"]).IsValid);
Assert.True(Registry.Find("niss")!.Validate(f["NISS"]).IsValid);
Assert.True(Registry.Find("cc")!.Validate(f["Cartão de Cidadão"]).IsValid);
Assert.True(Registry.Find("iban")!.Validate(f["IBAN"]).IsValid);
Assert.True(Registry.Find("telefone")!.Validate(f["Telemóvel"]).IsValid);
Assert.True(Registry.Find("email")!.Validate(f["Email"]).IsValid);
Assert.True(Registry.Find("codigo-postal")!.Validate(f["Código postal"]).IsValid);
var age = DateTime.UtcNow.Year - DateOnly.Parse(f["Data de nascimento"]).Year;
Assert.InRange(age, 18, 81);
}
}
[Fact]
public void Same_seed_gives_same_values()
{
var nif = Registry.Find("nif")!;
var a = Registry.Generate(nif, 20, new Dictionary<string, string?>(), seed: 123);
var b = Registry.Generate(nif, 20, new Dictionary<string, string?>(), seed: 123);
Assert.Equal(a.Select(x => x.Value), b.Select(x => x.Value));
}
[Fact]
public void Generated_values_are_not_all_equal()
{
var items = Registry.Generate(Registry.Find("nif")!, 50, new Dictionary<string, string?>());
Assert.True(items.Select(i => i.Value).Distinct().Count() > 40);
}
[Fact]
public void Invalid_option_value_throws()
{
var nif = Registry.Find("nif")!;
Assert.Throws<ArgumentException>(() =>
Registry.Generate(nif, 1, new Dictionary<string, string?> { ["tipo"] = "4" }));
}
[Theory]
[InlineData(0)]
[InlineData(GeneratorRegistry.MaxBatch + 1)]
public void Count_out_of_range_throws(int count)
{
Assert.Throws<ArgumentOutOfRangeException>(() =>
Registry.Generate(Registry.Find("nif")!, count, new Dictionary<string, string?>()));
}
[Fact]
public void Ids_are_unique()
{
Assert.Equal(Registry.All.Count, Registry.All.Select(g => g.Id).Distinct().Count());
}
}