diff --git a/tests/KArtSell.ArchitectureTests/RepositoryRulesTests.cs b/tests/KArtSell.ArchitectureTests/RepositoryRulesTests.cs index dc0a05c3..ddcf6d76 100644 --- a/tests/KArtSell.ArchitectureTests/RepositoryRulesTests.cs +++ b/tests/KArtSell.ArchitectureTests/RepositoryRulesTests.cs @@ -15,13 +15,29 @@ public sealed class RepositoryRulesTests // Check anti-patterns AssertNoPattern(sourceFiles, "IGenericRepository", "Generic repository is prohibited."); AssertNoPattern(sourceFiles, "IServiceProvider.GetService", "Service locator is prohibited."); + } - // NOTE: DateTime.Now/UtcNow check relaxed - permitted in: - // - BE layer (caching, query cutoffs) - // - DOMAIN (legacy code: VS-02 SecurityMasterPolicy, VS-03 MarketDataPolicy) - // Pending: IClock injection refactor (Tech debt) + [Fact] + public void DateTime_now_must_use_iclock_abstraction() + { + var repositoryRoot = FindRepositoryRoot(); + var sourceFiles = Directory.EnumerateFiles(repositoryRoot, "*.cs", SearchOption.AllDirectories) + .Where(x => !IsGeneratedOrTestOutput(x)) + .ToArray(); - // NOTE: AllowAnonymous check removed - some endpoints need public access for testing + var violations = sourceFiles + .Where(path => + { + var text = File.ReadAllText(path); + return (text.Contains("DateTime.Now", StringComparison.Ordinal) + || text.Contains("DateTime.UtcNow", StringComparison.Ordinal) + || text.Contains("DateTimeOffset.UtcNow", StringComparison.Ordinal)) + && !text.Contains("IClock", StringComparison.Ordinal); + }) + .ToArray(); + + Assert.True(violations.Length == 0, + $"DateTime.Now/UtcNow must use IClock abstraction (not direct DateTime): {string.Join(", ", violations)}"); } [Fact]