224 lines
8.7 KiB
C#
224 lines
8.7 KiB
C#
using Omika.Diagnostics.Referential;
|
|
using Omika.Diagnostics.Security;
|
|
using Omika.Diagnostics.Tests.Fakes;
|
|
using Omika.Diagnostics.Web.Pages;
|
|
|
|
namespace Omika.Diagnostics.Tests;
|
|
|
|
/// <summary>
|
|
/// T24-A Partie B — PageModels du référentiel (/Referentiel + /Referentiel/Admin) et
|
|
/// libellés des dropdowns Diagnostics. Les handlers n'accèdent pas à HttpContext (aucun
|
|
/// harnais Web requis) ; l'autorisation est portée par la convention Program.cs.
|
|
/// </summary>
|
|
public class DiagnosticReferencePageModelTests
|
|
{
|
|
private static DiagnosticReferenceRecord Ref(
|
|
long id,
|
|
string type,
|
|
string code,
|
|
string label,
|
|
bool enabled = true) => new()
|
|
{
|
|
Id = id,
|
|
ReferenceType = type,
|
|
Code = code,
|
|
Label = label,
|
|
Enabled = enabled,
|
|
CreatedAtUtc = DateTimeOffset.UtcNow,
|
|
UpdatedAtUtc = DateTimeOffset.UtcNow
|
|
};
|
|
|
|
private static ReferentielAdminModel NewAdminModel(
|
|
FakeDiagnosticReferenceRepository references) =>
|
|
new(new FakeDiagnosticEventRepository(), references);
|
|
|
|
// ------------------------------------------- création admin ----
|
|
[Fact]
|
|
public async Task AdminCreate_StoresNormalizedEntry()
|
|
{
|
|
var references = new FakeDiagnosticReferenceRepository();
|
|
var model = NewAdminModel(references);
|
|
model.NewType = DiagnosticReferenceTypes.ScreenCode;
|
|
model.NewCode = " facture_detail ";
|
|
model.NewLabel = " Détail de facture ";
|
|
model.NewDescription = "Fiche détaillée d'une facture.";
|
|
|
|
await model.OnPostCreateAsync();
|
|
|
|
DiagnosticReferenceRecord? created = await references.GetByTypeAndCodeAsync(
|
|
DiagnosticReferenceTypes.ScreenCode, "FACTURE_DETAIL");
|
|
Assert.NotNull(created);
|
|
Assert.Equal("FACTURE_DETAIL", created!.Code);
|
|
Assert.Equal("Détail de facture", created.Label);
|
|
Assert.Contains("FACTURE_DETAIL", model.SuccessMessage);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task AdminCreate_Duplicate_ShowsError()
|
|
{
|
|
var references = new FakeDiagnosticReferenceRepository();
|
|
references.Seed(Ref(1, DiagnosticReferenceTypes.ScreenCode, "AGENDA", "Agenda"));
|
|
var model = NewAdminModel(references);
|
|
model.NewType = DiagnosticReferenceTypes.ScreenCode;
|
|
model.NewCode = "agenda";
|
|
model.NewLabel = "Agenda bis";
|
|
|
|
await model.OnPostCreateAsync();
|
|
|
|
Assert.Contains("existe déjà", model.ErrorMessage);
|
|
Assert.Single(await references.ListAsync());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task AdminCreate_EmptyLabel_ShowsError()
|
|
{
|
|
var references = new FakeDiagnosticReferenceRepository();
|
|
var model = NewAdminModel(references);
|
|
model.NewType = DiagnosticReferenceTypes.ScreenCode;
|
|
model.NewCode = "X";
|
|
model.NewLabel = " ";
|
|
|
|
await model.OnPostCreateAsync();
|
|
|
|
Assert.Contains("libellé", model.ErrorMessage, StringComparison.OrdinalIgnoreCase);
|
|
Assert.Empty(await references.ListAsync());
|
|
}
|
|
|
|
// ------------------------------------------- modification / archivage ----
|
|
[Fact]
|
|
public async Task AdminUpdate_ChangesLabelDescriptionAndState()
|
|
{
|
|
var references = new FakeDiagnosticReferenceRepository();
|
|
references.Seed(Ref(1, DiagnosticReferenceTypes.ScreenCode, "AGENDA", "Agenda"));
|
|
var model = NewAdminModel(references);
|
|
|
|
await model.OnPostUpdateAsync(1, "Nouvel agenda", "Description", enabled: false, sortOrder: 5);
|
|
|
|
DiagnosticReferenceRecord? record = await references.GetByIdAsync(1);
|
|
Assert.Equal("Nouvel agenda", record!.Label);
|
|
Assert.Equal("Description", record.Description);
|
|
Assert.False(record.Enabled);
|
|
Assert.Equal(5, record.SortOrder);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task AdminArchive_DisablesWithoutDelete()
|
|
{
|
|
var references = new FakeDiagnosticReferenceRepository();
|
|
references.Seed(Ref(1, DiagnosticReferenceTypes.ScreenCode, "AGENDA", "Agenda"));
|
|
var model = NewAdminModel(references);
|
|
|
|
await model.OnPostArchiveAsync(1);
|
|
|
|
Assert.False((await references.GetByIdAsync(1))!.Enabled);
|
|
Assert.Single(await references.ListAsync()); // jamais de DELETE.
|
|
Assert.Contains("archivée", model.SuccessMessage);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task AdminEnable_ReactivatesArchived()
|
|
{
|
|
var references = new FakeDiagnosticReferenceRepository();
|
|
references.Seed(Ref(1, DiagnosticReferenceTypes.ScreenCode, "AGENDA", "Agenda", enabled: false));
|
|
var model = NewAdminModel(references);
|
|
|
|
await model.OnPostEnableAsync(1);
|
|
|
|
Assert.True((await references.GetByIdAsync(1))!.Enabled);
|
|
}
|
|
|
|
// ------------------------------------------- ajout rapide non référencé ----
|
|
[Fact]
|
|
public async Task AdminAddUnreferenced_CreatesReference()
|
|
{
|
|
var references = new FakeDiagnosticReferenceRepository();
|
|
DateTimeOffset last = DateTimeOffset.UtcNow.AddDays(-1);
|
|
references.SeedObserved(DiagnosticReferenceTypes.ScreenCode, "FACTURE_DETAIL", 128, last);
|
|
var model = NewAdminModel(references);
|
|
|
|
await model.OnGetAsync();
|
|
DiagnosticUnreferencedCode unreferenced = Assert.Single(model.Unreferenced);
|
|
Assert.Equal("FACTURE_DETAIL", unreferenced.Code);
|
|
|
|
await model.OnPostAddUnreferencedAsync(
|
|
DiagnosticReferenceTypes.ScreenCode, "FACTURE_DETAIL", "Détail de facture", "Fiche détaillée.");
|
|
|
|
Assert.NotNull(await references.GetByTypeAndCodeAsync(DiagnosticReferenceTypes.ScreenCode, "FACTURE_DETAIL"));
|
|
// Après ajout, le code n'est plus « non référencé ».
|
|
await model.OnGetAsync();
|
|
Assert.Empty(model.Unreferenced);
|
|
}
|
|
|
|
// ------------------------------------------- consultation /Referentiel ----
|
|
[Fact]
|
|
public async Task ReferentielModel_LoadsScreenAndFeatureReferences()
|
|
{
|
|
var references = new FakeDiagnosticReferenceRepository();
|
|
references.Seed(
|
|
Ref(1, DiagnosticReferenceTypes.ScreenCode, "AGENDA", "Agenda"),
|
|
Ref(2, DiagnosticReferenceTypes.FeatureCode, "EMAIL_SEND", "Envoi de courriel"));
|
|
|
|
var model = new ReferentielModel(new FakeDiagnosticEventRepository(), references);
|
|
await model.OnGetAsync();
|
|
|
|
Assert.True(model.PostgreSqlAvailable);
|
|
DiagnosticReferenceRecord screen = Assert.Single(model.ScreenReferences);
|
|
Assert.Equal("AGENDA", screen.Code);
|
|
DiagnosticReferenceRecord feature = Assert.Single(model.FeatureReferences);
|
|
Assert.Equal("EMAIL_SEND", feature.Code);
|
|
}
|
|
|
|
// ------------------------------------------- dropdowns Diagnostics (§33/§37) ----
|
|
[Fact]
|
|
public async Task DiagnosticsDropdown_ReferencedCode_UsesDbLabel()
|
|
{
|
|
var references = new FakeDiagnosticReferenceRepository();
|
|
references.Seed(Ref(1, DiagnosticReferenceTypes.ScreenCode, "FACTURE_DETAIL", "Détail de facture"));
|
|
var model = new DiagnosticsModel(new FakeDiagnosticEventRepository(), references);
|
|
|
|
await model.OnGetAsync();
|
|
|
|
// Référence DB → « Libellé (CODE) ».
|
|
Assert.Equal("Détail de facture (FACTURE_DETAIL)", model.ScreenCodeOptionLabel("FACTURE_DETAIL"));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task DiagnosticsDropdown_UnreferencedCode_ShowsNotReferenced()
|
|
{
|
|
var references = new FakeDiagnosticReferenceRepository();
|
|
var model = new DiagnosticsModel(new FakeDiagnosticEventRepository(), references);
|
|
|
|
await model.OnGetAsync();
|
|
|
|
// Aucune référence → « CODE (non référencé) ». La valeur envoyée reste le CODE.
|
|
Assert.Equal("FACTURE_DETAIL (non référencé)", model.ScreenCodeOptionLabel("FACTURE_DETAIL"));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task DiagnosticsDropdown_CatalogCodeWithoutDbEntry_FallsBackToCatalog()
|
|
{
|
|
var references = new FakeDiagnosticReferenceRepository();
|
|
var model = new DiagnosticsModel(new FakeDiagnosticEventRepository(), references);
|
|
|
|
await model.OnGetAsync();
|
|
|
|
// Code du catalogue applicatif mais sans entrée DB → repli catalogue (résilience).
|
|
Assert.Equal("AGENDA — Agenda", model.ScreenCodeOptionLabel("AGENDA"));
|
|
}
|
|
|
|
// ------------------------------------------- rôles (§40/§46) ----
|
|
[Fact]
|
|
public void Roles_SupportCanConsultButNotAdmin()
|
|
{
|
|
Assert.True(DiagnosticAuthorization.IsSupport([DiagnosticRoles.Support]));
|
|
Assert.False(DiagnosticAuthorization.IsAdmin([DiagnosticRoles.Support]));
|
|
}
|
|
|
|
[Fact]
|
|
public void Roles_AdminCanConsultAndAdmin()
|
|
{
|
|
Assert.True(DiagnosticAuthorization.IsSupport([DiagnosticRoles.Admin]));
|
|
Assert.True(DiagnosticAuthorization.IsAdmin([DiagnosticRoles.Admin]));
|
|
}
|
|
}
|