Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Sources/AngouriMath/Docs/Contributing/Packaging.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
72 changes: 42 additions & 30 deletions Sources/Tests/UnitTests/Core/KernelDependenciesTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,60 +56,72 @@ public sealed class KernelDependenciesTest
"Antlr4.Runtime.Standard",
};

/// <summary>
/// Whether a reference is part of the framework rather than something a consumer restores.
/// </summary>
/// <remarks>
/// <c>netstandard</c> 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 <c>net10.0</c>, and failed the <c>C# Test</c> 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.
/// </remarks>
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()
.Select(name => name.Name!)
.OrderBy(name => name, System.StringComparer.Ordinal)
.ToArray();

/// <summary>
/// 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 — <c>System.Text.Json</c> arriving with
/// <c>Core/Serialization</c> is the case in point — is exactly what wants seeing.
/// </summary>
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));
}

/// <summary>
/// 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.
/// </summary>
[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();

Expand Down
Loading