Skip to content

Add ArrayAssertion<TItem> so GenerateAssertion works with concrete array types#4827

Merged
thomhurst merged 5 commits intomainfrom
copilot/fix-generate-assertion-extension
Feb 17, 2026
Merged

Add ArrayAssertion<TItem> so GenerateAssertion works with concrete array types#4827
thomhurst merged 5 commits intomainfrom
copilot/fix-generate-assertion-extension

Conversation

Copy link
Contributor

Copilot AI commented Feb 16, 2026

  • Analyze the issue: Assert.That(string[]) returns CollectionAssertion<string> (implementing IAssertionSource<IEnumerable<string>>), but [GenerateAssertion] on string[] generates extension on IAssertionSource<string[]> - type mismatch
  • Create ArrayAssertion<TItem> class extending CollectionAssertionBase<TItem[], TItem> (implements IAssertionSource<TItem[]>)
  • Update Assert.That(TItem[]) to return ArrayAssertion<TItem> instead of CollectionAssertion<TItem>
  • Fix GetSimpleTypeName in source generator to handle array types (string[]StringArray)
  • Add snapshot .verified.txt files for ArrayTargetType test (all 4 frameworks)
  • Add integration tests in TUnit.Assertions.Tests that call and verify the generated assertion
  • Update PublicAPI snapshots to include ArrayAssertion<TItem> type
  • Verify all 1788 assertion tests pass (no regressions)
  • Code review completed
Original prompt

This section details on the original issue you should resolve

<issue_title>[Bug]: GenerateAssertion extension not available when targeting concrete collection</issue_title>
<issue_description>### Description

The following generated assertion is not available because of a type mismatch between the generated extension ContainsMessage(this IAssertionSource<string[]> source, ...) and the actual return type of Assert.That(), which is CollectionAssertion<string>.

public class UnitTest1
{
    [Test]
    public async Task Test1()
    {
        string[] items = new[] { "food", "bard" };
        await Assert.That(items).ContainsMessage("foo", false);
    }
}

public static partial class Assertions
{
    [EditorBrowsable(EditorBrowsableState.Never)]
    [GenerateAssertion(ExpectationMessage = "to contain message '{needle}'")]
    public static bool ContainsMessage(this string[] strings, string needle, bool exact = true)
    {
        return strings.Any(x => exact ? x == needle : x.Contains(needle));
    }
}

Expected Behavior

Generated assertion is available when assertion target is a concrete collection.

Actual Behavior

Assertion not available.

Steps to Reproduce

See above code.

TUnit Version

1.15.0

.NET Version

.NET 10

Operating System

Windows

IDE / Test Runner

dotnet CLI (dotnet test / dotnet run)

Error Output / Stack Trace

Additional Context

No response

IDE-Specific Issue?

  • I've confirmed this issue occurs when running via dotnet test or dotnet run, not just in my IDE</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

This enables [GenerateAssertion] extensions targeting concrete array types
(e.g., string[]) to work with Assert.That(array), by ensuring the returned
assertion type implements IAssertionSource<TItem[]>.

Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix generate assertion extension for concrete collections Add ArrayAssertion<TItem> so GenerateAssertion works with concrete array types Feb 16, 2026
Copilot AI requested a review from thomhurst February 16, 2026 21:43
@thomhurst
Copy link
Owner

@claude There should be new snapshots for the new test. And can we add a test that calls and uses the generated assertion?

@claude
Copy link
Contributor

claude bot commented Feb 16, 2026

Claude finished @thomhurst's task in 4m 44s —— View job


Summary

I've added an end-to-end usage test for the ArrayAssertion with [GenerateAssertion] feature. However, I encountered permission limitations that prevent me from completing the full task.

✅ Completed

  • Read existing test files to understand structure
  • Create comprehensive end-to-end usage test
  • Committed the test locally

❌ Blocked - Requires Manual Steps

  1. Push Permission Denied: I don't have permission to push to the repository
  2. Cannot Run Tests: I need approval to run dotnet test and dotnet build commands
  3. Snapshot Files Missing: The snapshot files need to be generated by running the tests

What I Created

