using DatReaderWriter; using System.Reflection; using System.Text.RegularExpressions; namespace AcDream.App.Tests; public sealed class RuntimeDatAccessArchitectureTests { [Fact] public void ProductionAppTypes_DoNotStoreOrAcceptRawDatCollection() { Type rawType = typeof(DatReaderWriter.DatCollection); Type ownerType = typeof(RuntimeDatCollection); Type[] appTypes = typeof(RuntimeDatCollectionFactory).Assembly.GetTypes(); var violations = new List(); foreach (Type type in appTypes.Where(type => type != ownerType)) { foreach (FieldInfo field in type.GetFields( BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) { if (field.FieldType == rawType) violations.Add($"{type.FullName} field {field.Name}"); } foreach (PropertyInfo property in type.GetProperties( BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) { if (property.PropertyType == rawType) violations.Add($"{type.FullName} property {property.Name}"); } foreach (MethodBase method in type.GetMethods( BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly) .Cast() .Concat(type.GetConstructors( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))) { if (method.GetParameters().Any(parameter => parameter.ParameterType == rawType)) violations.Add($"{type.FullName} method {method.Name}"); if (method is MethodInfo info && info.ReturnType == rawType) violations.Add($"{type.FullName} return {method.Name}"); } } Assert.Empty(violations); } [Fact] public void ProductionSource_CreatesRawHandlesAndBoundedAdapterOnlyInRuntimeOwner() { string root = FindRepoRoot(); string appRoot = Path.Combine(root, "src", "AcDream.App"); string ownerPath = Path.GetFullPath( Path.Combine(appRoot, "RuntimeDatCollectionFactory.cs")); string[] sources = Directory.GetFiles(appRoot, "*.cs", SearchOption.AllDirectories); string[] rawCreates = FindMatchingFiles(sources, @"\bnew\s+DatCollection\s*\("); string[] adapterCreates = FindMatchingFiles(sources, @"\bnew\s+DatCollectionAdapter\s*\("); string[] rawTypedReads = FindMatchingFiles( sources, @"\.Db\s*\.\s*(?:Get|TryGet)\s*<"); Assert.Equal([ownerPath], rawCreates); Assert.Equal([ownerPath], adapterCreates); Assert.Empty(rawTypedReads); } private static string[] FindMatchingFiles(IEnumerable sources, string pattern) => sources .Where(path => Regex.IsMatch(File.ReadAllText(path), pattern)) .Select(Path.GetFullPath) .OrderBy(path => path, StringComparer.OrdinalIgnoreCase) .ToArray(); private static string FindRepoRoot() { string? dir = AppContext.BaseDirectory; while (dir is not null) { if (File.Exists(Path.Combine(dir, "AcDream.slnx"))) return dir; dir = Directory.GetParent(dir)?.FullName; } throw new DirectoryNotFoundException("Could not locate AcDream.slnx."); } }