Files
Omika/tests/Omika.Diagnostics.Tests/DiagnosticUserPolicyTests.cs
2026-10-23 18:46:50 +02:00

140 lines
5.3 KiB
C#

using Omika.Diagnostics.Security;
namespace Omika.Diagnostics.Tests;
/// <summary>
/// T23 — Règles de validation des utilisateurs (username/password/rôle) + protections
/// d'administration (dernier Admin, auto-désactivation, auto-rétrogradation) + hash factice.
/// </summary>
public class DiagnosticUserPolicyTests
{
// -------------------------------------------------- username ----
[Theory]
[InlineData("jean.dupont")]
[InlineData("admin-local")]
[InlineData("a_b-c.d")]
[InlineData("ABC123")]
public void Username_Valid(string username) =>
Assert.True(DiagnosticUserRules.IsValidUsername(username));
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData("avec espace")]
[InlineData("accentué")]
[InlineData("a/b")]
[InlineData("a@b")]
[InlineData("a;b")]
public void Username_Invalid(string username) =>
Assert.False(DiagnosticUserRules.IsValidUsername(username));
[Fact]
public void Username_TooLong_Rejected()
{
string tooLong = new string('a', DiagnosticUserRules.MaxUsernameLength + 1);
Assert.False(DiagnosticUserRules.IsValidUsername(tooLong));
Assert.True(DiagnosticUserRules.IsValidUsername(new string('a', DiagnosticUserRules.MaxUsernameLength)));
}
[Fact]
public void NormalizeUsername_Trims()
{
Assert.Equal("jean", DiagnosticUserRules.NormalizeUsername(" jean "));
Assert.Null(DiagnosticUserRules.NormalizeUsername(" "));
Assert.Null(DiagnosticUserRules.NormalizeUsername(null));
}
// -------------------------------------------------- password ----
[Fact]
public void Password_Minimum12()
{
Assert.True(DiagnosticUserRules.IsValidPassword("123456789012"));
Assert.True(DiagnosticUserRules.IsValidPassword("abcdefghijkl"));
Assert.False(DiagnosticUserRules.IsValidPassword("12345678901")); // 11
Assert.False(DiagnosticUserRules.IsValidPassword(""));
Assert.False(DiagnosticUserRules.IsValidPassword(null));
}
// -------------------------------------------------- role ----
[Fact]
public void Role_OnlySupportOrAdmin()
{
Assert.True(DiagnosticUserRules.IsValidRole("Support"));
Assert.True(DiagnosticUserRules.IsValidRole("Admin"));
Assert.True(DiagnosticUserRules.IsValidRole("admin"));
Assert.False(DiagnosticUserRules.IsValidRole("Owner"));
Assert.False(DiagnosticUserRules.IsValidRole(""));
Assert.False(DiagnosticUserRules.IsValidRole(null));
}
// -------------------------------------------------- guard : dernier Admin ----
[Fact]
public void Guard_Disable_LastActiveAdmin_Refused()
{
bool ok = DiagnosticUserGuard.CanDisable("admin1", "admin2", targetIsActiveAdmin: true, activeAdminCount: 1, out string? error);
Assert.False(ok);
Assert.Equal(DiagnosticUserGuard.LastAdminMessage, error);
}
[Fact]
public void Guard_Disable_NonLastAdmin_Allowed()
{
bool ok = DiagnosticUserGuard.CanDisable("admin1", "admin2", targetIsActiveAdmin: true, activeAdminCount: 2, out string? error);
Assert.True(ok);
Assert.Null(error);
}
[Fact]
public void Guard_Disable_SupportUser_Allowed()
{
bool ok = DiagnosticUserGuard.CanDisable("admin1", "support1", targetIsActiveAdmin: false, activeAdminCount: 1, out string? error);
Assert.True(ok);
Assert.Null(error);
}
// -------------------------------------------------- guard : auto-désactivation ----
[Fact]
public void Guard_Disable_Self_Refused()
{
bool ok = DiagnosticUserGuard.CanDisable("admin1", "admin1", targetIsActiveAdmin: true, activeAdminCount: 2, out string? error);
Assert.False(ok);
Assert.Equal(DiagnosticUserGuard.SelfDisableMessage, error);
}
// -------------------------------------------------- guard : auto-rétrogradation ----
[Fact]
public void Guard_Demote_LastActiveAdmin_Refused()
{
bool ok = DiagnosticUserGuard.CanDemoteFromAdmin("admin1", "admin2", activeAdminCount: 1, out string? error);
Assert.False(ok);
Assert.Equal(DiagnosticUserGuard.LastAdminMessage, error);
}
[Fact]
public void Guard_Demote_Self_Refused()
{
bool ok = DiagnosticUserGuard.CanDemoteFromAdmin("admin1", "admin1", activeAdminCount: 2, out string? error);
Assert.False(ok);
Assert.Equal(DiagnosticUserGuard.SelfDemoteMessage, error);
}
[Fact]
public void Guard_Demote_NonLastAdmin_Allowed()
{
bool ok = DiagnosticUserGuard.CanDemoteFromAdmin("admin1", "admin2", activeAdminCount: 2, out string? error);
Assert.True(ok);
Assert.Null(error);
}
// -------------------------------------------------- hash factice ----
[Fact]
public void DummyHash_ValidFormatAndDoesNotMatchArbitraryPassword()
{
Assert.False(DiagnosticPasswordHasher.Verify("un-mot-de-passe-arbitraire", DiagnosticPasswordHasher.DummyHash));
// Format valide : 3 parties, itérations positives (compatible Verify).
string[] parts = DiagnosticPasswordHasher.DummyHash.Split('.');
Assert.Equal(3, parts.Length);
Assert.True(int.TryParse(parts[0], out int iterations) && iterations > 0);
}
}