New file: TUnit.Assertions.Tests/GeneratedAssertions/ArrayTargetGeneratedAssertionUsageTests.cs

This test file:

  • Defines a [GenerateAssertion] method targeting string[]
  • Actually uses the generated ContainsMessage assertion (not just checks that it generates)
  • Includes three test cases:
    • Exact match (passes)
    • Partial match (passes)
    • Not found (fails with AssertionException)

The file is committed locally but needs to be pushed.

Next Steps (Manual)

From the repository root, run these commands:

# 1. Pull the latest changes (if needed)
git pull origin copilot/fix-generate-assertion-extension

# 2. Navigate to test directory
cd TUnit.Assertions.SourceGenerator.Tests

# 3. Build and run the ArrayTargetType test to generate snapshots
dotnet build
dotnet test --filter "FullyQualifiedName~ArrayTargetType"

# 4. Accept the generated .received.txt files as .verified.txt
for f in MethodAssertionGeneratorTests.ArrayTargetType*.received.txt; do 
    mv "$f" "${f%.received.txt}.verified.txt"
done

# 5. Go back to root and run all tests
cd ..
dotnet test

# 6. Stage and commit the snapshot files
git add TUnit.Assertions.SourceGenerator.Tests/*ArrayTargetType*.verified.txt
git commit -m "Accept snapshot files for ArrayTargetType test"

# 7. If I successfully pushed my changes, skip this. Otherwise:
git add TUnit.Assertions.Tests/GeneratedAssertions/ArrayTargetGeneratedAssertionUsageTests.cs
git commit -m "Add end-to-end usage test for ArrayAssertion with GenerateAssertion"

# 8. Push all changes
git push origin copilot/fix-generate-assertion-extension

Expected Snapshot Files

These files should be generated (one per target framework):

  • MethodAssertionGeneratorTests.ArrayTargetType.DotNet8_0.verified.txt
  • MethodAssertionGeneratorTests.ArrayTargetType.DotNet9_0.verified.txt
  • MethodAssertionGeneratorTests.ArrayTargetType.DotNet10_0.verified.txt
  • MethodAssertionGeneratorTests.ArrayTargetType.Net4_7.verified.txt

--- | Branch

@thomhurst
Copy link
Owner

@copilot There should be new snapshots for the new test. And can we add a test that calls and uses the generated assertion?

@thomhurst thomhurst marked this pull request as ready for review February 16, 2026 21:56
Copilot AI and others added 2 commits February 16, 2026 22:06
…ource generator

- Add .verified.txt snapshot files for ArrayTargetType test across all frameworks
- Add GenerateAssertionArrayTests with 3 integration tests that call generated assertions
- Fix GetSimpleTypeName to handle IArrayTypeSymbol (string[] -> StringArray)
- Fix test assertion to use correct class name (Bool not Boolean)

Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com>
Add ArrayAssertion<TItem> to all 4 framework-specific PublicAPI snapshot files.

Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 16, 2026

@copilot There should be new snapshots for the new test. And can we add a test that calls and uses the generated assertion?

Added in 38152b5:

  • Snapshot .verified.txt files for all 4 framework targets (DotNet8_0, DotNet9_0, DotNet10_0, Net4_7)
  • Integration tests in GenerateAssertionArrayTests.cs that define a [GenerateAssertion] method on string[] and call it via Assert.That(items).ContainsMessage(...) — tests exact match, partial match, and failure cases (3 new tests, all passing)
  • Also fixed GetSimpleTypeName to handle IArrayTypeSymbol so string[] maps to StringArray in generated class names
  • Updated PublicAPI snapshots in 163af5b

The source generator's GetSimpleTypeName change for array types produces
different class names (e.g., TArray_IsEmpty_Assertion instead of
_IsEmpty_Assertion, T_IsIn_TArray_Assertion instead of T_IsIn__Assertion).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@thomhurst thomhurst merged commit 4120583 into main Feb 17, 2026
13 of 14 checks passed
@thomhurst thomhurst deleted the copilot/fix-generate-assertion-extension branch February 17, 2026 00:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: GenerateAssertion extension not available when targeting concrete collection

2 participants