diff --git a/Sources/AngouriMath/Docs/Contributing/Packaging.md b/Sources/AngouriMath/Docs/Contributing/Packaging.md index fe99ba11f..6effd0769 100644 --- a/Sources/AngouriMath/Docs/Contributing/Packaging.md +++ b/Sources/AngouriMath/Docs/Contributing/Packaging.md @@ -144,7 +144,10 @@ typeof(AngouriMath.Entity).Assembly # measured by reflection on the built ne ANTLR-generated lexer and parser default their error streams to it.) This said 13 until `System.Text.Json` arrived with `Core/Serialization` — a framework assembly, so no consumer's restore changed, and nothing noticed for the same reason. `KernelDependenciesTest` is the gate §7 - asked for and now holds both counts. + asked for. It asserts the **third-party** set exactly, in both directions, and the framework ones + only as a set nothing may exceed — which framework assemblies a build resolves depends on the + target framework leg, and `netstandard` appears on the netstandard2.0 one and not on `net10.0`. + A leg resolving fewer of them is not a packaging event; one pulling in something new is. **Twelve capabilities × 68 node types is the reason the kernel is one assembly.** A capability written as an abstract member of `Entity` cannot be in a different package than `Entity`, whatever anyone diff --git a/Sources/Tests/UnitTests/Core/KernelDependenciesTest.cs b/Sources/Tests/UnitTests/Core/KernelDependenciesTest.cs index 77e798044..14d1a18fd 100644 --- a/Sources/Tests/UnitTests/Core/KernelDependenciesTest.cs +++ b/Sources/Tests/UnitTests/Core/KernelDependenciesTest.cs @@ -56,6 +56,22 @@ public sealed class KernelDependenciesTest "Antlr4.Runtime.Standard", }; + /// + /// Whether a reference is part of the framework rather than something a consumer restores. + /// + /// + /// netstandard is on this list because it is the reference assembly the + /// netstandard2.0 leg resolves against, and it appears or does not depending on which leg + /// is loaded. The first version of this file asserted an exact set that had been measured + /// on one leg, passed locally on net10.0, and failed the C# Test workflow on + /// exactly that name. Which framework assemblies appear is a fact about the build leg; + /// which third-party ones appear is the packaging decision, and only the second is + /// asserted exactly. + /// + private static bool IsFramework(string name) => + name.StartsWith("System.", System.StringComparison.Ordinal) + || name is "System" or "netstandard" or "mscorlib"; + private static string[] Referenced() => typeof(MathS).Assembly .GetReferencedAssemblies() @@ -63,53 +79,49 @@ private static string[] Referenced() => .OrderBy(name => name, System.StringComparer.Ordinal) .ToArray(); + /// + /// The framework assemblies seen so far, across the legs this has run on. A superset rather + /// than an equality: a leg that resolves fewer of them is not a packaging event, while one + /// that pulls in something new — System.Text.Json arriving with + /// Core/Serialization is the case in point — is exactly what wants seeing. + /// + private static readonly string[] Framework = + { + "System.Collections", + "System.Collections.Concurrent", + "System.Console", + "System.Linq", + "System.Linq.Expressions", + "System.Memory", + "System.Runtime", + "System.Runtime.Numerics", + "System.Text.Json", + "System.Threading", + "netstandard", + }; + [Fact] public void TheKernelReferencesNothingItIsNotRecordedAsReferencing() { - var expected = new[] - { - "Antlr4.Runtime.Standard", - "GenericTensor", - "HonkSharp", - "Numbers", - "System.Collections", - "System.Collections.Concurrent", - "System.Console", - "System.Linq", - "System.Linq.Expressions", - "System.Memory", - "System.Runtime", - "System.Runtime.Numerics", - "System.Text.Json", - "System.Threading", - }; - - var actual = Referenced(); + var recorded = Framework.Concat(ThirdParty).ToList(); + var added = Referenced().Except(recorded).ToList(); - var added = actual.Except(expected).ToList(); Assert.True(added.Count == 0, $"the kernel references {added.Count} assemblies this list does not record: " + string.Join(", ", added) + ". Adding one is a packaging decision — see Docs/Contributing/Packaging.md §11 — " + "so record it here in the same change that adds it."); - - // The other direction, so the list cannot outlive what it describes: a dependency that - // goes away should be deleted here rather than left asserting nothing. - var gone = expected.Except(actual).ToList(); - Assert.True(gone.Count == 0, - $"{gone.Count} assemblies are recorded here and no longer referenced, and should be " - + "deleted: " + string.Join(", ", gone)); } /// - /// The number that matters to a consumer, separately from the framework ones, because it - /// is what a restore actually fetches. + /// The set that matters to a consumer, separately from the framework ones, because it is + /// what a restore actually fetches. Asserted exactly, in both directions. /// [Fact] public void TheThirdPartyDependenciesAreTheFourThatWereAgreed() { var actual = Referenced() - .Where(name => !name.StartsWith("System.", System.StringComparison.Ordinal)) + .Where(name => !IsFramework(name)) .OrderBy(name => name, System.StringComparer.Ordinal) .ToArray();