Premiere commit - Omika
This commit is contained in:
@@ -0,0 +1,279 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Omika.Diagnostics.Models;
|
||||
using Omika.Diagnostics.Queries;
|
||||
using Omika.Diagnostics.Tests.Fakes;
|
||||
using Omika.Diagnostics.Web.Pages;
|
||||
|
||||
namespace Omika.Diagnostics.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// T17-D — Contexte Client / Licence / Appareil / Application : formatage d'affichage
|
||||
/// (NULL historique → « — »), détail diagnostic complet, filtres Licence/Appareil,
|
||||
/// pagination, et non-régression sécurité (aucun identifiant brut exposé).
|
||||
/// </summary>
|
||||
public class DiagnosticDeviceContextUiTests
|
||||
{
|
||||
// ------------------------------------------------ formatage -------------------------
|
||||
[Fact]
|
||||
public void Value_NullOrEmpty_RendersEmDash()
|
||||
{
|
||||
Assert.Equal("—", UiDeviceContext.Value(null));
|
||||
Assert.Equal("—", UiDeviceContext.Value(""));
|
||||
Assert.Equal("—", UiDeviceContext.Value(" "));
|
||||
Assert.Equal("Android", UiDeviceContext.Value(" Android "));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(1080, 2400, "1080 × 2400 px")]
|
||||
[InlineData(null, 2400, "—")]
|
||||
[InlineData(1080, null, "—")]
|
||||
[InlineData(0, 2400, "—")]
|
||||
[InlineData(1080, 0, "—")]
|
||||
public void Resolution_RequiresBothDimensions(int? w, int? h, string expected)
|
||||
=> Assert.Equal(expected, UiDeviceContext.Resolution(w, h, "px"));
|
||||
|
||||
[Fact]
|
||||
public void Scale_FormatsWithoutFloatingNoise()
|
||||
{
|
||||
Assert.Equal("2.75×", UiDeviceContext.Scale(2.75));
|
||||
Assert.Equal("3×", UiDeviceContext.Scale(3.0));
|
||||
Assert.Equal("—", UiDeviceContext.Scale(null));
|
||||
Assert.Equal("—", UiDeviceContext.Scale(0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DeviceIdentity_CombinesManufacturerAndModel()
|
||||
{
|
||||
Assert.Equal("Xiaomi · 23113RKC6G", UiDeviceContext.DeviceIdentity("Xiaomi", "23113RKC6G"));
|
||||
Assert.Equal("Apple", UiDeviceContext.DeviceIdentity("Apple", null));
|
||||
Assert.Equal("—", UiDeviceContext.DeviceIdentity(null, null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PlatformOs_CombinesOsAndVersion()
|
||||
{
|
||||
Assert.Equal("Android 16", UiDeviceContext.PlatformOs("Android", "16"));
|
||||
Assert.Equal("iOS 18.6", UiDeviceContext.PlatformOs("iOS", "18.6"));
|
||||
Assert.Equal("—", UiDeviceContext.PlatformOs(null, "16"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void VersionBuild_ShowsBuildWhenPresent()
|
||||
{
|
||||
Assert.Equal("1.4.1 (10401)", UiDeviceContext.VersionBuild("1.4.1", "10401"));
|
||||
Assert.Equal("1.4.1", UiDeviceContext.VersionBuild("1.4.1", null));
|
||||
Assert.Equal("—", UiDeviceContext.VersionBuild(null, "10401"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Short_TruncatesAndKeepsFullViaTitle()
|
||||
{
|
||||
Assert.Equal("—", UiDeviceContext.Short(null));
|
||||
Assert.Equal("f71919f4f9974d70…", UiDeviceContext.Short("f71919f4f9974d70967014fbbefabf9d", 16));
|
||||
Assert.Equal("abc", UiDeviceContext.Short("abc", 16)); // court → intact
|
||||
}
|
||||
|
||||
// ------------------------------------------------ détail complet (§41) -------------
|
||||
[Fact]
|
||||
public async Task Detail_LoadsFullDeviceAndLicenseContext()
|
||||
{
|
||||
var repo = new FakeDiagnosticEventRepository();
|
||||
Guid traceId = Guid.NewGuid();
|
||||
Guid operationId = Guid.NewGuid();
|
||||
Guid sessionId = Guid.NewGuid();
|
||||
DiagnosticEventRecord record = DeviceRecord(42, traceId: traceId, operationId: operationId, sessionId: sessionId);
|
||||
await repo.InsertBatchAsync(new[] { record });
|
||||
|
||||
var model = new DiagnosticsDetailModel(repo);
|
||||
IActionResult result = await model.OnGetAsync(42);
|
||||
|
||||
Assert.IsType<Microsoft.AspNetCore.Mvc.RazorPages.PageResult>(result);
|
||||
Assert.NotNull(model.Event);
|
||||
Assert.Equal("CLIENT-042", model.Event!.ClientCode);
|
||||
Assert.Equal("LIC-000842", model.Event.LicenseNumber);
|
||||
Assert.Equal("hash-test", model.Event.DeviceKey);
|
||||
Assert.Equal(1, model.Event.DeviceKeyVersion);
|
||||
Assert.Equal("Android", model.Event.Platform);
|
||||
Assert.Equal("Android", model.Event.OperatingSystem);
|
||||
Assert.Equal("16", model.Event.OperatingSystemVersion);
|
||||
Assert.Equal("Xiaomi", model.Event.DeviceManufacturer);
|
||||
Assert.Equal("23113RKC6G", model.Event.DeviceModel);
|
||||
Assert.Equal("1.4.1", model.Event.AppVersion);
|
||||
Assert.Equal("10401", model.Event.AppBuild);
|
||||
Assert.Equal(1080, model.Event.ScreenWidth);
|
||||
Assert.Equal(2400, model.Event.ScreenHeight);
|
||||
Assert.Equal(393, model.Event.LogicalWidth);
|
||||
Assert.Equal(873, model.Event.LogicalHeight);
|
||||
Assert.Equal(2.75, model.Event.DisplayScale);
|
||||
Assert.Equal(traceId, model.Event.TraceId);
|
||||
Assert.Equal(operationId, model.Event.OperationId);
|
||||
Assert.Equal(sessionId, model.Event.SessionId);
|
||||
}
|
||||
|
||||
// ------------------------------------------------ anciennes données NULL (§42) ------
|
||||
[Fact]
|
||||
public void OldData_WithAllNulls_FormatsWithoutBreaking()
|
||||
{
|
||||
DiagnosticEventRecord legacy = DiagnosticTestData.Event(Guid.NewGuid());
|
||||
legacy.ClientCode = null;
|
||||
legacy.LicenseNumber = null;
|
||||
legacy.DeviceKey = null;
|
||||
legacy.DeviceManufacturer = null;
|
||||
legacy.DeviceModel = null;
|
||||
legacy.OperatingSystem = null;
|
||||
legacy.ScreenWidth = null;
|
||||
legacy.ScreenHeight = null;
|
||||
legacy.LogicalWidth = null;
|
||||
legacy.LogicalHeight = null;
|
||||
legacy.DisplayScale = null;
|
||||
|
||||
Assert.Equal("Non renseigné", UiDeploymentContext.Value(legacy.ClientCode));
|
||||
Assert.Equal("—", UiDeviceContext.Value(legacy.LicenseNumber));
|
||||
Assert.Equal("—", UiDeviceContext.Resolution(legacy.ScreenWidth, legacy.ScreenHeight, "px"));
|
||||
Assert.Equal("—", UiDeviceContext.Resolution(legacy.LogicalWidth, legacy.LogicalHeight));
|
||||
Assert.Equal("—", UiDeviceContext.Scale(legacy.DisplayScale));
|
||||
Assert.Null(UiDeviceContext.CompactDeviceOrNull(legacy));
|
||||
}
|
||||
|
||||
// ------------------------------------------------ filtre licence (§43) -------------
|
||||
[Fact]
|
||||
public async Task LicenseFilter_ReturnsOnlyMatchingEvents()
|
||||
{
|
||||
var repo = new FakeDiagnosticEventRepository();
|
||||
await repo.InsertBatchAsync(new[]
|
||||
{
|
||||
LicenseRecord(1, "LIC-A"),
|
||||
LicenseRecord(2, "LIC-A"),
|
||||
LicenseRecord(3, "LIC-B")
|
||||
});
|
||||
|
||||
var model = new DiagnosticsModel(repo) { LicenseNumber = "LIC-A" };
|
||||
await model.OnGetAsync();
|
||||
|
||||
Assert.Equal(2, model.Items.Count);
|
||||
Assert.All(model.Items, e => Assert.Equal("LIC-A", e.LicenseNumber));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Route_PreservesLicenseAndDeviceFilters()
|
||||
{
|
||||
var model = new DiagnosticsModel(new FakeDiagnosticEventRepository())
|
||||
{
|
||||
LicenseNumber = "LIC-A",
|
||||
DeviceKey = "hash-test"
|
||||
};
|
||||
|
||||
Dictionary<string, string> route = model.Route(2);
|
||||
|
||||
Assert.Equal("2", route["pageNumber"]);
|
||||
Assert.Equal("LIC-A", route["licenseNumber"]);
|
||||
Assert.Equal("hash-test", route["deviceKey"]);
|
||||
}
|
||||
|
||||
// ------------------------------------------------ filtre appareil (§44) ------------
|
||||
[Fact]
|
||||
public async Task DeviceKeyFilter_ReturnsOnlyMatchingDevice()
|
||||
{
|
||||
var repo = new FakeDiagnosticEventRepository();
|
||||
await repo.InsertBatchAsync(new[]
|
||||
{
|
||||
DeviceKeyRecord(1, "hash-test"),
|
||||
DeviceKeyRecord(2, "hash-test"),
|
||||
DeviceKeyRecord(3, "hash-other")
|
||||
});
|
||||
|
||||
var model = new DiagnosticsModel(repo) { DeviceKey = "hash-test" };
|
||||
await model.OnGetAsync();
|
||||
|
||||
Assert.Equal(2, model.Items.Count);
|
||||
Assert.All(model.Items, e => Assert.Equal("hash-test", e.DeviceKey));
|
||||
Assert.DoesNotContain(model.Items, e => e.DeviceKey == "hash-other");
|
||||
}
|
||||
|
||||
// ------------------------------------------------ filtres analytiques T17-E -------
|
||||
[Fact]
|
||||
public async Task ManufacturerAndOsFilters_ReturnOnlyMatchingEvents()
|
||||
{
|
||||
var repo = new FakeDiagnosticEventRepository();
|
||||
DiagnosticEventRecord samsung = DiagnosticTestData.Event(Guid.NewGuid());
|
||||
samsung.Id = 1;
|
||||
samsung.DeviceManufacturer = "Samsung";
|
||||
samsung.OperatingSystem = "Android";
|
||||
DiagnosticEventRecord apple = DiagnosticTestData.Event(Guid.NewGuid());
|
||||
apple.Id = 2;
|
||||
apple.DeviceManufacturer = "Apple";
|
||||
apple.OperatingSystem = "iOS";
|
||||
await repo.InsertBatchAsync(new[] { samsung, apple });
|
||||
|
||||
var model = new DiagnosticsModel(repo) { Manufacturer = "Samsung", OperatingSystem = "Android" };
|
||||
await model.OnGetAsync();
|
||||
|
||||
DiagnosticEventRecord record = Assert.Single(model.Items);
|
||||
Assert.Equal("Samsung", record.DeviceManufacturer);
|
||||
}
|
||||
|
||||
// ------------------------------------------------ sécurité UI (§45) ----------------
|
||||
[Fact]
|
||||
public void DiagnosticEventRecord_ExposesNoRawIdentityOrSecrets()
|
||||
{
|
||||
string[] names = typeof(DiagnosticEventRecord).GetProperties().Select(p => p.Name).ToArray();
|
||||
|
||||
Assert.DoesNotContain("DeviceId", names);
|
||||
Assert.DoesNotContain("UserId", names);
|
||||
Assert.DoesNotContain("CollaborateurId", names);
|
||||
Assert.DoesNotContain("Token", names);
|
||||
Assert.DoesNotContain("HmacKey", names);
|
||||
Assert.DoesNotContain("LI_PKID", names);
|
||||
Assert.DoesNotContain("LI_CleAPI", names);
|
||||
Assert.DoesNotContain("CL_CleAPIInstall", names);
|
||||
// DeviceKey (pseudonymisé) est autorisé.
|
||||
Assert.Contains("DeviceKey", names);
|
||||
}
|
||||
|
||||
// ------------------------------------------------ fabriques ------------------------
|
||||
private static DiagnosticEventRecord DeviceRecord(
|
||||
long id,
|
||||
Guid? traceId = null,
|
||||
Guid? operationId = null,
|
||||
Guid? sessionId = null)
|
||||
{
|
||||
DiagnosticEventRecord record = DiagnosticTestData.Event(Guid.NewGuid());
|
||||
record.Id = id;
|
||||
record.ClientCode = "CLIENT-042";
|
||||
record.LicenseNumber = "LIC-000842";
|
||||
record.DeviceKey = "hash-test";
|
||||
record.DeviceKeyVersion = 1;
|
||||
record.Platform = "Android";
|
||||
record.OperatingSystem = "Android";
|
||||
record.OperatingSystemVersion = "16";
|
||||
record.DeviceManufacturer = "Xiaomi";
|
||||
record.DeviceModel = "23113RKC6G";
|
||||
record.AppVersion = "1.4.1";
|
||||
record.AppBuild = "10401";
|
||||
record.ScreenWidth = 1080;
|
||||
record.ScreenHeight = 2400;
|
||||
record.LogicalWidth = 393;
|
||||
record.LogicalHeight = 873;
|
||||
record.DisplayScale = 2.75;
|
||||
record.TraceId = traceId;
|
||||
record.OperationId = operationId;
|
||||
record.SessionId = sessionId;
|
||||
return record;
|
||||
}
|
||||
|
||||
private static DiagnosticEventRecord LicenseRecord(long id, string licenseNumber)
|
||||
{
|
||||
DiagnosticEventRecord record = DiagnosticTestData.Event(Guid.NewGuid());
|
||||
record.Id = id;
|
||||
record.LicenseNumber = licenseNumber;
|
||||
return record;
|
||||
}
|
||||
|
||||
private static DiagnosticEventRecord DeviceKeyRecord(long id, string deviceKey)
|
||||
{
|
||||
DiagnosticEventRecord record = DiagnosticTestData.Event(Guid.NewGuid());
|
||||
record.Id = id;
|
||||
record.DeviceKey = deviceKey;
|
||||
return record;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user