From 2f9733cad392ac73e23ec63d96822fdc3cfdc6e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Montiel=20Cardona?= Date: Sat, 6 Jun 2026 01:54:54 -0600 Subject: [PATCH 1/2] chore(deps): downgrade FluentAssertions to 6.12.0 (MIT) FluentAssertions 7.x+ moved to a commercial (Xceed) license; 6.12.0 is the last MIT-licensed release. The published RP2040Sharp.TestKit package took a transitive dependency on 8.8.0, so consumers inherited the non-MIT license. - Pin FluentAssertions to 6.12.0 in TestKit, unit tests, and integration tests. - Port the custom assertions (CortexM0/Gpio/UartProbe) back to the 6.x extension model: constructor without AssertionChain, using Execute.Assertion instead. Tests: 445 unit + 149 integration green. Co-Authored-By: Claude Opus 4.8 --- .../Assertions/CortexM0Assertions.cs | 15 ++++++--------- .../Assertions/GpioAssertions.cs | 15 ++++++--------- .../Assertions/UartProbeAssertions.cs | 19 ++++++++----------- .../Extensions/AssertionExtensions.cs | 10 +++------- src/RP2040.TestKit/RP2040.TestKit.csproj | 3 ++- .../RP2040Sharp.IntegrationTests.csproj | 2 +- .../RP2040Sharp.Tests.csproj | 2 +- 7 files changed, 27 insertions(+), 39 deletions(-) diff --git a/src/RP2040.TestKit/Assertions/CortexM0Assertions.cs b/src/RP2040.TestKit/Assertions/CortexM0Assertions.cs index fae3ac9..3c95c76 100644 --- a/src/RP2040.TestKit/Assertions/CortexM0Assertions.cs +++ b/src/RP2040.TestKit/Assertions/CortexM0Assertions.cs @@ -8,17 +8,14 @@ namespace RP2040.TestKit.Assertions; /// FluentAssertions extension for . public sealed class CortexM0Assertions : ReferenceTypeAssertions { - private readonly AssertionChain _chain; - - public CortexM0Assertions(CortexM0Plus subject, AssertionChain chain) : base(subject, chain) - => _chain = chain; + public CortexM0Assertions(CortexM0Plus subject) : base(subject) { } protected override string Identifier => "cpu"; public AndConstraint HaveRegister(int index, uint expected, string because = "", params object[] becauseArgs) { - _chain.BecauseOf(because, becauseArgs) + Execute.Assertion.BecauseOf(because, becauseArgs) .ForCondition(Subject.Registers[index] == expected) .FailWith("Expected R{0} to be 0x{1:X8}{reason}, but found 0x{2:X8}.", index, expected, Subject.Registers[index]); @@ -28,7 +25,7 @@ public AndConstraint HaveRegister(int index, uint expected, public AndConstraint HavePC(uint expected, string because = "", params object[] becauseArgs) { - _chain.BecauseOf(because, becauseArgs) + Execute.Assertion.BecauseOf(because, becauseArgs) .ForCondition(Subject.Registers.PC == expected) .FailWith("Expected PC to be 0x{0:X8}{reason}, but found 0x{1:X8}.", expected, Subject.Registers.PC); @@ -38,7 +35,7 @@ public AndConstraint HavePC(uint expected, public AndConstraint HaveSP(uint expected, string because = "", params object[] becauseArgs) { - _chain.BecauseOf(because, becauseArgs) + Execute.Assertion.BecauseOf(because, becauseArgs) .ForCondition(Subject.Registers.SP == expected) .FailWith("Expected SP to be 0x{0:X8}{reason}, but found 0x{1:X8}.", expected, Subject.Registers.SP); @@ -48,7 +45,7 @@ public AndConstraint HaveSP(uint expected, public AndConstraint HaveCycles(long expected, string because = "", params object[] becauseArgs) { - _chain.BecauseOf(because, becauseArgs) + Execute.Assertion.BecauseOf(because, becauseArgs) .ForCondition(Subject.Cycles == expected) .FailWith("Expected Cycles to be {0}{reason}, but found {1}.", expected, Subject.Cycles); @@ -74,7 +71,7 @@ public AndConstraint HaveOverflowFlag(bool expected, private AndConstraint HaveFlag(string name, bool actual, bool expected, string because, object[] becauseArgs) { - _chain.BecauseOf(because, becauseArgs) + Execute.Assertion.BecauseOf(because, becauseArgs) .ForCondition(actual == expected) .FailWith("Expected flag {0} to be {1}{reason}, but found {2}.", name, expected, actual); return new AndConstraint(this); diff --git a/src/RP2040.TestKit/Assertions/GpioAssertions.cs b/src/RP2040.TestKit/Assertions/GpioAssertions.cs index a3d0114..d123dde 100644 --- a/src/RP2040.TestKit/Assertions/GpioAssertions.cs +++ b/src/RP2040.TestKit/Assertions/GpioAssertions.cs @@ -8,17 +8,14 @@ namespace RP2040.TestKit.Assertions; /// FluentAssertions extension for . public sealed class GpioAssertions : ReferenceTypeAssertions { - private readonly AssertionChain _chain; - - public GpioAssertions(GpioPin subject, AssertionChain chain) : base(subject, chain) - => _chain = chain; + public GpioAssertions(GpioPin subject) : base(subject) { } protected override string Identifier => "pin"; public AndConstraint BeHigh( string because = "", params object[] becauseArgs) { - _chain.BecauseOf(because, becauseArgs) + Execute.Assertion.BecauseOf(because, becauseArgs) .ForCondition(Subject.DigitalValue) .FailWith("Expected GPIO pin to be HIGH{reason}, but it was LOW."); return new AndConstraint(this); @@ -27,7 +24,7 @@ public AndConstraint BeHigh( public AndConstraint BeLow( string because = "", params object[] becauseArgs) { - _chain.BecauseOf(because, becauseArgs) + Execute.Assertion.BecauseOf(because, becauseArgs) .ForCondition(!Subject.DigitalValue) .FailWith("Expected GPIO pin to be LOW{reason}, but it was HIGH."); return new AndConstraint(this); @@ -36,7 +33,7 @@ public AndConstraint BeLow( public AndConstraint BeOutput( string because = "", params object[] becauseArgs) { - _chain.BecauseOf(because, becauseArgs) + Execute.Assertion.BecauseOf(because, becauseArgs) .ForCondition(Subject.IsOutput) .FailWith("Expected GPIO pin to be configured as OUTPUT{reason}, but it was INPUT."); return new AndConstraint(this); @@ -50,7 +47,7 @@ public AndConstraint BeOutput( public AndConstraint BePioOutput( string because = "", params object[] becauseArgs) { - _chain.BecauseOf(because, becauseArgs) + Execute.Assertion.BecauseOf(because, becauseArgs) .ForCondition(Subject.IsPioOutput) .FailWith("Expected GPIO pin to be assigned to a PIO state machine (FUNCSEL=6 or 7){reason}, but it was not."); return new AndConstraint(this); @@ -59,7 +56,7 @@ public AndConstraint BePioOutput( public AndConstraint BeInput( string because = "", params object[] becauseArgs) { - _chain.BecauseOf(because, becauseArgs) + Execute.Assertion.BecauseOf(because, becauseArgs) .ForCondition(!Subject.IsOutput) .FailWith("Expected GPIO pin to be configured as INPUT{reason}, but it was OUTPUT."); return new AndConstraint(this); diff --git a/src/RP2040.TestKit/Assertions/UartProbeAssertions.cs b/src/RP2040.TestKit/Assertions/UartProbeAssertions.cs index 2e2d233..4589bb2 100644 --- a/src/RP2040.TestKit/Assertions/UartProbeAssertions.cs +++ b/src/RP2040.TestKit/Assertions/UartProbeAssertions.cs @@ -8,17 +8,14 @@ namespace RP2040.TestKit.Assertions; /// FluentAssertions extension for . public sealed class UartProbeAssertions : ReferenceTypeAssertions { - private readonly AssertionChain _chain; - - public UartProbeAssertions(UartProbe subject, AssertionChain chain) : base(subject, chain) - => _chain = chain; + public UartProbeAssertions(UartProbe subject) : base(subject) { } protected override string Identifier => "uart"; public AndConstraint Contain(string expected, string because = "", params object[] becauseArgs) { - _chain.BecauseOf(because, becauseArgs) + Execute.Assertion.BecauseOf(because, becauseArgs) .ForCondition(Subject.Text.Contains(expected)) .FailWith("Expected UART output to contain {0}{reason}, but found {1}.", expected, Subject.Text); @@ -28,7 +25,7 @@ public AndConstraint Contain(string expected, public AndConstraint NotContain(string expected, string because = "", params object[] becauseArgs) { - _chain.BecauseOf(because, becauseArgs) + Execute.Assertion.BecauseOf(because, becauseArgs) .ForCondition(!Subject.Text.Contains(expected)) .FailWith("Expected UART output not to contain {0}{reason}, but found {1}.", expected, Subject.Text); @@ -38,7 +35,7 @@ public AndConstraint NotContain(string expected, public AndConstraint StartWith(string expected, string because = "", params object[] becauseArgs) { - _chain.BecauseOf(because, becauseArgs) + Execute.Assertion.BecauseOf(because, becauseArgs) .ForCondition(Subject.Text.StartsWith(expected, StringComparison.Ordinal)) .FailWith("Expected UART output to start with {0}{reason}, but found {1}.", expected, Subject.Text); @@ -48,7 +45,7 @@ public AndConstraint StartWith(string expected, public AndConstraint BeEmpty( string because = "", params object[] becauseArgs) { - _chain.BecauseOf(because, becauseArgs) + Execute.Assertion.BecauseOf(because, becauseArgs) .ForCondition(Subject.ByteCount == 0) .FailWith("Expected UART to have no output{reason}, but found {0} bytes.", Subject.ByteCount); return new AndConstraint(this); @@ -57,7 +54,7 @@ public AndConstraint BeEmpty( public AndConstraint HaveByteCount(int expected, string because = "", params object[] becauseArgs) { - _chain.BecauseOf(because, becauseArgs) + Execute.Assertion.BecauseOf(because, becauseArgs) .ForCondition(Subject.ByteCount == expected) .FailWith("Expected UART to have {0} bytes{reason}, but found {1}.", expected, Subject.ByteCount); @@ -67,7 +64,7 @@ public AndConstraint HaveByteCount(int expected, public AndConstraint ContainLine(string expected, string because = "", params object[] becauseArgs) { - _chain.BecauseOf(because, becauseArgs) + Execute.Assertion.BecauseOf(because, becauseArgs) .ForCondition(Subject.Lines.Contains(expected)) .FailWith("Expected UART output to contain line {0}{reason}.", expected); return new AndConstraint(this); @@ -76,7 +73,7 @@ public AndConstraint ContainLine(string expected, public AndConstraint HaveLineCount(int expected, string because = "", params object[] becauseArgs) { - _chain.BecauseOf(because, becauseArgs) + Execute.Assertion.BecauseOf(because, becauseArgs) .ForCondition(Subject.Lines.Count == expected) .FailWith("Expected UART output to have {0} lines{reason}, but found {1}.", expected, Subject.Lines.Count); diff --git a/src/RP2040.TestKit/Extensions/AssertionExtensions.cs b/src/RP2040.TestKit/Extensions/AssertionExtensions.cs index 94be057..acae1e9 100644 --- a/src/RP2040.TestKit/Extensions/AssertionExtensions.cs +++ b/src/RP2040.TestKit/Extensions/AssertionExtensions.cs @@ -1,4 +1,3 @@ -using FluentAssertions.Execution; using RP2040.Core.Cpu; using RP2040.Peripherals.Gpio; using RP2040.TestKit.Assertions; @@ -11,12 +10,9 @@ namespace RP2040.TestKit.Extensions; /// public static class AssertionExtensions { - public static CortexM0Assertions Should(this CortexM0Plus cpu) - => new(cpu, AssertionChain.GetOrCreate()); + public static CortexM0Assertions Should(this CortexM0Plus cpu) => new(cpu); - public static UartProbeAssertions Should(this UartProbe probe) - => new(probe, AssertionChain.GetOrCreate()); + public static UartProbeAssertions Should(this UartProbe probe) => new(probe); - public static GpioAssertions Should(this GpioPin pin) - => new(pin, AssertionChain.GetOrCreate()); + public static GpioAssertions Should(this GpioPin pin) => new(pin); } diff --git a/src/RP2040.TestKit/RP2040.TestKit.csproj b/src/RP2040.TestKit/RP2040.TestKit.csproj index a158a0d..1b0bc0e 100644 --- a/src/RP2040.TestKit/RP2040.TestKit.csproj +++ b/src/RP2040.TestKit/RP2040.TestKit.csproj @@ -10,6 +10,7 @@ - + + diff --git a/tests/RP2040Sharp.IntegrationTests/RP2040Sharp.IntegrationTests.csproj b/tests/RP2040Sharp.IntegrationTests/RP2040Sharp.IntegrationTests.csproj index fafc264..2ca91d4 100644 --- a/tests/RP2040Sharp.IntegrationTests/RP2040Sharp.IntegrationTests.csproj +++ b/tests/RP2040Sharp.IntegrationTests/RP2040Sharp.IntegrationTests.csproj @@ -15,7 +15,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/tests/RP2040Sharp.Tests/RP2040Sharp.Tests.csproj b/tests/RP2040Sharp.Tests/RP2040Sharp.Tests.csproj index 9584fe9..01dfcd4 100644 --- a/tests/RP2040Sharp.Tests/RP2040Sharp.Tests.csproj +++ b/tests/RP2040Sharp.Tests/RP2040Sharp.Tests.csproj @@ -13,7 +13,7 @@ - + From 5d511f1be7a8c03405d5f7a19a08fdae6bf18a4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Montiel=20Cardona?= Date: Sat, 6 Jun 2026 01:56:02 -0600 Subject: [PATCH 2/2] docs: add CHANGELOG entry for 1.0.0-rc.2 Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad4f671..ea25d2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.0.0-rc.2] - 2026-06-06 + +### Changed + +- **License hygiene:** pinned `FluentAssertions` to **6.12.0**, the last + MIT-licensed release (7.x+ moved to a commercial Xceed license). This keeps the + published `RP2040Sharp.TestKit` package and everything it pulls in MIT-compatible. + The TestKit's custom assertions were ported back to the 6.x extension model. + ## [1.0.0-rc.1] - 2026-06-06 First public release candidate. A high-performance RP2040 emulator in modern C# @@ -45,5 +54,6 @@ First public release candidate. A high-performance RP2040 emulator in modern C# - Flash programming uses C# hooks rather than the SSI XIP hardware path. - USB host support is CDC-only (sufficient for the MicroPython REPL). -[Unreleased]: https://github.com/begeistert/RP2040Sharp/compare/v1.0.0-rc.1...HEAD +[Unreleased]: https://github.com/begeistert/RP2040Sharp/compare/v1.0.0-rc.2...HEAD +[1.0.0-rc.2]: https://github.com/begeistert/RP2040Sharp/compare/v1.0.0-rc.1...v1.0.0-rc.2 [1.0.0-rc.1]: https://github.com/begeistert/RP2040Sharp/releases/tag/v1.0.0-rc.1