From b511b790d05496339974cba22959904e39563942 Mon Sep 17 00:00:00 2001 From: Terje Sandstrom Date: Wed, 6 May 2026 21:20:35 +0200 Subject: [PATCH 01/11] fixing phase 1, uid's and xrefs --- .claude/plans/constraints-improvement-plan.md | 228 ++++++++++++++++ .claude/settings.local.json | 11 +- .../skills/constraint-documentation/skill.md | 253 ++++++++++++++++++ .../classic-assertions/Assert.AreEqual.md | 2 +- .../classic-assertions/Assert.AreNotEqual.md | 2 +- .../classic-assertions/Assert.AreNotSame.md | 2 +- .../classic-assertions/Assert.AreSame.md | 2 +- .../classic-assertions/Assert.Catch.md | 2 +- .../classic-assertions/Assert.CatchAsync.md | 2 +- .../classic-assertions/Assert.DoesNotThrow.md | 2 +- .../Assert.DoesNotThrowAsync.md | 2 +- .../classic-assertions/Assert.Throws.md | 2 +- .../classic-assertions/Assert.ThrowsAsync.md | 2 +- .../constraints/AllItemsConstraint.md | 4 + .../constraints/AndConstraint.md | 4 + .../constraints/AnyOfConstraint.md | 6 +- .../constraints/AssignableFromConstraint.md | 4 + .../constraints/AssignableToConstraint.md | 4 + .../constraints/AttributeConstraint.md | 4 + .../constraints/AttributeExistsConstraint.md | 4 + .../BinarySerializableConstraint.md | 4 + .../CollectionEquivalentConstraint.md | 4 + .../CollectionOrderedConstraint.md | 4 + .../constraints/CollectionSubsetConstraint.md | 4 + .../CollectionSupersetConstraint.md | 4 + .../constraints/DefaultConstraint.md | 4 + .../constraints/DelayedConstraint.md | 4 + .../DictionaryContainsKeyConstraint.md | 4 + ...ictionaryContainsKeyValuePairConstraint.md | 4 + .../DictionaryContainsValueConstraint.md | 4 + .../constraints/EmptyCollectionConstraint.md | 4 + .../constraints/EmptyConstraint.md | 4 + .../constraints/EmptyDirectoryConstraint.md | 4 + .../constraints/EmptyStringConstraint.md | 4 + .../constraints/EndsWithConstraint.md | 4 + .../constraints/EqualConstraint.md | 2 +- .../constraints/ExactCountConstraint.md | 4 + .../constraints/ExactTypeConstraint.md | 4 + .../constraints/FalseConstraint.md | 4 + .../FileOrDirectoryExistsConstraint.md | 8 +- .../constraints/GreaterThanConstraint.md | 4 + .../GreaterThanOrEqualConstraint.md | 4 + .../constraints/InstanceOfTypeConstraint.md | 4 + .../constraints/LessThanConstraint.md | 4 + .../constraints/LessThanOrEqualConstraint.md | 4 + .../constraints/NaNConstraint.md | 4 + .../constraints/NoItemConstraint.md | 4 + .../constraints/NotConstraint.md | 6 +- .../constraints/NullConstraint.md | 4 + .../writing-tests/constraints/OrConstraint.md | 4 + .../constraints/PropertyConstraint.md | 4 + .../constraints/PropertyExistsConstraint.md | 4 + .../constraints/RangeConstraint.md | 4 + .../constraints/RegexConstraint.md | 4 + .../constraints/ReusableConstraint.md | 4 + .../constraints/SameAsConstraint.md | 2 +- .../constraints/SamePathConstraint.md | 4 + .../constraints/SamePathOrUnderConstraint.md | 4 + .../constraints/SomeItemsConstraint.md | 2 +- .../constraints/StartsWithConstraint.md | 4 + .../constraints/SubPathConstraint.md | 4 + .../constraints/SubstringConstraint.md | 4 + .../constraints/ThrowsConstraint.md | 2 +- .../constraints/ThrowsNothingConstraint.md | 4 + .../constraints/TrueConstraint.md | 4 + .../constraints/UniqueItemsConstraint.md | 4 + .../constraints/WhiteSpaceConstraint.md | 4 + .../constraints/XmlSerializableConstraint.md | 4 + 68 files changed, 712 insertions(+), 20 deletions(-) create mode 100644 .claude/plans/constraints-improvement-plan.md create mode 100644 .claude/skills/constraint-documentation/skill.md diff --git a/.claude/plans/constraints-improvement-plan.md b/.claude/plans/constraints-improvement-plan.md new file mode 100644 index 000000000..dac8a8564 --- /dev/null +++ b/.claude/plans/constraints-improvement-plan.md @@ -0,0 +1,228 @@ +# NUnit Constraints Documentation Improvement Plan + +This plan tracks the implementation of constraint documentation improvements. For the documentation template and guidelines, see the [Constraint Documentation Skill](../.claude/skills/constraint-documentation/skill.md). + +## Source Code Analysis (2024) + +Analysis of NUnit framework source code revealed significant documentation gaps: + +### Missing Constraint Documentation + +These constraints exist in source but have NO documentation: + +| Constraint | Syntax | Description | Priority | +|------------|--------|-------------|----------| +| MultipleOfConstraint | `Is.MultipleOf(n)`, `Is.Even`, `Is.Odd` | Tests if value is multiple of another | High | +| EmptyGuidConstraint | (internal, via `Is.Empty` on Guid) | Tests if a Guid is empty/default | Low | +| ContainsConstraint | `Does.Contain()` | Routes to Substring/SomeItems based on type | Medium | + +### Undocumented Features/Modifiers + +These features exist in source but are not well documented: + +| Feature | Constraints Affected | Status | +|---------|---------------------|--------| +| `UsingPropertiesComparer()` | EqualConstraint | ✅ **Well documented** in EqualConstraint.md | +| `IgnoreWhiteSpace` | EqualConstraint, ContainsConstraint | ✅ Documented in EqualConstraint.md | +| `Is.Even`, `Is.Odd`, `Is.MultipleOf(n)` | MultipleOfConstraint | ❌ **Not documented** | +| `ApplyToAsync()` | All constraints via IAsyncConstraint | ❌ **Not documented** | +| `IgnoreLineEndingFormat` | ContainsConstraint | ❌ **Not documented** (ContainsConstraint needs docs) | +| `Contains.*` syntax helper | Various | ⚠️ Partially documented within other constraint pages | + +### Deprecated/Removed Constraints + +| Constraint | Status | Notes | +|------------|--------|-------| +| BinarySerializableConstraint | **DEPRECATED** | Removed in NUnit 4.x due to .NET 8 binary serialization removal | + +### Syntax Helper Coverage + +The source exposes constraints via 4 helper classes: + +- **Is.*** - 50+ members (most well-documented) +- **Does.*** - 10+ members (partially documented) +- **Has.*** - 20+ members (partially documented) +- **Contains.*** - 4 members (needs documentation) + +## Constraint Inventory + +### Priority 1: High-Traffic Constraints (Improve First) + +These are commonly used and should have excellent documentation: + +| Constraint | Current State | Needs | +|------------|---------------|-------| +| EqualConstraint | ✅ **Excellent** - comprehensive with UsingPropertiesComparer | UID fixed ✅ | +| NullConstraint | Minimal (1 example ref) | Full rewrite with inline examples | +| TrueConstraint | Minimal | Full rewrite | +| FalseConstraint | Minimal | Full rewrite | +| GreaterThanConstraint | Good examples, has modifiers | UID fixed ✅, add section headers | +| LessThanConstraint | Same as GreaterThan | UID fixed ✅, add section headers | +| ThrowsConstraint | Good | UID fixed ✅, minor cleanup | +| ContainsConstraint | **No dedicated doc** | Create new doc explaining routing | +| CollectionEquivalentConstraint | Moderate | Add more examples, sections | + +### Priority 2: Comparison Constraints + +| Constraint | Current State | Needs | +|------------|---------------|-------| +| GreaterThanOrEqualConstraint | Moderate | Section headers, more context | +| LessThanOrEqualConstraint | Moderate | Section headers, more context | +| RangeConstraint | External ref only | Add inline examples | +| SameAsConstraint | Minimal | Add examples showing reference equality | + +### Priority 3: String Constraints + +| Constraint | Current State | Needs | +|------------|---------------|-------| +| StartsWithConstraint | Good | Minor cleanup | +| EndsWithConstraint | Moderate | Match StartsWithConstraint quality | +| SubstringConstraint | Good | Minor cleanup | +| RegexConstraint | Moderate | Add pattern examples | +| EmptyStringConstraint | Minimal | Add examples | +| WhiteSpaceConstraint | Unknown | Review and improve | + +### Priority 4: Collection Constraints + +| Constraint | Current State | Needs | +|------------|---------------|-------| +| AllItemsConstraint | Moderate | Add subsections | +| SomeItemsConstraint | Good modifiers | Add example sections | +| NoItemConstraint | Minimal | Add examples | +| UniqueItemsConstraint | Good modifiers | Add example sections | +| CollectionOrderedConstraint | Excellent | Minor cleanup only | +| CollectionSubsetConstraint | Moderate | Add examples | +| CollectionSupersetConstraint | Moderate | Add examples | +| ExactCountConstraint | Unknown | Review | +| EmptyCollectionConstraint | Minimal | Add examples | + +### Priority 5: Type Constraints + +| Constraint | Current State | Needs | +|------------|---------------|-------| +| InstanceOfTypeConstraint | External ref only | Add inline examples | +| ExactTypeConstraint | Minimal | Add examples | +| AssignableFromConstraint | Minimal (2 one-liners) | Add context, examples | +| AssignableToConstraint | Minimal | Add examples | +| AttributeConstraint | Unknown | Review | +| AttributeExistsConstraint | Unknown | Review | + +### Priority 6: Dictionary Constraints + +| Constraint | Current State | Needs | +|------------|---------------|-------| +| DictionaryContainsKeyConstraint | Excellent | Minor cleanup | +| DictionaryContainsValueConstraint | Unknown | Review, match Key quality | +| DictionaryContainsKeyValuePairConstraint | Unknown | Review | + +### Priority 7: Property Constraints + +| Constraint | Current State | Needs | +|------------|---------------|-------| +| PropertyConstraint | External ref only | Add inline examples | +| PropertyExistsConstraint | Unknown | Review | + +### Priority 8: Path/File Constraints + +| Constraint | Current State | Needs | +|------------|---------------|-------| +| FileOrDirectoryExistsConstraint | Has modifiers (wrong format) | Fix modifier format | +| SamePathConstraint | Unknown | Review | +| SamePathOrUnderConstraint | Unknown | Review | +| SubPathConstraint | Unknown | Review | +| EmptyDirectoryConstraint | Minimal | Add examples | + +### Priority 9: Compound Constraints + +| Constraint | Current State | Needs | +|------------|---------------|-------| +| AndConstraint | Minimal | Add examples of combining | +| OrConstraint | Minimal | Add examples | +| NotConstraint | **BROKEN** - wrong example ref | Fix reference, add examples | + +### Priority 10: Special Constraints + +| Constraint | Current State | Needs | +|------------|---------------|-------| +| DelayedConstraint | Has table format | Standardize, document async support | +| ReusableConstraint | Unknown | Review | +| DefaultConstraint | Has version info | Review | +| ThrowsNothingConstraint | Unknown | Review | +| NaNConstraint | Minimal (2 one-liners) | Add context | +| BinarySerializableConstraint | **DEPRECATED** | Add deprecation notice, mark as removed in NUnit 4.x | +| XmlSerializableConstraint | Unknown | Review | +| AnyOfConstraint | Unknown | Review | + +### Priority 11: Missing Documentation (NEW) + +| Constraint | Syntax | Needs | +|------------|--------|-------| +| MultipleOfConstraint | `Is.MultipleOf(n)`, `Is.Even`, `Is.Odd` | Create new doc page | +| ContainsConstraint | `Does.Contain()` | Create clarification doc explaining routing behavior | + +### Priority 12: Feature Documentation (NEW) + +| Feature | Current State | Needs | +|---------|---------------|-------| +| Async Constraint Support | Not documented | Create guide for ApplyToAsync patterns | +| Contains.* syntax helper | Partially documented | Consider dedicated Contains helper page | +| IgnoreLineEndingFormat | Not documented | Add to ContainsConstraint when created | + +## Critical Fixes (Do First) + +1. **NotConstraint.md** - Fix wrong example reference (currently points to PropertyConstraintExamples) +2. **FileOrDirectoryExistsConstraint.md** - Fix modifier format (missing `.` prefix) +3. **UID standardization** - Update all UIDs to `constraint-` pattern + +## Snippet File Organization + +Current: All examples in single `ConstraintExamples.cs` file with regions. + +Proposed: Keep single file but ensure: +- Every constraint has at least one region +- Regions are named consistently: `Examples` +- Each region has comments explaining what's being demonstrated +- Complex constraints have multiple regions for different scenarios + +## Estimated Scope + +| Category | Files | Effort | +|----------|-------|--------| +| Critical fixes | 3 | Small | ✅ Complete | +| Full rewrites needed | ~25 | Large | +| Moderate improvements | ~15 | Medium | +| Minor cleanup only | ~12 | Small | +| **Existing docs subtotal** | **55** | | +| New constraint docs needed | 2 | Small (MultipleOf, ContainsConstraint) | +| New feature docs needed | 2 | Medium (Async support, Contains.* helper) | +| **Total** | **59** | | + +## Implementation Order + +1. **Phase 1**: Critical fixes (NotConstraint, FileOrDirectoryExists, UID standardization) ✅ Complete +2. **Phase 2**: Priority 1 high-traffic constraints +3. **Phase 3**: Priority 2-4 constraints (comparison, string, collection) +4. **Phase 4**: Priority 5-10 remaining constraints +5. **Phase 5**: Priority 11 missing constraint documentation (MultipleOfConstraint, ContainsConstraint) +6. **Phase 6**: Priority 12 feature documentation (Async support, Contains.* helper) + +## Progress Tracking + +### Phase 1: Critical Fixes +| Task | Status | Notes | +|------|--------|-------| +| Fix NotConstraint.md example reference | Complete | Fixed #PropertyConstraintExamples → #NotConstraintExamples | +| Fix FileOrDirectoryExistsConstraint.md modifiers | Complete | Added `.` prefix to IgnoreDirectories and IgnoreFiles | +| Standardize all UIDs to `constraint-` | Complete | Added UIDs to all 55 constraint files, updated 11 xref references | + +### Phase 2: Priority 1 Constraints +| Constraint | Status | Notes | +|------------|--------|-------| +| EqualConstraint | Pending | | +| NullConstraint | Pending | | +| TrueConstraint | Pending | | +| FalseConstraint | Pending | | +| GreaterThanConstraint | Pending | | +| LessThanConstraint | Pending | | +| ThrowsConstraint | Pending | | +| CollectionEquivalentConstraint | Pending | | diff --git a/.claude/settings.local.json b/.claude/settings.local.json index cbde47d7c..17a390775 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -5,9 +5,16 @@ "Bash(dotnet test:*)", "Bash(docfx:*)", "Bash(dir:*)", - "Bash(grep:*)" + "Bash(grep:*)", + "Bash(for:*)", + "Bash(do grep \"^public.*class\" \"$f\")", + "Bash(echo:*)", + "Bash(done)", + "Bash(ls:*)", + "Bash(do grep \"^public class\\\\|^public sealed class\" \"$f\")", + "Bash(do grep \"^public class\" \"$f\")" ], "deny": [], "ask": [] } -} \ No newline at end of file +} diff --git a/.claude/skills/constraint-documentation/skill.md b/.claude/skills/constraint-documentation/skill.md new file mode 100644 index 000000000..90da250ee --- /dev/null +++ b/.claude/skills/constraint-documentation/skill.md @@ -0,0 +1,253 @@ +--- +name: NUnit Constraint Documentation +description: Create and update documentation for NUnit constraints following the established template structure +--- + +# NUnit Constraint Documentation + +This skill describes how to create and update documentation for NUnit constraints. + +## Documentation Template Structure + +Each constraint documentation file in `docs/articles/nunit/writing-tests/constraints/` should follow this structure: + +````markdown +--- +uid: constraint- +--- + +# Constraint + +Brief description (2-3 sentences) explaining what the constraint tests and when to use it. + +## Usage + +```csharp +Is.(args) // Primary syntax +Does.(args) // If applicable +Has.(args) // If applicable +``` + +## Modifiers + +```csharp +.IgnoreCase // Makes comparison case-insensitive +.Using(IComparer comparer) // Uses custom comparison logic +.Within(tolerance) // Allows approximate matching +``` + +> [!NOTE] +> Only include this section if the constraint has modifiers. + +## Examples + +Inline one-liners showing common patterns: + +```csharp +Assert.That(actual, Is.(expected)); +Assert.That(actual, Is.Not.(expected)); +Assert.That(actual, Is.(expected).IgnoreCase); +``` + +### [Scenario Section - only if complex setup needed] + +Brief explanation of the scenario. + +[!code-csharp[ScenarioExample](~/snippets/Snippets.NUnit/ConstraintExamples.cs#ScenarioExample)] + +## Notes + +1. Important behavioral notes +2. Edge cases +3. Compatibility information + +## See Also + +* [Related Constraint](related.md) +* [Another Related](another.md) +```` + +## Key Structural Principles + +| Section | Purpose | +|---------|---------| +| Usage (first) | Users interact with fluent API (`Is.*`, `Does.*`), not constructors | +| Modifiers | Use `.ModifierName` format (shows method chaining) | +| Examples | Inline one-liners for common patterns | +| Notes | Edge cases and important behaviors | +| See Also | Links to related constraints | + +## Inline vs External Examples + +**Inline examples** (in the markdown itself): +- **Usage section**: Always inline - shows the API surface (1-3 lines of just the syntax) +- **Examples section**: One-liners demonstrating common patterns without test boilerplate + +````markdown +## Usage + +```csharp +Is.Null +Is.Not.Null +``` + +## Examples + +```csharp +Assert.That(myObject, Is.Null); +Assert.That(myString, Is.Not.Null); +Assert.That(GetResult(), Is.Null.Or.Empty); // Combined with other constraints +``` +```` + +**External snippets** (from Snippets.NUnit): +- Complex scenarios requiring setup code (custom comparers, test data, helper classes) +- Full compilable test methods that verify the documentation is correct +- Scenarios where the setup/context is important to understand + +````markdown +### Using Custom Comparers + +[!code-csharp[EqualWithComparer](~/snippets/Snippets.NUnit/ConstraintExamples.cs#EqualWithComparer)] +```` + +**Never inline:** +- Full `[Test] public void...` methods - those go in external snippets +- Examples requiring helper classes or significant setup + +## UID Standardization + +All constraint UIDs should follow the pattern: `constraint-` + +Examples: +- `equalconstraint` → `constraint-equal` +- `nullconstraint` → `constraint-null` +- `greaterthanconstraint` → `constraint-greaterthan` + +## Workflow for Updating Constraint Documentation + +> **Repository Layout Assumption**: This workflow assumes you have cloned both repositories as siblings: +> - `/nunit/` - The NUnit framework source code ([nunit/nunit](https://github.com/nunit/nunit)) +> - `/docs/` - This documentation repository ([nunit/docs](https://github.com/nunit/docs)) +> +> Adjust paths below to match your local setup. + +### Step 1: Find the Source Code + +Search for the constraint class in the NUnit framework: + +```shell +# Find the constraint source file (adjust path to your nunit repo location) +grep -r "class Constraint" ../nunit/src/NUnitFramework/framework/Constraints --include="*.cs" +``` + +The source is typically at: +`/src/NUnitFramework/framework/Constraints/Constraint.cs` + +### Step 2: Analyze the Source Code + +From the source file, extract: +- Available syntax helpers (check `Is.cs`, `Does.cs`, `Has.cs`, `Contains.cs`) +- Modifier methods and their purposes +- Constructor parameters (for reference, not for documentation focus) +- Any special behaviors or edge cases from XML doc comments + +### Step 3: Check for Existing Unit Tests + +```shell +# Find unit tests for the constraint (adjust path to your nunit repo location) +grep -r "Constraint" ../nunit/src/NUnitFramework/tests --include="*.cs" +``` + +Unit tests provide good examples of usage patterns and edge cases. + +### Step 4: Update the Markdown Documentation + +Follow the template structure above. Key points: +- Lead with Usage section showing the fluent API +- Include inline examples for quick reference +- Add external snippet references for complex scenarios +- Document all available modifiers with brief descriptions + +### Step 5: Update or Create Snippet Examples + +If complex scenarios need external snippets, add them to: +`docs/snippets/Snippets.NUnit/ConstraintExamples.cs` + +Use regions to organize: + +```csharp +#region ConstraintExamples +[Test] +public void Constraint_WithCustomComparer() +{ + // Example with setup that's too complex for inline + var comparer = new MyCustomComparer(); + Assert.That(actual, Is.(expected).Using(comparer)); +} +#endregion +``` + +### Step 6: Build and Test + +Always verify the snippets compile and tests pass. From the docs repository root: + +```shell +# Build +dotnet build docs/snippets/Snippets.slnx + +# Run all tests +dotnet test docs/snippets/Snippets.slnx --no-build + +# Run specific constraint tests +dotnet test docs/snippets/Snippets.slnx --no-build --filter "FullyQualifiedName~ConstraintExamples" --verbosity normal +``` + +## Quality Checklist + +Before marking a constraint as done: + +- [ ] UID follows `constraint-` pattern +- [ ] Description is 2-3 sentences explaining purpose +- [ ] Usage section shows fluent API methods (inline, 1-3 lines) +- [ ] Modifiers section (if applicable) with brief descriptions +- [ ] Examples section with inline one-liners for common patterns +- [ ] External snippets for complex scenarios (custom comparers, setup-heavy) +- [ ] Examples have subsection headers if multiple scenarios exist +- [ ] Notes section for edge cases/important behaviors +- [ ] See Also links to related constraints +- [ ] Version info for features added after NUnit 3.0 + +## Common Constraint Patterns + +### Simple Constraints (no modifiers) +Examples: `NullConstraint`, `TrueConstraint`, `FalseConstraint`, `NaNConstraint` + +These need minimal documentation but should still have: +- Clear description +- Usage showing `Is.` and `Is.Not.` +- 2-3 inline examples + +### Comparison Constraints (with Using/Within modifiers) +Examples: `EqualConstraint`, `GreaterThanConstraint`, `LessThanConstraint` + +These need: +- Modifiers section documenting `.Using()` and `.Within()` variants +- Examples showing basic comparison and modifier usage +- External snippets for custom comparer scenarios + +### Collection Constraints (with collection-specific modifiers) +Examples: `CollectionEquivalentConstraint`, `UniqueItemsConstraint`, `AllItemsConstraint` + +These need: +- Modifiers section with `.IgnoreCase`, `.Using()`, `.UsingPropertiesComparer()` +- Examples showing different collection types +- Notes about element comparison behavior + +### String Constraints (with string-specific modifiers) +Examples: `StartsWithConstraint`, `SubstringConstraint`, `RegexConstraint` + +These need: +- Modifiers for `.IgnoreCase`, `.Using(StringComparison)`, `.Using(CultureInfo)` +- Examples showing case-sensitive and case-insensitive usage +- Notes about culture-specific behavior where applicable diff --git a/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.AreEqual.md b/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.AreEqual.md index ec9fddf7e..fa7562171 100644 --- a/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.AreEqual.md +++ b/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.AreEqual.md @@ -46,5 +46,5 @@ NUnit 3.0 adds the ability to compare generic collections and dictionaries. ## See Also -* [Equal Constraint](xref:equalconstraint) +* [Equal Constraint](xref:constraint-equal) * [DefaultFloatingPointTolerance Attribute](../../attributes/defaultfloatingpointtolerance.md) diff --git a/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.AreNotEqual.md b/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.AreNotEqual.md index cace3a4df..28099994f 100644 --- a/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.AreNotEqual.md +++ b/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.AreNotEqual.md @@ -20,4 +20,4 @@ See [Assert.AreEqual](Assert.AreEqual.md) for details of how NUnit performs equa ## See Also * [Assert.AreEqual](Assert.AreEqual.md) -* [Equal Constraint](xref:equalconstraint) +* [Equal Constraint](xref:constraint-equal) diff --git a/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.AreNotSame.md b/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.AreNotSame.md index 2e4e65d40..274b540a4 100644 --- a/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.AreNotSame.md +++ b/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.AreNotSame.md @@ -17,4 +17,4 @@ Assert.AreNotSame(object expected, object actual, ## See Also -* [SameAs Constraint](xref:sameasconstraint) +* [SameAs Constraint](xref:constraint-sameas) diff --git a/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.AreSame.md b/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.AreSame.md index 6074cd707..2153acd4d 100644 --- a/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.AreSame.md +++ b/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.AreSame.md @@ -17,4 +17,4 @@ Assert.AreSame(object expected, object actual, ## See Also -* [SameAs Constraint](xref:sameasconstraint) +* [SameAs Constraint](xref:constraint-sameas) diff --git a/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.Catch.md b/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.Catch.md index 0bfa6a419..e77d7610f 100644 --- a/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.Catch.md +++ b/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.Catch.md @@ -22,4 +22,4 @@ T Assert.Catch(TestDelegate code, * [Assert.CatchAsync](Assert.CatchAsync.md) * [Assert.Throws](Assert.Throws.md) * [Assert.ThrowsAsync](Assert.ThrowsAsync.md) -* [ThrowsConstraint](xref:throwsconstraint) +* [ThrowsConstraint](xref:constraint-throws) diff --git a/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.CatchAsync.md b/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.CatchAsync.md index 45ac80e59..4ae54c789 100644 --- a/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.CatchAsync.md +++ b/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.CatchAsync.md @@ -22,4 +22,4 @@ T Assert.CatchAsync(AsyncTestDelegate code, * [Assert.Catch](Assert.Catch.md) * [Assert.Throws](Assert.Throws.md) * [Assert.ThrowsAsync](Assert.ThrowsAsync.md) -* [ThrowsConstraint](xref:throwsconstraint) +* [ThrowsConstraint](xref:constraint-throws) diff --git a/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.DoesNotThrow.md b/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.DoesNotThrow.md index d8840519d..ef368d193 100644 --- a/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.DoesNotThrow.md +++ b/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.DoesNotThrow.md @@ -12,4 +12,4 @@ void Assert.DoesNotThrow(TestDelegate code, ## See Also * [Assert.Throws](Assert.Throws.md) -* [ThrowsConstraint](xref:throwsconstraint) +* [ThrowsConstraint](xref:constraint-throws) diff --git a/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.DoesNotThrowAsync.md b/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.DoesNotThrowAsync.md index 33d044241..bbcfec911 100644 --- a/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.DoesNotThrowAsync.md +++ b/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.DoesNotThrowAsync.md @@ -12,4 +12,4 @@ void Assert.DoesNotThrowAsync(AsyncTestDelegate code, ## See Also * [Assert.ThrowsAsync](Assert.ThrowsAsync.md) -* [ThrowsConstraint](xref:throwsconstraint) +* [ThrowsConstraint](xref:constraint-throws) diff --git a/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.Throws.md b/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.Throws.md index 9d582417e..ea7e3ccf5 100644 --- a/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.Throws.md +++ b/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.Throws.md @@ -82,4 +82,4 @@ Assert.Catch(code); * [Assert.Catch](Assert.Catch.md) * [Assert.CatchAsync](Assert.CatchAsync.md) * [Assert.ThrowsAsync](Assert.ThrowsAsync.md) -* [ThrowsConstraint](xref:throwsconstraint) +* [ThrowsConstraint](xref:constraint-throws) diff --git a/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.ThrowsAsync.md b/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.ThrowsAsync.md index 5dd61aee8..42abaad05 100644 --- a/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.ThrowsAsync.md +++ b/docs/articles/nunit/writing-tests/assertions/classic-assertions/Assert.ThrowsAsync.md @@ -35,4 +35,4 @@ additional verification of the exception. Note that you do not need to await the * [Assert.Catch](Assert.Catch.md) * [Assert.CatchAsync](Assert.CatchAsync.md) * [Assert.Throws](Assert.Throws.md) -* [ThrowsConstraint](xref:throwsconstraint) +* [ThrowsConstraint](xref:constraint-throws) diff --git a/docs/articles/nunit/writing-tests/constraints/AllItemsConstraint.md b/docs/articles/nunit/writing-tests/constraints/AllItemsConstraint.md index b58ab3e8b..1ea13bb94 100644 --- a/docs/articles/nunit/writing-tests/constraints/AllItemsConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/AllItemsConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-allitems +--- + # AllItems Constraint `AllItemsConstraint` applies a constraint to each item in an `IEnumerable`, succeeding only if all of them succeed. An diff --git a/docs/articles/nunit/writing-tests/constraints/AndConstraint.md b/docs/articles/nunit/writing-tests/constraints/AndConstraint.md index a294debe4..5684cc72c 100644 --- a/docs/articles/nunit/writing-tests/constraints/AndConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/AndConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-and +--- + # And Constraint `AndConstraint` combines two other constraints and succeeds only if they both succeed. diff --git a/docs/articles/nunit/writing-tests/constraints/AnyOfConstraint.md b/docs/articles/nunit/writing-tests/constraints/AnyOfConstraint.md index e19fe7560..32f47893f 100644 --- a/docs/articles/nunit/writing-tests/constraints/AnyOfConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/AnyOfConstraint.md @@ -1,10 +1,14 @@ +--- +uid: constraint-anyof +--- + # AnyOf Constraint `AnyOfConstraint` is used to determine whether a value is equal to any of the expected values. > [!NOTE] > Values provided must be as parameters to the method, not as e.g. a separate array. If you are instead looking -> to see if a collection contains a value, see the [SomeItems Constraint](xref:someitemsconstraint). +> to see if a collection contains a value, see the [SomeItems Constraint](xref:constraint-someitems). ## Constructor diff --git a/docs/articles/nunit/writing-tests/constraints/AssignableFromConstraint.md b/docs/articles/nunit/writing-tests/constraints/AssignableFromConstraint.md index 413971921..ec31c5a92 100644 --- a/docs/articles/nunit/writing-tests/constraints/AssignableFromConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/AssignableFromConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-assignablefrom +--- + # AssignableFrom Constraint `AssignableFromConstraint` tests that one type is assignable from another diff --git a/docs/articles/nunit/writing-tests/constraints/AssignableToConstraint.md b/docs/articles/nunit/writing-tests/constraints/AssignableToConstraint.md index 61c3bb4a9..c2ce32aac 100644 --- a/docs/articles/nunit/writing-tests/constraints/AssignableToConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/AssignableToConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-assignableto +--- + # AssignableTo Constraint `AssignableToConstraint` tests that one type is assignable to another diff --git a/docs/articles/nunit/writing-tests/constraints/AttributeConstraint.md b/docs/articles/nunit/writing-tests/constraints/AttributeConstraint.md index f574d41b6..15830f448 100644 --- a/docs/articles/nunit/writing-tests/constraints/AttributeConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/AttributeConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-attribute +--- + # Attribute Constraint `AttributeConstraint` tests for the existence of an attribute on a Type and then applies a constraint to that attribute. diff --git a/docs/articles/nunit/writing-tests/constraints/AttributeExistsConstraint.md b/docs/articles/nunit/writing-tests/constraints/AttributeExistsConstraint.md index 803458f6f..c97794478 100644 --- a/docs/articles/nunit/writing-tests/constraints/AttributeExistsConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/AttributeExistsConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-attributeexists +--- + # AttributeExists Constraint `AttributeExistsConstraint` tests for the existence of an attribute on a Type. diff --git a/docs/articles/nunit/writing-tests/constraints/BinarySerializableConstraint.md b/docs/articles/nunit/writing-tests/constraints/BinarySerializableConstraint.md index 66825abb0..4ca35d922 100644 --- a/docs/articles/nunit/writing-tests/constraints/BinarySerializableConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/BinarySerializableConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-binaryserializable +--- + # BinarySerializable Constraint `BinarySerializableConstraint` tests whether an object is serializable in binary format. diff --git a/docs/articles/nunit/writing-tests/constraints/CollectionEquivalentConstraint.md b/docs/articles/nunit/writing-tests/constraints/CollectionEquivalentConstraint.md index fa786a8c5..96640feab 100644 --- a/docs/articles/nunit/writing-tests/constraints/CollectionEquivalentConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/CollectionEquivalentConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-collectionequivalent +--- + # CollectionEquivalent Constraint `CollectionEquivalentConstraint` tests that two `IEnumerables` are equivalent - that they contain diff --git a/docs/articles/nunit/writing-tests/constraints/CollectionOrderedConstraint.md b/docs/articles/nunit/writing-tests/constraints/CollectionOrderedConstraint.md index bf77f8311..ec58b0a72 100644 --- a/docs/articles/nunit/writing-tests/constraints/CollectionOrderedConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/CollectionOrderedConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-collectionordered +--- + # CollectionOrdered Constraint `CollectionOrderedConstraint` tests that an `IEnumerable` is ordered. If the actual value passed does not implement diff --git a/docs/articles/nunit/writing-tests/constraints/CollectionSubsetConstraint.md b/docs/articles/nunit/writing-tests/constraints/CollectionSubsetConstraint.md index 3f42206cf..0455f1d00 100644 --- a/docs/articles/nunit/writing-tests/constraints/CollectionSubsetConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/CollectionSubsetConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-collectionsubset +--- + # CollectionSubset Constraint `CollectionSubsetConstraint` tests that one `IEnumerable` is a subset of another. If the actual value passed does not diff --git a/docs/articles/nunit/writing-tests/constraints/CollectionSupersetConstraint.md b/docs/articles/nunit/writing-tests/constraints/CollectionSupersetConstraint.md index e3b881ddd..7cb0482fd 100644 --- a/docs/articles/nunit/writing-tests/constraints/CollectionSupersetConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/CollectionSupersetConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-collectionsuperset +--- + # CollectionSuperset Constraint `CollectionSupersetConstraint` tests that one `IEnumerable` is a superset of another. If the actual value passed does diff --git a/docs/articles/nunit/writing-tests/constraints/DefaultConstraint.md b/docs/articles/nunit/writing-tests/constraints/DefaultConstraint.md index 947664526..04478783a 100644 --- a/docs/articles/nunit/writing-tests/constraints/DefaultConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/DefaultConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-default +--- + # DefaultConstraint `DefaultConstraint` tests that the actual value is the default value for the type. diff --git a/docs/articles/nunit/writing-tests/constraints/DelayedConstraint.md b/docs/articles/nunit/writing-tests/constraints/DelayedConstraint.md index e78f2308a..fb10baa46 100644 --- a/docs/articles/nunit/writing-tests/constraints/DelayedConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/DelayedConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-delayed +--- + # Delayed Constraint `DelayedConstraint` delays the application of another constraint until a certain diff --git a/docs/articles/nunit/writing-tests/constraints/DictionaryContainsKeyConstraint.md b/docs/articles/nunit/writing-tests/constraints/DictionaryContainsKeyConstraint.md index 6c3c202fa..b0b259306 100644 --- a/docs/articles/nunit/writing-tests/constraints/DictionaryContainsKeyConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/DictionaryContainsKeyConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-dictionarycontainskey +--- + # DictionaryContainsKey Constraint `DictionaryContainsKeyConstraint` is used to test whether a dictionary diff --git a/docs/articles/nunit/writing-tests/constraints/DictionaryContainsKeyValuePairConstraint.md b/docs/articles/nunit/writing-tests/constraints/DictionaryContainsKeyValuePairConstraint.md index 0e097a781..37a0306ee 100644 --- a/docs/articles/nunit/writing-tests/constraints/DictionaryContainsKeyValuePairConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/DictionaryContainsKeyValuePairConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-dictionarycontainskeyvaluepair +--- + # DictionaryContainsKeyValuePairConstraint Constraint `DictionaryContainsKeyValuePairConstraint` is used to test whether a dictionary diff --git a/docs/articles/nunit/writing-tests/constraints/DictionaryContainsValueConstraint.md b/docs/articles/nunit/writing-tests/constraints/DictionaryContainsValueConstraint.md index 624e30042..1f68f478e 100644 --- a/docs/articles/nunit/writing-tests/constraints/DictionaryContainsValueConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/DictionaryContainsValueConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-dictionarycontainsvalue +--- + # DictionaryContainsValue Constraint `DictionaryContainsValueConstraint` is used to test whether a dictionary diff --git a/docs/articles/nunit/writing-tests/constraints/EmptyCollectionConstraint.md b/docs/articles/nunit/writing-tests/constraints/EmptyCollectionConstraint.md index 6814d7636..dcc004ea4 100644 --- a/docs/articles/nunit/writing-tests/constraints/EmptyCollectionConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/EmptyCollectionConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-emptycollection +--- + # EmptyCollection Constraint The **EmptyCollectionConstraint** tests if a Collection or other `IEnumerable` is empty. An `ArgumentException` is diff --git a/docs/articles/nunit/writing-tests/constraints/EmptyConstraint.md b/docs/articles/nunit/writing-tests/constraints/EmptyConstraint.md index 335a36c5e..2e568f6d2 100644 --- a/docs/articles/nunit/writing-tests/constraints/EmptyConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/EmptyConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-empty +--- + # Empty Constraint `EmptyConstraint` tests that an object is an empty string, directory or collection. diff --git a/docs/articles/nunit/writing-tests/constraints/EmptyDirectoryConstraint.md b/docs/articles/nunit/writing-tests/constraints/EmptyDirectoryConstraint.md index 9df9b1828..1310766af 100644 --- a/docs/articles/nunit/writing-tests/constraints/EmptyDirectoryConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/EmptyDirectoryConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-emptydirectory +--- + # EmptyDirectory Constraint The `EmptyDirectoryConstraint` tests if a Directory is empty. diff --git a/docs/articles/nunit/writing-tests/constraints/EmptyStringConstraint.md b/docs/articles/nunit/writing-tests/constraints/EmptyStringConstraint.md index 8fc5bc39d..782bfccf2 100644 --- a/docs/articles/nunit/writing-tests/constraints/EmptyStringConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/EmptyStringConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-emptystring +--- + # EmptyString Constraint The `EmptyStringConstraint` tests if a string is empty. diff --git a/docs/articles/nunit/writing-tests/constraints/EndsWithConstraint.md b/docs/articles/nunit/writing-tests/constraints/EndsWithConstraint.md index e36bc4d7f..5c736cece 100644 --- a/docs/articles/nunit/writing-tests/constraints/EndsWithConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/EndsWithConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-endswith +--- + # EndsWith Constraint `EndsWithConstraint` tests for an ending string. diff --git a/docs/articles/nunit/writing-tests/constraints/EqualConstraint.md b/docs/articles/nunit/writing-tests/constraints/EqualConstraint.md index 1bf0c378a..600ab0d2f 100644 --- a/docs/articles/nunit/writing-tests/constraints/EqualConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/EqualConstraint.md @@ -1,5 +1,5 @@ --- -uid: equalconstraint +uid: constraint-equal --- # Equal Constraint diff --git a/docs/articles/nunit/writing-tests/constraints/ExactCountConstraint.md b/docs/articles/nunit/writing-tests/constraints/ExactCountConstraint.md index dbc3c65b0..d38763eac 100644 --- a/docs/articles/nunit/writing-tests/constraints/ExactCountConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/ExactCountConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-exactcount +--- + # ExactCount Constraint `ExactCountConstraint` has two functions. diff --git a/docs/articles/nunit/writing-tests/constraints/ExactTypeConstraint.md b/docs/articles/nunit/writing-tests/constraints/ExactTypeConstraint.md index f9884d586..6d357fe97 100644 --- a/docs/articles/nunit/writing-tests/constraints/ExactTypeConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/ExactTypeConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-exacttype +--- + # ExactType Constraint `ExactTypeConstraint` tests that an object is an exact Type. diff --git a/docs/articles/nunit/writing-tests/constraints/FalseConstraint.md b/docs/articles/nunit/writing-tests/constraints/FalseConstraint.md index e0a98da52..36f4defb5 100644 --- a/docs/articles/nunit/writing-tests/constraints/FalseConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/FalseConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-false +--- + # False Constraint `FalseConstraint` tests that a value is false. diff --git a/docs/articles/nunit/writing-tests/constraints/FileOrDirectoryExistsConstraint.md b/docs/articles/nunit/writing-tests/constraints/FileOrDirectoryExistsConstraint.md index 1a38e48c4..2cf9ccd75 100644 --- a/docs/articles/nunit/writing-tests/constraints/FileOrDirectoryExistsConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/FileOrDirectoryExistsConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-fileordirectoryexists +--- + # FileOrDirectoryExists Constraint `FileOrDirectoryExistsConstraint` tests that a File or Directory exists. @@ -18,8 +22,8 @@ Does.Not.Exist ## Modifiers ```csharp -IgnoreDirectories -IgnoreFiles +.IgnoreDirectories +.IgnoreFiles ``` ## Examples of Use diff --git a/docs/articles/nunit/writing-tests/constraints/GreaterThanConstraint.md b/docs/articles/nunit/writing-tests/constraints/GreaterThanConstraint.md index 7ba900675..c35a119b3 100644 --- a/docs/articles/nunit/writing-tests/constraints/GreaterThanConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/GreaterThanConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-greaterthan +--- + # GreaterThan Constraint `GreaterThanConstraint` tests that one value is greater than another. diff --git a/docs/articles/nunit/writing-tests/constraints/GreaterThanOrEqualConstraint.md b/docs/articles/nunit/writing-tests/constraints/GreaterThanOrEqualConstraint.md index 41a21b69d..15d44db3c 100644 --- a/docs/articles/nunit/writing-tests/constraints/GreaterThanOrEqualConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/GreaterThanOrEqualConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-greaterthanorequal +--- + # GreaterThanOrEqual Constraint `GreaterThanOrEqualConstraint` tests that one value is greater than or equal to another. diff --git a/docs/articles/nunit/writing-tests/constraints/InstanceOfTypeConstraint.md b/docs/articles/nunit/writing-tests/constraints/InstanceOfTypeConstraint.md index 984e7ebce..e31345da5 100644 --- a/docs/articles/nunit/writing-tests/constraints/InstanceOfTypeConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/InstanceOfTypeConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-instanceoftype +--- + # InstanceOfType Constraint `InstanceOfTypeConstraint` tests that an object is of the type supplied or a derived type. diff --git a/docs/articles/nunit/writing-tests/constraints/LessThanConstraint.md b/docs/articles/nunit/writing-tests/constraints/LessThanConstraint.md index a1cb41ff0..c51cf6a22 100644 --- a/docs/articles/nunit/writing-tests/constraints/LessThanConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/LessThanConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-lessthan +--- + # LessThan Constraint `LessThanConstraint` tests that one value is less than another. diff --git a/docs/articles/nunit/writing-tests/constraints/LessThanOrEqualConstraint.md b/docs/articles/nunit/writing-tests/constraints/LessThanOrEqualConstraint.md index 37c0d9742..636373251 100644 --- a/docs/articles/nunit/writing-tests/constraints/LessThanOrEqualConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/LessThanOrEqualConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-lessthanorequal +--- + # LessThanOrEqual Constraint `LessThanOrEqualConstraint` tests that one value is less than or equal to another. diff --git a/docs/articles/nunit/writing-tests/constraints/NaNConstraint.md b/docs/articles/nunit/writing-tests/constraints/NaNConstraint.md index f2b01d806..602a94130 100644 --- a/docs/articles/nunit/writing-tests/constraints/NaNConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/NaNConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-nan +--- + # NaN Constraint `NaNConstraint` tests that a value is floating-point NaN. diff --git a/docs/articles/nunit/writing-tests/constraints/NoItemConstraint.md b/docs/articles/nunit/writing-tests/constraints/NoItemConstraint.md index 82a6fff06..0817def8d 100644 --- a/docs/articles/nunit/writing-tests/constraints/NoItemConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/NoItemConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-noitem +--- + # NoItem Constraint `NoItemConstraint` applies a constraint to each item in a collection, succeeding only if all of them fail. An exception diff --git a/docs/articles/nunit/writing-tests/constraints/NotConstraint.md b/docs/articles/nunit/writing-tests/constraints/NotConstraint.md index 5d87d1157..0b4a1b6fe 100644 --- a/docs/articles/nunit/writing-tests/constraints/NotConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/NotConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-not +--- + # Not Constraint `NotConstraint` reverses the effect of another constraint. If the base constraint fails, NotConstraint succeeds. If the @@ -17,4 +21,4 @@ Is.Not... ## Examples of Use -[!code-csharp[NotConstraintExamples](~/snippets/Snippets.NUnit/ConstraintExamples.cs#PropertyConstraintExamples)] +[!code-csharp[NotConstraintExamples](~/snippets/Snippets.NUnit/ConstraintExamples.cs#NotConstraintExamples)] diff --git a/docs/articles/nunit/writing-tests/constraints/NullConstraint.md b/docs/articles/nunit/writing-tests/constraints/NullConstraint.md index 3fee6ae6a..247466e7c 100644 --- a/docs/articles/nunit/writing-tests/constraints/NullConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/NullConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-null +--- + # Null Constraint `NullConstraint` tests that a value is null. diff --git a/docs/articles/nunit/writing-tests/constraints/OrConstraint.md b/docs/articles/nunit/writing-tests/constraints/OrConstraint.md index 69334542f..4d6fb4c08 100644 --- a/docs/articles/nunit/writing-tests/constraints/OrConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/OrConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-or +--- + # Or Constraint `OrConstraint` combines two other constraints and succeeds if either of them succeeds. diff --git a/docs/articles/nunit/writing-tests/constraints/PropertyConstraint.md b/docs/articles/nunit/writing-tests/constraints/PropertyConstraint.md index 103fef947..572cdbb03 100644 --- a/docs/articles/nunit/writing-tests/constraints/PropertyConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/PropertyConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-property +--- + # Property Constraint `PropertyConstraint` tests for the existence of a named property on an object and then applies a constraint test to the diff --git a/docs/articles/nunit/writing-tests/constraints/PropertyExistsConstraint.md b/docs/articles/nunit/writing-tests/constraints/PropertyExistsConstraint.md index 416f524fe..d9b020388 100644 --- a/docs/articles/nunit/writing-tests/constraints/PropertyExistsConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/PropertyExistsConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-propertyexists +--- + # PropertyExists Constraint The `PropertyExistsConstraint` tests for the existence of a named property on an object. diff --git a/docs/articles/nunit/writing-tests/constraints/RangeConstraint.md b/docs/articles/nunit/writing-tests/constraints/RangeConstraint.md index b5008a481..bc1095cc6 100644 --- a/docs/articles/nunit/writing-tests/constraints/RangeConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/RangeConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-range +--- + # Range Constraint `RangeConstraint` tests that a value is in an (inclusive) range. diff --git a/docs/articles/nunit/writing-tests/constraints/RegexConstraint.md b/docs/articles/nunit/writing-tests/constraints/RegexConstraint.md index 08b7ebe02..a8037076d 100644 --- a/docs/articles/nunit/writing-tests/constraints/RegexConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/RegexConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-regex +--- + # RegexConstraint `RegexConstraint` tests that a pattern is matched. diff --git a/docs/articles/nunit/writing-tests/constraints/ReusableConstraint.md b/docs/articles/nunit/writing-tests/constraints/ReusableConstraint.md index 7b7e0dfb9..cedc032bf 100644 --- a/docs/articles/nunit/writing-tests/constraints/ReusableConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/ReusableConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-reusable +--- + # Reusable Constraint Normally constraints just work. However, attempting to reuse the diff --git a/docs/articles/nunit/writing-tests/constraints/SameAsConstraint.md b/docs/articles/nunit/writing-tests/constraints/SameAsConstraint.md index e41163fc1..cd38c388a 100644 --- a/docs/articles/nunit/writing-tests/constraints/SameAsConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/SameAsConstraint.md @@ -1,5 +1,5 @@ --- -uid: sameasconstraint +uid: constraint-sameas --- # SameAs Constraint diff --git a/docs/articles/nunit/writing-tests/constraints/SamePathConstraint.md b/docs/articles/nunit/writing-tests/constraints/SamePathConstraint.md index 857311cd2..f402469db 100644 --- a/docs/articles/nunit/writing-tests/constraints/SamePathConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/SamePathConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-samepath +--- + # SamePath Constraint `SamePathConstraint` tests that two paths are equivalent. diff --git a/docs/articles/nunit/writing-tests/constraints/SamePathOrUnderConstraint.md b/docs/articles/nunit/writing-tests/constraints/SamePathOrUnderConstraint.md index 402fdae7a..4a2b18ac6 100644 --- a/docs/articles/nunit/writing-tests/constraints/SamePathOrUnderConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/SamePathOrUnderConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-samepathorunder +--- + # SamePathOrUnder Constraint `SamePathOrUnderConstraint` tests that one path is equivalent to another path or that it is under it. diff --git a/docs/articles/nunit/writing-tests/constraints/SomeItemsConstraint.md b/docs/articles/nunit/writing-tests/constraints/SomeItemsConstraint.md index 10216d538..ca6807c09 100644 --- a/docs/articles/nunit/writing-tests/constraints/SomeItemsConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/SomeItemsConstraint.md @@ -1,5 +1,5 @@ --- -uid: someitemsconstraint +uid: constraint-someitems --- # SomeItems Constraint diff --git a/docs/articles/nunit/writing-tests/constraints/StartsWithConstraint.md b/docs/articles/nunit/writing-tests/constraints/StartsWithConstraint.md index 04e18611a..dd2e6fd7e 100644 --- a/docs/articles/nunit/writing-tests/constraints/StartsWithConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/StartsWithConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-startswith +--- + # StartsWith Constraint `StartsWithConstraint` tests for an initial string. diff --git a/docs/articles/nunit/writing-tests/constraints/SubPathConstraint.md b/docs/articles/nunit/writing-tests/constraints/SubPathConstraint.md index 3383cd677..9c9fdceba 100644 --- a/docs/articles/nunit/writing-tests/constraints/SubPathConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/SubPathConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-subpath +--- + # SubPath Constraint `SubPathConstraint` tests that one path is under another path. diff --git a/docs/articles/nunit/writing-tests/constraints/SubstringConstraint.md b/docs/articles/nunit/writing-tests/constraints/SubstringConstraint.md index b06f36ea3..b65cdd82a 100644 --- a/docs/articles/nunit/writing-tests/constraints/SubstringConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/SubstringConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-substring +--- + # Substring Constraint `SubstringConstraint` tests for a substring. diff --git a/docs/articles/nunit/writing-tests/constraints/ThrowsConstraint.md b/docs/articles/nunit/writing-tests/constraints/ThrowsConstraint.md index 00666ca45..d0f255350 100644 --- a/docs/articles/nunit/writing-tests/constraints/ThrowsConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/ThrowsConstraint.md @@ -1,5 +1,5 @@ --- -uid: throwsconstraint +uid: constraint-throws --- # Throws Constraint diff --git a/docs/articles/nunit/writing-tests/constraints/ThrowsNothingConstraint.md b/docs/articles/nunit/writing-tests/constraints/ThrowsNothingConstraint.md index 1f536de66..b63b2af14 100644 --- a/docs/articles/nunit/writing-tests/constraints/ThrowsNothingConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/ThrowsNothingConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-throwsnothing +--- + # ThrowsNothing Constraint `ThrowsNothingConstraint` asserts that the delegate passed as its argument does not throw an exception. diff --git a/docs/articles/nunit/writing-tests/constraints/TrueConstraint.md b/docs/articles/nunit/writing-tests/constraints/TrueConstraint.md index 1e0224559..d55095a02 100644 --- a/docs/articles/nunit/writing-tests/constraints/TrueConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/TrueConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-true +--- + # True Constraint `TrueConstraint` tests that a value is true. diff --git a/docs/articles/nunit/writing-tests/constraints/UniqueItemsConstraint.md b/docs/articles/nunit/writing-tests/constraints/UniqueItemsConstraint.md index b0f4220db..55f0e2e01 100644 --- a/docs/articles/nunit/writing-tests/constraints/UniqueItemsConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/UniqueItemsConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-uniqueitems +--- + # UniqueItems Constraint **UniqueItemsConstraint** tests that an array, collection or other IEnumerable is composed diff --git a/docs/articles/nunit/writing-tests/constraints/WhiteSpaceConstraint.md b/docs/articles/nunit/writing-tests/constraints/WhiteSpaceConstraint.md index 030946b99..173e3615a 100644 --- a/docs/articles/nunit/writing-tests/constraints/WhiteSpaceConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/WhiteSpaceConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-whitespace +--- + # WhiteSpace Constraint The `WhiteSpaceConstraint` tests if a string contains only white-space. diff --git a/docs/articles/nunit/writing-tests/constraints/XmlSerializableConstraint.md b/docs/articles/nunit/writing-tests/constraints/XmlSerializableConstraint.md index d2cefd09d..a7ad8d1cf 100644 --- a/docs/articles/nunit/writing-tests/constraints/XmlSerializableConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/XmlSerializableConstraint.md @@ -1,3 +1,7 @@ +--- +uid: constraint-xmlserializable +--- + # XmlSerializable Constraint `XmlSerializableConstraint` tests whether an object is serializable in XML format. From b29e81282b0a0c8b365283a1c9644ff0cddd2914 Mon Sep 17 00:00:00 2001 From: Terje Sandstrom Date: Wed, 6 May 2026 21:35:39 +0200 Subject: [PATCH 02/11] Phase 2 constraints --- .claude/plans/constraints-improvement-plan.md | 17 ++-- .../CollectionEquivalentConstraint.md | 67 +++++++------ .../constraints/ContainsConstraint.md | 75 +++++++++++++++ .../constraints/FalseConstraint.md | 29 ++++-- .../constraints/GreaterThanConstraint.md | 49 ++++++---- .../constraints/LessThanConstraint.md | 49 ++++++---- .../constraints/NullConstraint.md | 29 ++++-- .../constraints/ThrowsConstraint.md | 95 +++++++++++-------- .../constraints/TrueConstraint.md | 27 ++++-- .../nunit/writing-tests/constraints/toc.yml | 2 + 10 files changed, 306 insertions(+), 133 deletions(-) create mode 100644 docs/articles/nunit/writing-tests/constraints/ContainsConstraint.md diff --git a/.claude/plans/constraints-improvement-plan.md b/.claude/plans/constraints-improvement-plan.md index dac8a8564..9612c2494 100644 --- a/.claude/plans/constraints-improvement-plan.md +++ b/.claude/plans/constraints-improvement-plan.md @@ -218,11 +218,12 @@ Proposed: Keep single file but ensure: ### Phase 2: Priority 1 Constraints | Constraint | Status | Notes | |------------|--------|-------| -| EqualConstraint | Pending | | -| NullConstraint | Pending | | -| TrueConstraint | Pending | | -| FalseConstraint | Pending | | -| GreaterThanConstraint | Pending | | -| LessThanConstraint | Pending | | -| ThrowsConstraint | Pending | | -| CollectionEquivalentConstraint | Pending | | +| EqualConstraint | Complete | Already excellent - UID fixed | +| NullConstraint | Complete | Full rewrite with inline examples | +| TrueConstraint | Complete | Full rewrite with inline examples | +| FalseConstraint | Complete | Full rewrite with inline examples | +| GreaterThanConstraint | Complete | Restructured with Usage section, inline examples | +| LessThanConstraint | Complete | Restructured with Usage section, inline examples | +| ThrowsConstraint | Complete | Added modifiers section, inline examples | +| ContainsConstraint | Complete | **NEW** - Created doc explaining routing behavior | +| CollectionEquivalentConstraint | Complete | Restructured with better examples | diff --git a/docs/articles/nunit/writing-tests/constraints/CollectionEquivalentConstraint.md b/docs/articles/nunit/writing-tests/constraints/CollectionEquivalentConstraint.md index 96640feab..07896d738 100644 --- a/docs/articles/nunit/writing-tests/constraints/CollectionEquivalentConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/CollectionEquivalentConstraint.md @@ -4,48 +4,59 @@ uid: constraint-collectionequivalent # CollectionEquivalent Constraint -`CollectionEquivalentConstraint` tests that two `IEnumerables` are equivalent - that they contain -the same items, in any order. If the actual value passed does not implement `IEnumerable` an exception is thrown. +`CollectionEquivalentConstraint` tests that two `IEnumerables` are equivalent - that they contain the same items, in any +order. Two collections are equivalent if they have the same number of elements and every element in one collection has a +matching element in the other. -## Constructor +## Usage ```csharp -CollectionEquivalentConstraint(IEnumerable other) +Is.EquivalentTo(IEnumerable expected) +Is.Not.EquivalentTo(IEnumerable expected) ``` -## Syntax +## Modifiers ```csharp -Is.EquivalentTo(IEnumerable other) +.IgnoreCase +.IgnoreWhiteSpace // From version 4.2 +.Using(IEqualityComparer comparer) +.Using(IComparer comparer) +.Using(IEqualityComparer comparer) +.Using(IComparer comparer) +.Using(Comparison comparer) +.Using(Func comparer) +.UsingPropertiesComparer() // From version 4.1 ``` -## Modifiers +## Examples ```csharp -...IgnoreCase -...IgnoreWhiteSpace // From version 4.2 -...Using(IEqualityComparer comparer) -...Using(IComparer comparer) -...Using(IEqualityComparer comparer) -...Using(IComparer comparer) -...Using(Comparison comparer) -...Using(Func comparer) -...Using(Func comparison) -...UsingPropertiesComparer() // From version 4.1 -...UsingPropertiesComparer( - Func configure) // From version 4.4 -``` +// Basic equivalence - order doesn't matter +int[] expected = { 1, 2, 3 }; +Assert.That(new[] { 3, 1, 2 }, Is.EquivalentTo(expected)); -## Examples of Use +// Not equivalent - different counts matter +Assert.That(new[] { 1, 2, 2 }, Is.Not.EquivalentTo(expected)); -```csharp -int[] iarray = new int[] { 1, 2, 3 }; -string[] sarray = new string[] { "a", "b", "c" }; -Assert.That(new string[] { "c", "a", "b" }, Is.EquivalentTo(sarray)); -Assert.That(new int[] { 1, 2, 2 }, Is.Not.EquivalentTo(iarray)); +// String comparison with case insensitivity +string[] names = { "Alice", "Bob", "Charlie" }; +Assert.That(new[] { "alice", "BOB", "CHARLIE" }, Is.EquivalentTo(names).IgnoreCase); + +// With custom comparer for complex objects +Assert.That(actualPeople, Is.EquivalentTo(expectedPeople).UsingPropertiesComparer()); ``` ## Notes -1. To compare items in order, use Is.EqualTo(). +1. To compare items in a specific order, use `Is.EqualTo()` instead. +2. Duplicate items matter: `{1, 2, 2}` is not equivalent to `{1, 2, 3}` even though they have the same length. +3. The constraint checks that each item in one collection has exactly one matching item in the other, accounting for + duplicates correctly. + +## See Also + +* [Equal Constraint](EqualConstraint.md) - For ordered comparison +* [CollectionSubset Constraint](CollectionSubsetConstraint.md) +* [CollectionSuperset Constraint](CollectionSupersetConstraint.md) +* [AllItems Constraint](AllItemsConstraint.md) diff --git a/docs/articles/nunit/writing-tests/constraints/ContainsConstraint.md b/docs/articles/nunit/writing-tests/constraints/ContainsConstraint.md new file mode 100644 index 000000000..47898b117 --- /dev/null +++ b/docs/articles/nunit/writing-tests/constraints/ContainsConstraint.md @@ -0,0 +1,75 @@ +--- +uid: constraint-contains +--- + +# Contains Constraint + +`ContainsConstraint` is a smart constraint that adapts its behavior based on the type being tested. When the actual +value is a string, it tests for a substring. When the actual value is a collection, it tests for item membership. + +## Usage + +```csharp +Does.Contain(object expected) +Does.Not.Contain(object expected) +``` + +## Modifiers + +```csharp +.IgnoreCase // Case-insensitive matching +.IgnoreWhiteSpace // Ignore whitespace differences (collections only) +.IgnoreLineEndingFormat // Ignore line ending differences (collections only) +``` + +## Examples + +### String Containment + +When the actual value is a string, `Does.Contain` tests for a substring: + +```csharp +Assert.That("Hello World", Does.Contain("World")); +Assert.That("Hello World", Does.Contain("world").IgnoreCase); +Assert.That("Hello World", Does.Not.Contain("Goodbye")); +``` + +### Collection Membership + +When the actual value is a collection, `Does.Contain` tests for item membership: + +```csharp +int[] numbers = { 1, 2, 3, 4, 5 }; +Assert.That(numbers, Does.Contain(3)); +Assert.That(numbers, Does.Not.Contain(99)); + +string[] names = { "Alice", "Bob", "Charlie" }; +Assert.That(names, Does.Contain("Bob")); +Assert.That(names, Does.Contain("bob").IgnoreCase); +``` + +## How It Works + +`ContainsConstraint` defers its behavior until the actual value's type is known: + +| Actual Type | Behavior | +|-------------|----------| +| `string` | Uses [SubstringConstraint](SubstringConstraint.md) to test for substring | +| Collection/IEnumerable | Uses [SomeItemsConstraint](SomeItemsConstraint.md) to test for item presence | + +## Notes + +1. When testing strings, the expected value must also be a string. For type safety, consider using + `Does.Contain(string)` explicitly. +2. The `.IgnoreWhiteSpace` and `.IgnoreLineEndingFormat` modifiers only work with collections, not strings. Using them + with string containment will throw an `InvalidOperationException`. +3. For more explicit control, use the specific constraints directly: + - [SubstringConstraint](SubstringConstraint.md) for string containment + - [SomeItemsConstraint](SomeItemsConstraint.md) for collection membership + +## See Also + +* [Substring Constraint](SubstringConstraint.md) +* [SomeItems Constraint](SomeItemsConstraint.md) +* [DictionaryContainsKey Constraint](DictionaryContainsKeyConstraint.md) +* [DictionaryContainsValue Constraint](DictionaryContainsValueConstraint.md) diff --git a/docs/articles/nunit/writing-tests/constraints/FalseConstraint.md b/docs/articles/nunit/writing-tests/constraints/FalseConstraint.md index 36f4defb5..d6c03f84c 100644 --- a/docs/articles/nunit/writing-tests/constraints/FalseConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/FalseConstraint.md @@ -4,22 +4,33 @@ uid: constraint-false # False Constraint -`FalseConstraint` tests that a value is false. +`FalseConstraint` tests that a value is `false`. Use this constraint when asserting that a boolean condition or +expression evaluates to `false`. -## Constructor +## Usage ```csharp -FalseConstraint() +Is.False +Is.Not.False // equivalent to Is.True ``` -## Syntax +## Examples ```csharp -Is.False +Assert.That(2 + 2 == 5, Is.False); +Assert.That(isDisabled, Is.False); +Assert.That(list.IsReadOnly, Is.False); + +// With nullable booleans +bool? isDeleted = false; +Assert.That(isDeleted, Is.False); ``` -## Example of Use +## Notes -```csharp -Assert.That(condition, Is.False); -``` +1. `Is.Not.False` is equivalent to `Is.True` for non-nullable booleans. +2. For nullable booleans (`bool?`), `Is.False` only passes when the value is exactly `false`, not when it's `null`. + +## See Also + +* [True Constraint](TrueConstraint.md) diff --git a/docs/articles/nunit/writing-tests/constraints/GreaterThanConstraint.md b/docs/articles/nunit/writing-tests/constraints/GreaterThanConstraint.md index c35a119b3..c8c2bcd0e 100644 --- a/docs/articles/nunit/writing-tests/constraints/GreaterThanConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/GreaterThanConstraint.md @@ -4,34 +4,51 @@ uid: constraint-greaterthan # GreaterThan Constraint -`GreaterThanConstraint` tests that one value is greater than another. +`GreaterThanConstraint` tests that one value is greater than another. It works with numeric types, `DateTime`, +`TimeSpan`, and any type implementing `IComparable`. For custom types, a user-specified comparer can be provided using +the `Using` modifier. -It works with numeric types, `DateTime`, `TimeSpan`, and any type implementing `IComparable`. For custom types, a -user-specified comparer can be provided using the `Using` modifier. - -## Constructor +## Usage ```csharp -GreaterThanConstraint(object expected) +Is.GreaterThan(object expected) +Is.Positive // Equivalent to Is.GreaterThan(0) ``` -## Syntax +## Modifiers ```csharp -Is.GreaterThan(object expected) -Is.Positive // Equivalent to Is.GreaterThan(0) +.Using(IComparer comparer) +.Using(IComparer comparer) +.Using(Comparison comparer) +.Within(object tolerance) ``` -## Modifiers +## Examples ```csharp -...Using(IComparer comparer) -...Using(IComparer comparer) -...Using(Comparison comparer) -...Within(object tolerance) +Assert.That(7, Is.GreaterThan(3)); +Assert.That(5, Is.Positive); +Assert.That(-3, Is.Not.Positive); + +// With DateTime +Assert.That(DateTime.Now, Is.GreaterThan(DateTime.Today)); + +// With tolerance +Assert.That(10.5, Is.GreaterThan(10.0).Within(0.1)); ``` -## Examples of Use +### Using Custom Comparers -[!code-csharp[GreaterThanExamples](~/snippets/Snippets.NUnit/ConstraintExamples.cs#GreaterThanExamples)] [!code-csharp[With Comparer](~/snippets/Snippets.NUnit/ConstraintExamples.cs#MyComparerExample)] + +## Notes + +1. When comparing floating-point numbers, consider using `.Within()` to specify a tolerance. +2. `Is.Positive` is a convenience shorthand for `Is.GreaterThan(0)`. + +## See Also + +* [LessThan Constraint](LessThanConstraint.md) +* [GreaterThanOrEqual Constraint](GreaterThanOrEqualConstraint.md) +* [Range Constraint](RangeConstraint.md) diff --git a/docs/articles/nunit/writing-tests/constraints/LessThanConstraint.md b/docs/articles/nunit/writing-tests/constraints/LessThanConstraint.md index c51cf6a22..8dae48f1d 100644 --- a/docs/articles/nunit/writing-tests/constraints/LessThanConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/LessThanConstraint.md @@ -4,34 +4,51 @@ uid: constraint-lessthan # LessThan Constraint -`LessThanConstraint` tests that one value is less than another. +`LessThanConstraint` tests that one value is less than another. It works with numeric types, `DateTime`, `TimeSpan`, and +any type implementing `IComparable`. For custom types, a user-specified comparer can be provided using the `Using` +modifier. -It works with numeric types, `DateTime`, `TimeSpan`, and any type implementing `IComparable`. For custom types, a -user-specified comparer can be provided using the `Using` modifier. - -## Constructor +## Usage ```csharp -LessThanConstraint(object expected) +Is.LessThan(object expected) +Is.Negative // Equivalent to Is.LessThan(0) ``` -## Syntax +## Modifiers ```csharp -Is.LessThan(object expected) -Is.Negative // Equivalent to Is.LessThan(0) +.Using(IComparer comparer) +.Using(IComparer comparer) +.Using(Comparison comparer) +.Within(object tolerance) ``` -## Modifiers +## Examples ```csharp -...Using(IComparer comparer) -...Using(IComparer comparer) -...Using(Comparison comparer) -...Within(object tolerance) +Assert.That(3, Is.LessThan(7)); +Assert.That(-5, Is.Negative); +Assert.That(5, Is.Not.Negative); + +// With DateTime +Assert.That(DateTime.Today, Is.LessThan(DateTime.Now)); + +// With tolerance +Assert.That(9.5, Is.LessThan(10.0).Within(0.1)); ``` -## Examples of Use +### Using Custom Comparers -[!code-csharp[LessThanExamples](~/snippets/Snippets.NUnit/ConstraintExamples.cs#LessThanExamples)] [!code-csharp[With Comparer](~/snippets/Snippets.NUnit/ConstraintExamples.cs#MyComparerExample)] + +## Notes + +1. When comparing floating-point numbers, consider using `.Within()` to specify a tolerance. +2. `Is.Negative` is a convenience shorthand for `Is.LessThan(0)`. + +## See Also + +* [GreaterThan Constraint](GreaterThanConstraint.md) +* [LessThanOrEqual Constraint](LessThanOrEqualConstraint.md) +* [Range Constraint](RangeConstraint.md) diff --git a/docs/articles/nunit/writing-tests/constraints/NullConstraint.md b/docs/articles/nunit/writing-tests/constraints/NullConstraint.md index 247466e7c..03025e95f 100644 --- a/docs/articles/nunit/writing-tests/constraints/NullConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/NullConstraint.md @@ -4,20 +4,35 @@ uid: constraint-null # Null Constraint -`NullConstraint` tests that a value is null. +`NullConstraint` tests that a value is `null`. This is one of the most commonly used constraints for verifying that +references have not been assigned or have been explicitly set to `null`. -## Constructor +## Usage ```csharp -NullConstraint() +Is.Null +Is.Not.Null ``` -## Syntax +## Examples ```csharp -Is.Null +object? obj = null; +Assert.That(obj, Is.Null); + +string? name = GetName(); +Assert.That(name, Is.Not.Null); + +// Combining with other constraints +Assert.That(result, Is.Not.Null.And.Not.Empty); +Assert.That(GetOptionalValue(), Is.Null.Or.GreaterThan(0)); ``` -## Examples of Use +## Notes + +1. For value types, consider using `Is.Default` instead, which tests for the default value of the type. +2. When testing nullable value types (`int?`, `bool?`, etc.), `Is.Null` works as expected. + +## See Also -[!code-csharp[NullConstraintExamples](~/snippets/Snippets.NUnit/ConstraintExamples.cs#NullConstraintExamples)] +* [Default Constraint](DefaultConstraint.md) diff --git a/docs/articles/nunit/writing-tests/constraints/ThrowsConstraint.md b/docs/articles/nunit/writing-tests/constraints/ThrowsConstraint.md index d0f255350..184b448de 100644 --- a/docs/articles/nunit/writing-tests/constraints/ThrowsConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/ThrowsConstraint.md @@ -4,60 +4,71 @@ uid: constraint-throws # Throws Constraint -`ThrowsConstraint` is used to test that some code, represented as a delegate, -throws a particular exception. It may be used alone, to merely test the type -of constraint, or with an additional constraint to be applied to the exception -specified as an argument. +`ThrowsConstraint` is used to test that code, represented as a delegate, throws a particular exception. It may be used +alone to test the exception type, or with additional constraints applied to the exception itself. The related +[ThrowsNothingConstraint](ThrowsNothingConstraint.md) asserts that the delegate does not throw. -The related [ThrowsNothingConstraint](ThrowsNothingConstraint.md) simply asserts that the delegate -does not throw an exception. +## Usage -## Constructors +```csharp +Throws.Exception +Throws.TypeOf() +Throws.TypeOf(Type expectedType) +Throws.InstanceOf() +Throws.InstanceOf(Type expectedType) + +// Common exception shortcuts +Throws.ArgumentException +Throws.ArgumentNullException +Throws.InvalidOperationException +Throws.TargetInvocationException + +// For testing nothing is thrown +Throws.Nothing +``` + +## Modifiers ```csharp -ThrowsConstraint(Type expectedType) -ThrowsConstraint() -ThrowsConstraint(Type expectedType, Constraint constraint) -ThrowsConstraint(Constraint constraint) +.With.Message.EqualTo(string) // Test exception message +.With.Message.Contains(string) // Test message contains substring +.With.Property("Name").EqualTo(x) // Test exception property +.With.InnerException.TypeOf() // Test inner exception ``` -## Syntax +## Examples ```csharp -Throws.Exception -Throws.TargetInvocationException -Throws.ArgumentException -Throws.ArgumentNullException -Throws.InvalidOperationException -Throws.TypeOf(Type expectedType) -Throws.TypeOf() -Throws.InstanceOf(Type expectedType) -Throws.InstanceOf() -Throws.InnerException +// Test for specific exception type +Assert.That(() => MethodThatThrows(), Throws.TypeOf()); +Assert.That(() => MethodThatThrows(), Throws.InstanceOf()); + +// Test exception message +Assert.That(() => throw new ArgumentException("bad value"), + Throws.ArgumentException.With.Message.EqualTo("bad value")); + +// Test with lambda expression +Assert.That(() => int.Parse("abc"), Throws.TypeOf()); + +// Assert no exception is thrown +Assert.That(() => SafeMethod(), Throws.Nothing); ``` -## Examples of Use +### Additional Examples [!code-csharp[ThrowsConstraintExamples](~/snippets/Snippets.NUnit/ConstraintExamples.cs#ThrowsConstraintExamples)] ## Notes -1. **Throws.Exception** may be followed by further constraints, - which are applied to the exception itself as shown in the last two - examples above. It may also be used alone to verify that some - exception has been thrown, without regard to type. This is - not a recommended practice since you should normally know - what exception you are expecting. - -2. **Throws.TypeOf** and **Throws.InstanceOf** are provided - as a shorter syntax for this common test. They work exactly like - the corresponding forms following **Throws.Exception**. - -3. **Throws.TargetInvocationException**, **Throws.ArgumentException** - and **Throws.InvalidOperationException** provide a shortened form - for some common exceptions. - -4. Used alone, **Throws.InnerException** simply tests the InnerException - value of the thrown exception. More commonly, it will be used in - combination with a test for the type of the outer exception as shown - in the examples above. +1. **Throws.TypeOf** requires an exact type match. Use **Throws.InstanceOf** to allow derived exception types. +2. **Throws.Exception** can be followed by additional constraints on the exception object. Avoid using it alone without + type checking, as you should generally know what exception to expect. +3. For async code, use `Assert.ThrowsAsync` or test the async delegate directly with `Throws`. +4. **Throws.InnerException** tests the InnerException property. Combine it with outer exception type tests for full + validation. + +## See Also + +* [ThrowsNothing Constraint](ThrowsNothingConstraint.md) +* [Assert.Throws](xref:classicassertthrows) +* [Assert.ThrowsAsync](xref:classicassertthrowsasync) diff --git a/docs/articles/nunit/writing-tests/constraints/TrueConstraint.md b/docs/articles/nunit/writing-tests/constraints/TrueConstraint.md index d55095a02..0b97bec7f 100644 --- a/docs/articles/nunit/writing-tests/constraints/TrueConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/TrueConstraint.md @@ -4,20 +4,33 @@ uid: constraint-true # True Constraint -`TrueConstraint` tests that a value is true. +`TrueConstraint` tests that a value is `true`. Use this constraint when asserting boolean conditions or the result of +boolean expressions. -## Constructor +## Usage ```csharp -TrueConstraint() +Is.True +Is.Not.True // equivalent to Is.False ``` -## Syntax +## Examples ```csharp -Is.True +Assert.That(2 + 2 == 4, Is.True); +Assert.That(isValid, Is.True); +Assert.That(list.Contains(item), Is.True); + +// With nullable booleans +bool? hasValue = true; +Assert.That(hasValue, Is.True); ``` -## Example of Use +## Notes + +1. `Is.Not.True` is equivalent to `Is.False` for non-nullable booleans. +2. For nullable booleans (`bool?`), `Is.True` only passes when the value is exactly `true`, not when it's `null`. + +## See Also -[!code-csharp[TrueConstraintExamples](~/snippets/Snippets.NUnit/ConstraintExamples.cs#TrueConstraintExamples)] +* [False Constraint](FalseConstraint.md) diff --git a/docs/articles/nunit/writing-tests/constraints/toc.yml b/docs/articles/nunit/writing-tests/constraints/toc.yml index c6d90e253..4e106fa2a 100644 --- a/docs/articles/nunit/writing-tests/constraints/toc.yml +++ b/docs/articles/nunit/writing-tests/constraints/toc.yml @@ -24,6 +24,8 @@ href: CollectionSubsetConstraint.md - name: CollectionSupersetConstraint href: CollectionSupersetConstraint.md +- name: ContainsConstraint + href: ContainsConstraint.md - name: DefaultConstraint href: DefaultConstraint.md - name: DelayedConstraint From ece27d9fd41699552088fe4825cdcf316d9eb9d7 Mon Sep 17 00:00:00 2001 From: Terje Sandstrom Date: Wed, 6 May 2026 21:40:21 +0200 Subject: [PATCH 03/11] Phase 2 constraints --- .../constraints/ContainsConstraint.md | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/docs/articles/nunit/writing-tests/constraints/ContainsConstraint.md b/docs/articles/nunit/writing-tests/constraints/ContainsConstraint.md index 47898b117..332d601d1 100644 --- a/docs/articles/nunit/writing-tests/constraints/ContainsConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/ContainsConstraint.md @@ -17,11 +17,15 @@ Does.Not.Contain(object expected) ## Modifiers ```csharp -.IgnoreCase // Case-insensitive matching -.IgnoreWhiteSpace // Ignore whitespace differences (collections only) -.IgnoreLineEndingFormat // Ignore line ending differences (collections only) +.IgnoreCase // Case-insensitive matching (strings and collections) +.IgnoreWhiteSpace // Ignore whitespace in item equality (collections only) +.IgnoreLineEndingFormat // Ignore line endings in item equality (collections only) ``` +> [!NOTE] +> `.IgnoreWhiteSpace` and `.IgnoreLineEndingFormat` only work when testing collection membership, not substring +> containment. For strings, these modifiers throw an `InvalidOperationException`. + ## Examples ### String Containment @@ -61,9 +65,15 @@ Assert.That(names, Does.Contain("bob").IgnoreCase); 1. When testing strings, the expected value must also be a string. For type safety, consider using `Does.Contain(string)` explicitly. -2. The `.IgnoreWhiteSpace` and `.IgnoreLineEndingFormat` modifiers only work with collections, not strings. Using them - with string containment will throw an `InvalidOperationException`. -3. For more explicit control, use the specific constraints directly: +2. **Important**: `.IgnoreWhiteSpace` and `.IgnoreLineEndingFormat` only work with collections, not strings. When used + with string containment, they throw `InvalidOperationException`. This is because `SubstringConstraint` doesn't + support these modifiers, while `EqualConstraint` (used for collection item comparison) does. +3. For collections of strings, `.IgnoreWhiteSpace` affects item equality comparison: + ```csharp + // Works: checks if any item equals "hello world" ignoring whitespace + Assert.That(new[] { "hello world" }, Does.Contain("hello world").IgnoreWhiteSpace); + ``` +4. For more explicit control, use the specific constraints directly: - [SubstringConstraint](SubstringConstraint.md) for string containment - [SomeItemsConstraint](SomeItemsConstraint.md) for collection membership From f01a78a92e5651d4dcbd2c5e210d3d79ab076387 Mon Sep 17 00:00:00 2001 From: Terje Sandstrom Date: Thu, 7 May 2026 17:07:56 +0200 Subject: [PATCH 04/11] improvements constraints --- .claude/plans/constraints-improvement-plan.md | 60 +++++ .../constraints/AllItemsConstraint.md | 35 ++- .../constraints/AndConstraint.md | 31 +-- .../constraints/AnyOfConstraint.md | 54 ++-- .../constraints/AssignableFromConstraint.md | 30 ++- .../constraints/AssignableToConstraint.md | 30 ++- .../constraints/AsyncConstraints.md | 131 ++++++++++ .../constraints/AttributeConstraint.md | 32 ++- .../constraints/AttributeExistsConstraint.md | 28 ++- .../CollectionOrderedConstraint.md | 84 +++---- .../constraints/CollectionSubsetConstraint.md | 48 ++-- .../CollectionSupersetConstraint.md | 49 ++-- .../writing-tests/constraints/Constraints.md | 11 + .../constraints/ContainsConstraint.md | 16 +- .../constraints/ContainsHelper.md | 126 ++++++++++ .../constraints/DelayedConstraint.md | 51 ++-- .../DictionaryContainsKeyConstraint.md | 55 ++-- ...ictionaryContainsKeyValuePairConstraint.md | 66 +++-- .../DictionaryContainsValueConstraint.md | 56 ++--- .../constraints/EmptyCollectionConstraint.md | 32 +-- .../constraints/EmptyDirectoryConstraint.md | 29 ++- .../constraints/EmptyStringConstraint.md | 32 +-- .../constraints/EndsWithConstraint.md | 38 ++- .../constraints/ExactCountConstraint.md | 49 ++-- .../constraints/ExactTypeConstraint.md | 25 +- .../constraints/FalseConstraint.md | 10 +- .../FileOrDirectoryExistsConstraint.md | 30 ++- .../constraints/GreaterThanConstraint.md | 12 +- .../GreaterThanOrEqualConstraint.md | 43 ++-- .../constraints/InstanceOfTypeConstraint.md | 27 +- .../constraints/LessThanConstraint.md | 12 +- .../constraints/LessThanOrEqualConstraint.md | 43 ++-- .../constraints/MultipleOfConstraint.md | 32 +++ .../constraints/NaNConstraint.md | 26 +- .../constraints/NoItemConstraint.md | 32 +-- .../constraints/NotConstraint.md | 27 +- .../constraints/NullConstraint.md | 12 +- .../writing-tests/constraints/OrConstraint.md | 32 ++- .../constraints/PropertyConstraint.md | 43 ++-- .../constraints/PropertyExistsConstraint.md | 24 +- .../constraints/RangeConstraint.md | 36 ++- .../constraints/RegexConstraint.md | 39 ++- .../constraints/SameAsConstraint.md | 32 ++- .../constraints/SamePathConstraint.md | 8 +- .../constraints/SamePathOrUnderConstraint.md | 9 +- .../constraints/SomeItemsConstraint.md | 66 +++-- .../constraints/StartsWithConstraint.md | 44 ++-- .../constraints/SubPathConstraint.md | 8 +- .../constraints/SubstringConstraint.md | 39 +-- .../constraints/ThrowsConstraint.md | 16 +- .../constraints/ThrowsNothingConstraint.md | 24 +- .../constraints/TrueConstraint.md | 10 +- .../constraints/UniqueItemsConstraint.md | 49 ++-- .../constraints/WhiteSpaceConstraint.md | 36 +-- .../nunit/writing-tests/constraints/toc.yml | 6 + .../CollectionConstraintSnippets.cs | 237 ++++++++++++++++++ .../ComparisonConstraintSnippets.cs | 188 ++++++++++++++ .../Constraints/CompoundConstraintSnippets.cs | 103 ++++++++ .../DictionaryConstraintSnippets.cs | 99 ++++++++ .../Constraints/PathConstraintSnippets.cs | 43 ++++ .../Constraints/SpecialConstraintSnippets.cs | 236 +++++++++++++++++ .../Constraints/StringConstraintSnippets.cs | 129 ++++++++++ .../Constraints/TypeConstraintSnippets.cs | 125 +++++++++ 63 files changed, 2283 insertions(+), 902 deletions(-) create mode 100644 docs/articles/nunit/writing-tests/constraints/AsyncConstraints.md create mode 100644 docs/articles/nunit/writing-tests/constraints/ContainsHelper.md create mode 100644 docs/articles/nunit/writing-tests/constraints/MultipleOfConstraint.md create mode 100644 docs/snippets/Snippets.NUnit/Constraints/CollectionConstraintSnippets.cs create mode 100644 docs/snippets/Snippets.NUnit/Constraints/ComparisonConstraintSnippets.cs create mode 100644 docs/snippets/Snippets.NUnit/Constraints/CompoundConstraintSnippets.cs create mode 100644 docs/snippets/Snippets.NUnit/Constraints/DictionaryConstraintSnippets.cs create mode 100644 docs/snippets/Snippets.NUnit/Constraints/PathConstraintSnippets.cs create mode 100644 docs/snippets/Snippets.NUnit/Constraints/SpecialConstraintSnippets.cs create mode 100644 docs/snippets/Snippets.NUnit/Constraints/StringConstraintSnippets.cs create mode 100644 docs/snippets/Snippets.NUnit/Constraints/TypeConstraintSnippets.cs diff --git a/.claude/plans/constraints-improvement-plan.md b/.claude/plans/constraints-improvement-plan.md index 9612c2494..621291289 100644 --- a/.claude/plans/constraints-improvement-plan.md +++ b/.claude/plans/constraints-improvement-plan.md @@ -227,3 +227,63 @@ Proposed: Keep single file but ensure: | ThrowsConstraint | Complete | Added modifiers section, inline examples | | ContainsConstraint | Complete | **NEW** - Created doc explaining routing behavior | | CollectionEquivalentConstraint | Complete | Restructured with better examples | + +### Phase 3: Priority 2-4 Constraints +| Constraint | Status | Notes | +|------------|--------|-------| +| GreaterThanOrEqualConstraint | Complete | Added Is.AtLeast alias, inline examples | +| LessThanOrEqualConstraint | Complete | Added Is.AtMost alias, inline examples | +| RangeConstraint | Complete | Added inline examples, noted inclusive bounds | +| SameAsConstraint | Complete | Added reference equality examples | +| StartsWithConstraint | Complete | Minor cleanup, added See Also | +| EndsWithConstraint | Complete | Minor cleanup, added See Also | +| SubstringConstraint | Complete | Minor cleanup, added See Also | +| RegexConstraint | Complete | Added common pattern examples | +| EmptyStringConstraint | Complete | Full rewrite with null-or-empty patterns | +| WhiteSpaceConstraint | Complete | Full rewrite, clarified null behavior | +| AllItemsConstraint | Complete | Full rewrite with inline examples | +| SomeItemsConstraint | Complete | Restructured, clarified membership aliases | +| NoItemConstraint | Complete | Full rewrite with inline examples | +| UniqueItemsConstraint | Complete | Restructured, added custom comparison examples | +| CollectionOrderedConstraint | Complete | Restructured with clearer examples | +| CollectionSubsetConstraint | Complete | Restructured with inline examples | +| CollectionSupersetConstraint | Complete | Restructured with inline examples | +| ExactCountConstraint | Complete | Restructured with inline examples | +| EmptyCollectionConstraint | Complete | Restructured with inline examples | + +### Phase 4: Priority 5-10 Constraints +| Constraint | Status | Notes | +|------------|--------|-------| +| InstanceOfTypeConstraint | Complete | Full rewrite with inline examples | +| ExactTypeConstraint | Complete | Full rewrite with inline examples | +| AssignableFromConstraint | Complete | Full rewrite with inline examples | +| AssignableToConstraint | Complete | Full rewrite with inline examples | +| AttributeConstraint | Complete | Restructured with clearer examples | +| AttributeExistsConstraint | Complete | Restructured with inline examples | +| DictionaryContainsKeyConstraint | Complete | Restructured, clarified comparer behavior | +| DictionaryContainsValueConstraint | Complete | Restructured with inline examples | +| DictionaryContainsKeyValuePairConstraint | Complete | Restructured with inline examples | +| PropertyConstraint | Complete | Full rewrite with shortcuts and examples | +| PropertyExistsConstraint | Complete | Restructured with inline examples | +| FileOrDirectoryExistsConstraint | Complete | Restructured with inline examples | +| EmptyDirectoryConstraint | Complete | Restructured with inline examples | +| AndConstraint | Complete | Full rewrite with precedence examples | +| OrConstraint | Complete | Full rewrite with precedence examples | +| NotConstraint | Complete | Full rewrite with inline examples | +| DelayedConstraint | Complete | Restructured with polling and time examples | +| ThrowsNothingConstraint | Complete | Restructured with inline examples | +| NaNConstraint | Complete | Restructured with inline examples | +| AnyOfConstraint | Complete | Restructured with inline examples | + +### Phase 5: Missing Constraint Documentation +| Constraint | Status | Notes | +|------------|--------|-------| +| MultipleOfConstraint | Complete | **NEW** - Created doc for Is.MultipleOf, Is.Even, Is.Odd | +| ContainsConstraint | Complete | Created in Phase 2 - explains routing behavior | + +### Phase 6: Feature Documentation +| Feature | Status | Notes | +|---------|--------|-------| +| AsyncConstraints.md | Complete | **NEW** - Guide for using constraints with async code | +| ContainsHelper.md | Complete | **NEW** - Documentation for Contains.* syntax helper | +| Constraints.md updates | Complete | Added links to new pages, added missing constraints to lists | diff --git a/docs/articles/nunit/writing-tests/constraints/AllItemsConstraint.md b/docs/articles/nunit/writing-tests/constraints/AllItemsConstraint.md index 1ea13bb94..406e7fdc3 100644 --- a/docs/articles/nunit/writing-tests/constraints/AllItemsConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/AllItemsConstraint.md @@ -4,29 +4,28 @@ uid: constraint-allitems # AllItems Constraint -`AllItemsConstraint` applies a constraint to each item in an `IEnumerable`, succeeding only if all of them succeed. An -exception is thrown if the actual value passed does not implement `IEnumerable`. +`AllItemsConstraint` applies a constraint to each item in an `IEnumerable`, succeeding only if all items satisfy the +constraint. An exception is thrown if the actual value does not implement `IEnumerable`. -## Constructor +## Usage ```csharp -AllItemsConstraint(Constraint itemConstraint) +Is.All. +Has.All. ``` -## Syntax +## Examples -```csharp -Is.All... -Has.All... -``` +[!code-csharp[AllItemsConstraintExamples](~/snippets/Snippets.NUnit/Constraints/CollectionConstraintSnippets.cs#AllItemsConstraintExamples)] -## Examples of Use +## Notes -```csharp -int[] iarray = new int[] { 1, 2, 3 }; -string[] sarray = new string[] { "a", "b", "c" }; -Assert.That(iarray, Is.All.Not.Null); -Assert.That(sarray, Is.All.InstanceOf()); -Assert.That(iarray, Is.All.GreaterThan(0)); -Assert.That(iarray, Has.All.GreaterThan(0)); -``` +1. `Is.All` and `Has.All` are interchangeable. +2. The constraint fails on the first item that doesn't match. +3. An empty collection satisfies `Is.All` for any constraint (vacuous truth). + +## See Also + +* [SomeItems Constraint](SomeItemsConstraint.md) - At least one item matches +* [NoItem Constraint](NoItemConstraint.md) - No items match +* [ExactCount Constraint](ExactCountConstraint.md) - Specific number of items match diff --git a/docs/articles/nunit/writing-tests/constraints/AndConstraint.md b/docs/articles/nunit/writing-tests/constraints/AndConstraint.md index 5684cc72c..de611b0c6 100644 --- a/docs/articles/nunit/writing-tests/constraints/AndConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/AndConstraint.md @@ -4,33 +4,28 @@ uid: constraint-and # And Constraint -`AndConstraint` combines two other constraints and succeeds only if they both succeed. +`AndConstraint` combines two constraints and succeeds only if both succeed. -## Constructor +## Usage ```csharp -AndConstraint(Constraint left, Constraint right) +.And. ``` -## Syntax +## Examples -```csharp -.And. -``` - -## Examples of Use - -[!code-csharp[AndConstraintExamples](~/snippets/Snippets.NUnit/ConstraintExamples.cs#AndConstraintExamples)] +[!code-csharp[AndConstraintExamples](~/snippets/Snippets.NUnit/Constraints/CompoundConstraintSnippets.cs#AndConstraintExamples)] ## Evaluation Order and Precedence -Note that the constraint evaluates the sub-constraints left to right, meaning that `Assert.That(i, -Is.Not.Null.And.GreaterThan(9));` where `i` is a nullable `int` will work for `10`, but fail for `null` with the message -`Expected: not null and greater than 9. But was: null`. `Assert.That(i, Is.GreaterThan(9).And.Not.Null);` will also -succeed for `10`, but throw an exception for `null`, as `null` cannot be compared to `9`. +Constraints are evaluated **left to right**. This is important for null checks: + +[!code-csharp[AndConstraintNullCheckExamples](~/snippets/Snippets.NUnit/Constraints/CompoundConstraintSnippets.cs#AndConstraintNullCheckExamples)] -The **OrConstraint** has precedence over the **AndConstraint**. +> [!NOTE] +> `Or` has higher precedence than `And`. The expression `A.And.B.Or.C` is evaluated as `A.And.(B.Or.C)`. -## See also +## See Also -* [OrConstraint](OrConstraint.md) +* [Or Constraint](OrConstraint.md) - Either condition must be true +* [Not Constraint](NotConstraint.md) - Negate a constraint diff --git a/docs/articles/nunit/writing-tests/constraints/AnyOfConstraint.md b/docs/articles/nunit/writing-tests/constraints/AnyOfConstraint.md index 32f47893f..3d9dbbd39 100644 --- a/docs/articles/nunit/writing-tests/constraints/AnyOfConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/AnyOfConstraint.md @@ -4,46 +4,44 @@ uid: constraint-anyof # AnyOf Constraint -`AnyOfConstraint` is used to determine whether a value is equal to any of the expected values. +`AnyOfConstraint` tests that a value equals any one of a set of expected values. > [!NOTE] -> Values provided must be as parameters to the method, not as e.g. a separate array. If you are instead looking -> to see if a collection contains a value, see the [SomeItems Constraint](xref:constraint-someitems). +> Pass expected values as individual parameters, not as an array. To test if a collection contains a specific +> value, use [SomeItemsConstraint](SomeItemsConstraint.md) instead. -## Constructor +## Usage ```csharp -AnyOfConstraint(object[] expected) +Is.AnyOf(params object[] expected) ``` -## Syntax +## Modifiers ```csharp -Is.AnyOf(object[] expected) +.IgnoreCase +.IgnoreWhiteSpace // NUnit 4.2+ +.Using(IComparer comparer) +.Using(IEqualityComparer comparer) +.Using(IComparer comparer) +.Using(IEqualityComparer comparer) +.Using(Comparison comparer) +.Using(Func comparer) +.UsingPropertiesComparer() // NUnit 4.1+ ``` -## Modifiers +## Examples -```csharp -...IgnoreCase -...IgnoreWhiteSpace // From version 4.2 -...Using(IEqualityComparer comparer) -...Using(IComparer comparer) -...Using(IEqualityComparer comparer) -...Using(IComparer comparer) -...Using(Comparison comparer) -...Using(Func comparer) -...UsingPropertiesComparer() // From version 4.1 -...UsingPropertiesComparer( - Func configure) // From version 4.4 -``` +[!code-csharp[AnyOfConstraintExamples](~/snippets/Snippets.NUnit/Constraints/SpecialConstraintSnippets.cs#AnyOfConstraintExamples)] -## Examples of Use +## Notes -```csharp -Assert.That(42, Is.AnyOf(0, -1, 42, 100)); +1. This is for testing a single value against multiple options. +2. For testing if a collection contains a value, use `Has.Member()` or `Does.Contain()`. +3. All comparison modifiers apply to the equality check between the actual and each expected value. -// You can use a custom comparer as well -Assert.That(myOwnObject, Is.AnyOf(myArray).Using(myComparer)); -``` +## See Also + +* [SomeItems Constraint](SomeItemsConstraint.md) - Test if collection contains a value +* [Equal Constraint](EqualConstraint.md) - Test equality with single value +* [Or Constraint](OrConstraint.md) - Alternative way to express multiple options diff --git a/docs/articles/nunit/writing-tests/constraints/AssignableFromConstraint.md b/docs/articles/nunit/writing-tests/constraints/AssignableFromConstraint.md index ec31c5a92..b9ebb5b80 100644 --- a/docs/articles/nunit/writing-tests/constraints/AssignableFromConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/AssignableFromConstraint.md @@ -4,24 +4,28 @@ uid: constraint-assignablefrom # AssignableFrom Constraint -`AssignableFromConstraint` tests that one type is assignable from another +`AssignableFromConstraint` tests that an instance of the specified type can be assigned to the actual value's type. In +other words, the actual value's type is a base type or interface of the expected type. -## Constructor +## Usage ```csharp -AssignableFromConstraint(Type) +Is.AssignableFrom(Type expectedType) +Is.AssignableFrom() ``` -## Syntax +## Examples -```csharp -Is.AssignableFrom(Type) -Is.AssignableFrom() -``` +[!code-csharp[AssignableFromConstraintExamples](~/snippets/Snippets.NUnit/Constraints/TypeConstraintSnippets.cs#AssignableFromConstraintExamples)] -## Examples of Use +## Notes -```csharp -Assert.That("Hello", Is.AssignableFrom(typeof(string))); -Assert.That(5, Is.Not.AssignableFrom(typeof(string))); -``` +1. `Is.AssignableFrom()` is true when `actualType.IsAssignableFrom(typeof(T))`. +2. This tests "can I assign an instance of T to this variable?". +3. This is the reverse of [AssignableToConstraint](AssignableToConstraint.md). + +## See Also + +* [AssignableTo Constraint](AssignableToConstraint.md) - Reverse direction check +* [InstanceOfType Constraint](InstanceOfTypeConstraint.md) - Test if object is instance of type +* [ExactType Constraint](ExactTypeConstraint.md) - Test for exact type match diff --git a/docs/articles/nunit/writing-tests/constraints/AssignableToConstraint.md b/docs/articles/nunit/writing-tests/constraints/AssignableToConstraint.md index c2ce32aac..a6097e6ca 100644 --- a/docs/articles/nunit/writing-tests/constraints/AssignableToConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/AssignableToConstraint.md @@ -4,24 +4,28 @@ uid: constraint-assignableto # AssignableTo Constraint -`AssignableToConstraint` tests that one type is assignable to another +`AssignableToConstraint` tests that the actual value can be assigned to a variable of the specified type. In other +words, the actual value's type derives from or implements the expected type. -## Constructor +## Usage ```csharp -AssignableToConstraint(Type) +Is.AssignableTo(Type expectedType) +Is.AssignableTo() ``` -## Syntax +## Examples -```csharp -Is.AssignableTo(Type) -Is.AssignableTo() -``` +[!code-csharp[AssignableToConstraintExamples](~/snippets/Snippets.NUnit/Constraints/TypeConstraintSnippets.cs#AssignableToConstraintExamples)] -## Examples of Use +## Notes -```csharp -Assert.That("Hello", Is.AssignableTo(typeof(object))); -Assert.That(5, Is.Not.AssignableTo(typeof(string))); -``` +1. `Is.AssignableTo()` is true when `typeof(T).IsAssignableFrom(actual.GetType())`. +2. This tests "can this value be assigned to a variable of type T?". +3. This is the reverse of [AssignableFromConstraint](AssignableFromConstraint.md). + +## See Also + +* [AssignableFrom Constraint](AssignableFromConstraint.md) - Reverse direction check +* [InstanceOfType Constraint](InstanceOfTypeConstraint.md) - Test if object is instance of type +* [ExactType Constraint](ExactTypeConstraint.md) - Test for exact type match diff --git a/docs/articles/nunit/writing-tests/constraints/AsyncConstraints.md b/docs/articles/nunit/writing-tests/constraints/AsyncConstraints.md new file mode 100644 index 000000000..119364a4f --- /dev/null +++ b/docs/articles/nunit/writing-tests/constraints/AsyncConstraints.md @@ -0,0 +1,131 @@ +--- +uid: constraint-async +--- + +# Async Constraint Support + +NUnit constraints fully support testing asynchronous code. This page covers patterns for using constraints with async +methods, tasks, and delegates. + +## Testing Async Methods + +### Basic Async Assertions + +Use `async` lambdas with `Assert.That` to test async code: + +```csharp +// Test async method return values +Assert.That(async () => await service.GetValueAsync(), Is.EqualTo(42)); + +// Test that async method completes without throwing +Assert.That(async () => await service.InitializeAsync(), Throws.Nothing); + +// Test async exception throwing +Assert.That(async () => await service.InvalidOperationAsync(), + Throws.TypeOf()); +``` + +### Testing Task Results + +You can also await tasks directly before asserting: + +```csharp +// Await first, then assert +var result = await calculator.AddAsync(2, 3); +Assert.That(result, Is.EqualTo(5)); + +// Or use Assert.ThatAsync (NUnit 4.0+) +await Assert.ThatAsync(async () => await calculator.AddAsync(2, 3), Is.EqualTo(5)); +``` + +## Exception Testing with Async Code + +### ThrowsConstraint with Async + +```csharp +// Test for specific exception type +Assert.That(async () => await service.FailingMethodAsync(), + Throws.TypeOf()); + +// Test exception message +Assert.That(async () => await service.FailingMethodAsync(), + Throws.TypeOf() + .With.Message.Contains("expected error")); + +// Test inner exception +Assert.That(async () => await service.FailingMethodAsync(), + Throws.TypeOf() + .With.InnerException.TypeOf()); +``` + +### ThrowsNothing with Async + +```csharp +// Verify async method completes successfully +Assert.That(async () => await service.SafeMethodAsync(), Throws.Nothing); +``` + +## Delayed Constraints with Async + +Use `DelayedConstraint` for testing eventually-consistent async operations: + +```csharp +// Poll until condition is true (or timeout) +Assert.That(async () => await service.IsReadyAsync(), + Is.True.After(5).Seconds.PollEvery(100).MilliSeconds); + +// Wait for value to appear +Assert.That(async () => await cache.GetCountAsync(), + Is.GreaterThan(0).After(2000, 100)); +``` + +## Collection Constraints with Async Enumerables + +For `IAsyncEnumerable`, materialize the collection first: + +```csharp +// Convert to list first +var items = await asyncEnumerable.ToListAsync(); +Assert.That(items, Has.Count.EqualTo(5)); +Assert.That(items, Is.All.Positive); + +// Or use helper method +Assert.That(await ToListAsync(service.GetItemsAsync()), Has.Some.GreaterThan(100)); +``` + +## Best Practices + +1. **Use async lambdas** when testing methods that return `Task` or `Task`: + ```csharp + Assert.That(async () => await method(), constraint); + ``` + +2. **Avoid blocking calls** like `.Result` or `.Wait()` - they can cause deadlocks: + ```csharp + // BAD - can deadlock + Assert.That(service.GetValueAsync().Result, Is.EqualTo(42)); + + // GOOD - use async lambda + Assert.That(async () => await service.GetValueAsync(), Is.EqualTo(42)); + ``` + +3. **Use `Throws.Nothing`** to explicitly verify async code doesn't throw: + ```csharp + Assert.That(async () => await service.ProcessAsync(), Throws.Nothing); + ``` + +4. **Use `DelayedConstraint`** for eventually-consistent operations instead of `Task.Delay`: + ```csharp + // BAD - arbitrary wait + await Task.Delay(1000); + Assert.That(value, Is.True); + + // GOOD - polls until true or timeout + Assert.That(() => value, Is.True.After(2).Seconds.PollEvery(100).MilliSeconds); + ``` + +## See Also + +* [Throws Constraint](ThrowsConstraint.md) - Exception testing +* [ThrowsNothing Constraint](ThrowsNothingConstraint.md) - Verify no exception +* [Delayed Constraint](DelayedConstraint.md) - Polling and timeouts diff --git a/docs/articles/nunit/writing-tests/constraints/AttributeConstraint.md b/docs/articles/nunit/writing-tests/constraints/AttributeConstraint.md index 15830f448..08a26d856 100644 --- a/docs/articles/nunit/writing-tests/constraints/AttributeConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/AttributeConstraint.md @@ -4,30 +4,28 @@ uid: constraint-attribute # Attribute Constraint -`AttributeConstraint` tests for the existence of an attribute on a Type and then applies a constraint to that attribute. +`AttributeConstraint` tests for the existence of an attribute on a type and then applies a further constraint to that +attribute's properties. -## Constructor +## Usage ```csharp -AttributeConstraint(Type type, IConstraint baseConstraint) +Has.Attribute(Type attributeType). +Has.Attribute(). ``` -## Syntax +## Examples -```csharp -Has.Attribute(typeof(TestFixtureAttribute))... -Has.Attribute()... -``` +[!code-csharp[AttributeConstraintExamples](~/snippets/Snippets.NUnit/Constraints/TypeConstraintSnippets.cs#AttributeConstraintExamples)] -## Examples of Use +## Notes -```csharp -Assert.That(someObject, Has.Attribute(typeof(TestFixtureAttribute)) - .Property("Description").EqualTo("My description")); -Assert.That(someObject, Has.Attribute() - .Property("Description").EqualTo("My description")); -``` +1. The constraint first checks that the attribute exists, then applies the chained constraint to the attribute instance. +2. To only check for attribute existence without testing its properties, use + [AttributeExistsConstraint](AttributeExistsConstraint.md). +3. The constraint works on both `Type` objects and instances (testing the instance's type). -## See also +## See Also -* [AttributeExistsConstraint](AttributeExistsConstraint.md) +* [AttributeExists Constraint](AttributeExistsConstraint.md) - Just test for attribute presence +* [Property Constraint](PropertyConstraint.md) - Test property values diff --git a/docs/articles/nunit/writing-tests/constraints/AttributeExistsConstraint.md b/docs/articles/nunit/writing-tests/constraints/AttributeExistsConstraint.md index c97794478..d852da0a6 100644 --- a/docs/articles/nunit/writing-tests/constraints/AttributeExistsConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/AttributeExistsConstraint.md @@ -4,24 +4,26 @@ uid: constraint-attributeexists # AttributeExists Constraint -`AttributeExistsConstraint` tests for the existence of an attribute on a Type. +`AttributeExistsConstraint` tests for the existence of an attribute on a type. -## Constructor +## Usage ```csharp -AttributeExistsConstraint(Type type) +Has.Attribute(Type attributeType) +Has.Attribute() ``` -## Syntax +## Examples -```csharp -Has.Attribute(typeof(TestFixtureAttribute)) -Has.Attribute() -``` +[!code-csharp[AttributeExistsConstraintExamples](~/snippets/Snippets.NUnit/Constraints/TypeConstraintSnippets.cs#AttributeExistsConstraintExamples)] -## Examples of Use +## Notes -```csharp -Assert.That(someObject, Has.Attribute(typeof(TestFixtureAttribute))); -Assert.That(someObject, Has.Attribute()); -``` +1. When no further constraint is chained, `Has.Attribute` creates an `AttributeExistsConstraint`. +2. When a constraint is chained (e.g., `.Property("Name")`), it becomes an + [AttributeConstraint](AttributeConstraint.md). +3. The constraint works on both `Type` objects and instances (testing the instance's type). + +## See Also + +* [Attribute Constraint](AttributeConstraint.md) - Test attribute properties diff --git a/docs/articles/nunit/writing-tests/constraints/CollectionOrderedConstraint.md b/docs/articles/nunit/writing-tests/constraints/CollectionOrderedConstraint.md index ec58b0a72..ebf48cb25 100644 --- a/docs/articles/nunit/writing-tests/constraints/CollectionOrderedConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/CollectionOrderedConstraint.md @@ -4,76 +4,48 @@ uid: constraint-collectionordered # CollectionOrdered Constraint -`CollectionOrderedConstraint` tests that an `IEnumerable` is ordered. If the actual value passed does not implement -`IEnumerable`, an exception is thrown. +`CollectionOrderedConstraint` tests that an `IEnumerable` is ordered. An exception is thrown if the actual value does +not implement `IEnumerable`. -The constraint supports both simple and property-based ordering (Ordered.By). - -## Simple Ordering - -Simple ordering is based on the values of the items themselves. It is implied when the `By` modifier is not used. +## Usage ```csharp -int[] iarray = new int[] { 1, 2, 3 }; -Assert.That(iarray, Is.Ordered); - -string[] sarray = new string[] { "c", "b", "a" }; -Assert.That(sarray, Is.Ordered.Descending); +Is.Ordered +Is.Ordered.Ascending +Is.Ordered.Descending +Is.Ordered.By(string propertyName) ``` -### Ordering Modifiers +## Modifiers ```csharp -...Ascending -...Descending -...Using(IComparer comparer) -...Using(IComparer comparer) -...Using(Comparison comparer) +.Ascending // Ascending order (default) +.Descending // Descending order +.By(string propertyName) // Order by property +.Then // Begin next ordering step +.Using(IComparer comparer) +.Using(IComparer comparer) +.Using(Comparison comparer) ``` -By default, the order is expected to be ascending. - -## Property-Based Ordering - -Property-based ordering uses one or more properties that are common to every item in the enumeration. It is used when -one or more instances of the `By` modifier appears in the ordering expression. - -```csharp -string[] sarray = new string[] ("a", "aa", "aaa"); -Assert.That(sarray, Is.Ordered.By("Length")); +## Examples -string[] sarray2 = new string[] ("aaa", "aa", "a"); -Assert.That(sarray2, Is.Ordered.Descending.By("Length")); -``` +### Simple Ordering -### Property-based Modifiers +[!code-csharp[CollectionOrderedConstraintExamples](~/snippets/Snippets.NUnit/Constraints/CollectionConstraintSnippets.cs#CollectionOrderedConstraintExamples)] -```csharp -...Then -...Ascending -...Descending -...By(string propertyName) -...Using(IComparer comparer) -...Using(IComparer comparer) -...Using(Comparison comparer) -``` +### Multiple Property Ordering -## Ordering on Multiple Properties +[!code-csharp[CollectionOrderedMultiplePropertiesExamples](~/snippets/Snippets.NUnit/Constraints/CollectionConstraintSnippets.cs#CollectionOrderedMultiplePropertiesExamples)] -An ordering expression may use multiple `By` modifiers, each referring to a different property. The following examples -assume a collection of items with properties named A and B. +## Notes -```csharp -Assert.That(collection, Is.Ordered.By("A").Then.By("B")); -Assert.That(collection, Is.Ordered.By("A").Then.By("B").Descending); -Assert.That(collection, Is.Ordered.Ascending.By("A").Then.Descending.By("B")); -Assert.That(collection, Is.Ordered.Ascending.By("A").By("B").Descending); -Assert.That(collection, Is.Ordered.Ascending.By("A").Descending.By("B")); // Illegal! -``` +1. The default ordering is ascending. +2. The `Then` modifier separates ordering steps. Each step can have its own `Ascending`/`Descending` and `Using` + modifiers. +3. An empty or single-item collection is always considered ordered. -## Notes +## See Also -1. The `Then` modifier divides the expression into ordering steps. Each step may optionally contain one `Ascending` or - `Descending` modifier and one `Using` modifier. -2. If `Then` is not used, each new `By` modifier marks the beginning of a step. The last example statement is illegal - because the first group contains both Ascending and Descending. Use of `Then` is recommended for clarity. +* [CollectionEquivalent Constraint](CollectionEquivalentConstraint.md) - Test equivalence regardless of order +* [UniqueItems Constraint](UniqueItemsConstraint.md) - Test for unique items diff --git a/docs/articles/nunit/writing-tests/constraints/CollectionSubsetConstraint.md b/docs/articles/nunit/writing-tests/constraints/CollectionSubsetConstraint.md index 0455f1d00..9baefeff5 100644 --- a/docs/articles/nunit/writing-tests/constraints/CollectionSubsetConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/CollectionSubsetConstraint.md @@ -4,40 +4,38 @@ uid: constraint-collectionsubset # CollectionSubset Constraint -`CollectionSubsetConstraint` tests that one `IEnumerable` is a subset of another. If the actual value passed does not -implement `IEnumerable`, an exception is thrown. +`CollectionSubsetConstraint` tests that one `IEnumerable` is a subset of another. Every item in the actual collection +must be present in the expected collection. An exception is thrown if the actual value does not implement `IEnumerable`. -## Constructor +## Usage ```csharp -CollectionSubsetConstraint(IEnumerable) +Is.SubsetOf(IEnumerable expected) ``` -## Syntax +## Modifiers ```csharp -Is.SubsetOf(IEnumerable) +.Using(IComparer comparer) +.Using(IEqualityComparer comparer) +.Using(IComparer comparer) +.Using(IEqualityComparer comparer) +.Using(Comparison comparer) +.Using(Func comparer) +.UsingPropertiesComparer() // NUnit 4.1+ ``` -## Modifiers +## Examples -```csharp -...Using(IEqualityComparer comparer) -...Using(IComparer comparer) -...Using(IEqualityComparer comparer) -...Using(IComparer comparer) -...Using(Comparison comparer) -...Using(Func comparer) -...Using(Func comparison) -...UsingPropertiesComparer() // From version 4.1 -...UsingPropertiesComparer( - Func configure) // From version 4.4 -``` +[!code-csharp[CollectionSubsetConstraintExamples](~/snippets/Snippets.NUnit/Constraints/CollectionConstraintSnippets.cs#CollectionSubsetConstraintExamples)] -## Example of Use +## Notes -```csharp -int[] iarray = new int[] { 1, 3 }; -Assert.That(iarray, Is.SubsetOf(new int[] { 1, 2, 3 })); -``` +1. A set is always a subset of itself. +2. The empty set is a subset of every set. +3. Duplicate items are considered: `{1, 1}` is a subset of `{1, 1, 2}` but not of `{1, 2}`. + +## See Also + +* [CollectionSuperset Constraint](CollectionSupersetConstraint.md) - Test that collection is a superset +* [CollectionEquivalent Constraint](CollectionEquivalentConstraint.md) - Test exact equivalence diff --git a/docs/articles/nunit/writing-tests/constraints/CollectionSupersetConstraint.md b/docs/articles/nunit/writing-tests/constraints/CollectionSupersetConstraint.md index 7cb0482fd..ac5a695c6 100644 --- a/docs/articles/nunit/writing-tests/constraints/CollectionSupersetConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/CollectionSupersetConstraint.md @@ -4,40 +4,39 @@ uid: constraint-collectionsuperset # CollectionSuperset Constraint -`CollectionSupersetConstraint` tests that one `IEnumerable` is a superset of another. If the actual value passed does -not implement `IEnumerable`, an exception is thrown. +`CollectionSupersetConstraint` tests that one `IEnumerable` is a superset of another. Every item in the expected +collection must be present in the actual collection. An exception is thrown if the actual value does not implement +`IEnumerable`. -## Constructor +## Usage ```csharp -CollectionSupersetConstraint(IEnumerable) +Is.SupersetOf(IEnumerable expected) ``` -## Syntax +## Modifiers ```csharp -Is.SupersetOf(IEnumerable) +.Using(IComparer comparer) +.Using(IEqualityComparer comparer) +.Using(IComparer comparer) +.Using(IEqualityComparer comparer) +.Using(Comparison comparer) +.Using(Func comparer) +.UsingPropertiesComparer() // NUnit 4.1+ ``` -## Modifiers +## Examples -```csharp -...Using(IEqualityComparer comparer) -...Using(IComparer comparer) -...Using(IEqualityComparer comparer) -...Using(IComparer comparer) -...Using(Comparison comparer) -...Using(Func comparer) -...Using(Func comparison) -...UsingPropertiesComparer() // From version 4.1 -...UsingPropertiesComparer( - Func configure) // From version 4.4 -``` +[!code-csharp[CollectionSupersetConstraintExamples](~/snippets/Snippets.NUnit/Constraints/CollectionConstraintSnippets.cs#CollectionSupersetConstraintExamples)] -## Example of Use +## Notes -```csharp -int[] iarray = new int[] { 1, 2, 3 }; -Assert.That(iarray, Is.SupersetOf(new int[] { 1, 3 })); -``` +1. A set is always a superset of itself. +2. Every set is a superset of the empty set. +3. Duplicate items are considered: `{1, 2}` is not a superset of `{1, 1}`. + +## See Also + +* [CollectionSubset Constraint](CollectionSubsetConstraint.md) - Test that collection is a subset +* [CollectionEquivalent Constraint](CollectionEquivalentConstraint.md) - Test exact equivalence diff --git a/docs/articles/nunit/writing-tests/constraints/Constraints.md b/docs/articles/nunit/writing-tests/constraints/Constraints.md index 985298a88..c987fc590 100644 --- a/docs/articles/nunit/writing-tests/constraints/Constraints.md +++ b/docs/articles/nunit/writing-tests/constraints/Constraints.md @@ -9,6 +9,11 @@ This page lists all the constraints available in NUnit. * [Alphabetical List of Constraints](#alphabetical-list-of-constraints) * [Constraints by Category](#constraints-by-category) +For additional topics, see: + +* [Async Constraint Support](AsyncConstraints.md) - Using constraints with async code +* [Contains Helper](ContainsHelper.md) - The Contains.* syntax helper + ## Alphabetical List of Constraints Constraint Name | @@ -25,6 +30,8 @@ Constraint Name | [CollectionOrderedConstraint](CollectionOrderedConstraint.md) | [CollectionSubsetConstraint](CollectionSubsetConstraint.md) | [CollectionSupersetConstraint](CollectionSupersetConstraint.md) | +[ContainsConstraint](ContainsConstraint.md) | +[DefaultConstraint](DefaultConstraint.md) | [DelayedConstraint](DelayedConstraint.md) | [DictionaryContainsKeyConstraint](DictionaryContainsKeyConstraint.md) | [DictionaryContainsKeyValuePairConstraint](DictionaryContainsKeyValuePairConstraint.md) | @@ -44,6 +51,7 @@ Constraint Name | [InstanceOfTypeConstraint](InstanceOfTypeConstraint.md) | [LessThanConstraint](LessThanConstraint.md) | [LessThanOrEqualConstraint](LessThanOrEqualConstraint.md) | +[MultipleOfConstraint](MultipleOfConstraint.md) | [NaNConstraint](NaNConstraint.md) | [NoItemConstraint](NoItemConstraint.md) | [NotConstraint](NotConstraint.md) | @@ -97,6 +105,7 @@ Constraint Name | [GreaterThanOrEqualConstraint](GreaterThanOrEqualConstraint.md) | [LessThanConstraint](LessThanConstraint.md) | [LessThanOrEqualConstraint](LessThanOrEqualConstraint.md) | +[MultipleOfConstraint](MultipleOfConstraint.md) | [RangeConstraint](RangeConstraint.md) | ### Compound Constraints @@ -111,6 +120,7 @@ Constraint Name | Constraint Name | -------------------------------------| +[DefaultConstraint](DefaultConstraint.md) | [EmptyConstraint](EmptyConstraint.md) | [FalseConstraint](FalseConstraint.md) | [NaNConstraint](NaNConstraint.md) | @@ -132,6 +142,7 @@ Constraint Name | Constraint Name | -------------------------------------| +[ContainsConstraint](ContainsConstraint.md) | [EmptyStringConstraint](EmptyStringConstraint.md) | [EndsWithConstraint](EndsWithConstraint.md) | [RegexConstraint](RegexConstraint.md) | diff --git a/docs/articles/nunit/writing-tests/constraints/ContainsConstraint.md b/docs/articles/nunit/writing-tests/constraints/ContainsConstraint.md index 332d601d1..b9e1ad965 100644 --- a/docs/articles/nunit/writing-tests/constraints/ContainsConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/ContainsConstraint.md @@ -32,25 +32,13 @@ Does.Not.Contain(object expected) When the actual value is a string, `Does.Contain` tests for a substring: -```csharp -Assert.That("Hello World", Does.Contain("World")); -Assert.That("Hello World", Does.Contain("world").IgnoreCase); -Assert.That("Hello World", Does.Not.Contain("Goodbye")); -``` +[!code-csharp[ContainsConstraintStringExamples](~/snippets/Snippets.NUnit/Constraints/ComparisonConstraintSnippets.cs#ContainsConstraintStringExamples)] ### Collection Membership When the actual value is a collection, `Does.Contain` tests for item membership: -```csharp -int[] numbers = { 1, 2, 3, 4, 5 }; -Assert.That(numbers, Does.Contain(3)); -Assert.That(numbers, Does.Not.Contain(99)); - -string[] names = { "Alice", "Bob", "Charlie" }; -Assert.That(names, Does.Contain("Bob")); -Assert.That(names, Does.Contain("bob").IgnoreCase); -``` +[!code-csharp[ContainsConstraintCollectionExamples](~/snippets/Snippets.NUnit/Constraints/ComparisonConstraintSnippets.cs#ContainsConstraintCollectionExamples)] ## How It Works diff --git a/docs/articles/nunit/writing-tests/constraints/ContainsHelper.md b/docs/articles/nunit/writing-tests/constraints/ContainsHelper.md new file mode 100644 index 000000000..2a53e9ac4 --- /dev/null +++ b/docs/articles/nunit/writing-tests/constraints/ContainsHelper.md @@ -0,0 +1,126 @@ +--- +uid: constraint-contains-helper +--- + +# Contains Helper + +The `Contains` helper class provides a fluent syntax for containment assertions. It offers shortcuts for common +containment tests on strings, collections, and dictionaries. + +## Overview + +`Contains` is one of NUnit's syntax helper classes (alongside `Is`, `Has`, and `Does`). It provides entry points for +constraints that test whether something contains an expected element. + +## Usage + +```csharp +Contains.Item(object expected) // Collection contains item +Contains.Key(object expectedKey) // Dictionary contains key +Contains.Value(object expectedValue) // Dictionary contains value +Contains.Substring(string expected) // String contains substring +``` + +## String Containment + +```csharp +string text = "Hello World"; + +// Test for substring +Assert.That(text, Contains.Substring("World")); +Assert.That(text, Contains.Substring("WORLD").IgnoreCase); + +// Equivalent to Does.Contain for strings +Assert.That(text, Does.Contain("World")); +``` + +## Collection Containment + +```csharp +int[] numbers = { 1, 2, 3, 4, 5 }; + +// Test for item in collection +Assert.That(numbers, Contains.Item(3)); +Assert.That(numbers, Contains.Item(3).And.Contains.Item(5)); + +// Equivalent forms +Assert.That(numbers, Does.Contain(3)); +Assert.That(numbers, Has.Member(3)); +``` + +## Dictionary Containment + +```csharp +var dict = new Dictionary +{ + ["Alice"] = 30, + ["Bob"] = 25 +}; + +// Test for key +Assert.That(dict, Contains.Key("Alice")); + +// Test for value +Assert.That(dict, Contains.Value(30)); + +// Test for key-value pair +Assert.That(dict, Contains.Key("Alice").WithValue(30)); +``` + +## Comparison with Other Helpers + +| Syntax | Description | Use Case | +|--------|-------------|----------| +| `Contains.Item(x)` | Collection contains x | General collection membership | +| `Contains.Key(k)` | Dictionary has key k | Dictionary key lookup | +| `Contains.Value(v)` | Dictionary has value v | Dictionary value search | +| `Contains.Substring(s)` | String contains s | Substring matching | +| `Does.Contain(x)` | Smart containment | Auto-routes based on type | +| `Has.Member(x)` | Collection contains x | Same as Contains.Item | + +## Smart Routing with Does.Contain + +`Does.Contain()` automatically routes to the appropriate constraint: + +```csharp +// String -> SubstringConstraint +Assert.That("Hello World", Does.Contain("World")); + +// Collection -> SomeItemsConstraint +Assert.That(new[] { 1, 2, 3 }, Does.Contain(2)); + +// Dictionary key check +Assert.That(dict, Does.ContainKey("Alice")); +Assert.That(dict, Does.ContainValue(30)); +``` + +## Modifiers + +### For String Containment + +```csharp +Contains.Substring("text").IgnoreCase +Contains.Substring("text").Using(StringComparison.OrdinalIgnoreCase) +``` + +### For Collection Containment + +```csharp +Contains.Item(obj).Using(comparer) +Contains.Item(obj).UsingPropertiesComparer() +``` + +### For Dictionary Values + +```csharp +Contains.Value(obj).Using(comparer) +Contains.Value(obj).IgnoreCase // For string values +``` + +## See Also + +* [Contains Constraint](ContainsConstraint.md) - How Does.Contain routes to different constraints +* [Substring Constraint](SubstringConstraint.md) - String containment details +* [SomeItems Constraint](SomeItemsConstraint.md) - Collection membership details +* [DictionaryContainsKey Constraint](DictionaryContainsKeyConstraint.md) - Dictionary key testing +* [DictionaryContainsValue Constraint](DictionaryContainsValueConstraint.md) - Dictionary value testing diff --git a/docs/articles/nunit/writing-tests/constraints/DelayedConstraint.md b/docs/articles/nunit/writing-tests/constraints/DelayedConstraint.md index fb10baa46..974b09dd2 100644 --- a/docs/articles/nunit/writing-tests/constraints/DelayedConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/DelayedConstraint.md @@ -4,35 +4,44 @@ uid: constraint-delayed # Delayed Constraint -`DelayedConstraint` delays the application of another constraint until a certain -amount of time has passed. In its simplest form, it replaces use of a Sleep -in the code but it also supports polling, which may allow use of a longer -maximum time while still keeping the tests as fast as possible. +`DelayedConstraint` delays evaluation of another constraint, optionally polling until the constraint passes or the +timeout expires. This is useful for testing asynchronous operations or eventual consistency. -The **After** modifier is permitted on any constraint, and the delay applies to -the entire expression up to the point where **After** appears. +## Usage -Use of a **DelayedConstraint** with a value argument makes no sense, since -the value will be extracted at the point of call. Its intended use is with -delegates and references. If a delegate is used with polling, it may be called -multiple times so only methods without side effects should be used in this way. +```csharp +.After(int delayInMilliseconds) +.After(int delayInMilliseconds, int pollingInterval) +.After(int delay).Seconds +.After(int delay).Minutes.PollEvery(int interval).MilliSeconds +``` + +## Examples -| Syntax Helper | Constructor | Operation | -| ------------- | ------------| --------- | -| After(int) | DelayedConstraint(Constraint, int) | tests that a constraint is satisfied after a delay. | -| After(int, int) | DelayedConstraint(Constraint, int, int) | tests that a constraint is satisfied after a delay using polling. | +[!code-csharp[DelayedConstraintExamples](~/snippets/Snippets.NUnit/Constraints/SpecialConstraintSnippets.cs#DelayedConstraintExamples)] -## Enhanced Syntax +### Fluent Time Syntax -With NUnit 3.6, an enhanced syntax is available that allows expressing the delay and polling interval more fluently. +[!code-csharp[DelayedConstraintFluentExamples](~/snippets/Snippets.NUnit/Constraints/SpecialConstraintSnippets.cs#DelayedConstraintFluentExamples)] + +## Time Modifiers ```csharp - After(4).Seconds - After(1).Minutes.PollEvery(500).MilliSeconds +.Seconds +.Minutes +.MilliSeconds // Note capital 'S' ``` -Only Minutes, Seconds and MilliSeconds (note capital-S) are accepted as time modifiers. The default is to use MilliSeconds. +Default unit is milliseconds when no modifier is specified. + +## Notes + +1. Use delegates (`() => value`) not direct values, since values are captured at call time. +2. When polling, the delegate may be called multiple times - avoid side effects. +3. The `.After()` modifier applies to the entire constraint expression preceding it. +4. Without polling, the constraint waits the full delay before checking once. -## Examples of Use +## See Also -[!code-csharp[DelayedConstraintExamples](~/snippets/Snippets.NUnit/ConstraintExamples.cs#DelayedConstraintExamples)] +* [Throws Constraint](ThrowsConstraint.md) - For exception testing +* [True Constraint](TrueConstraint.md) - For boolean conditions diff --git a/docs/articles/nunit/writing-tests/constraints/DictionaryContainsKeyConstraint.md b/docs/articles/nunit/writing-tests/constraints/DictionaryContainsKeyConstraint.md index b0b259306..770712507 100644 --- a/docs/articles/nunit/writing-tests/constraints/DictionaryContainsKeyConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/DictionaryContainsKeyConstraint.md @@ -4,58 +4,39 @@ uid: constraint-dictionarycontainskey # DictionaryContainsKey Constraint -`DictionaryContainsKeyConstraint` is used to test whether a dictionary -contains an expected object as a key. +`DictionaryContainsKeyConstraint` tests whether a dictionary contains an expected key. -## Constructor +## Usage ```csharp -DictionaryContainsKeyConstraint(object) -``` - -## Syntax - -```csharp -Contains.Key(object) -Does.ContainKey(object) -Does.Not.ContainKey(object) +Contains.Key(object expectedKey) +Does.ContainKey(object expectedKey) +Does.Not.ContainKey(object expectedKey) ``` ## Modifiers ```csharp -...WithValue(object expectedValue) +.WithValue(object expectedValue) // Also check the corresponding value ``` -As of version 4.4.0 of NUnit the other modifiers were removed as they were non-functional. -NUnit's `ContainKey` works the same as the `ContainsKey` method on `Dictionary` -It uses the comparer specified when the dictionary was created. +## Examples -## Examples of Use +[!code-csharp[DictionaryContainsKeyConstraintExamples](~/snippets/Snippets.NUnit/Constraints/DictionaryConstraintSnippets.cs#DictionaryContainsKeyConstraintExamples)] -```csharp -var caseSensitiveDictionary = new Dictionary(StringComparer.Ordinal) -{ - ["Hello"] = "World", -}; +### Dictionary Comparer Behavior -Assert.That(caseSensitiveDictionary, Does.ContainKey("Hello")); -Assert.That(caseSensitiveDictionary, Does.Not.ContainKey("hello")); +Key comparison uses the dictionary's own comparer: -var caseInsensitiveDictionary = new Dictionary(StringComparer.OrdinalIgnoreCase) -{ - ["Hello"] = "World", -}; +[!code-csharp[DictionaryContainsKeyComparerExamples](~/snippets/Snippets.NUnit/Constraints/DictionaryConstraintSnippets.cs#DictionaryContainsKeyComparerExamples)] -Assert.That(caseInsensitiveDictionary, Does.ContainKey("Hello")); -Assert.That(caseInsensitiveDictionary, Does.ContainKey("hello")); -Assert.That(caseInsensitiveDictionary, Does.Not.ContainKey("hallo")); +## Notes -// Note that the 'IgnoreCase' here is on the Value part, not the Key. -Assert.That(caseInsensitiveDictionary, Does.ContainKey("hello").WithValue("world").IgnoreCase); -``` +1. Key comparison always uses the dictionary's comparer, not NUnit's modifiers. +2. The `.WithValue()` modifier converts this to a key-value pair check. +3. As of NUnit 4.4, comparison modifiers on keys were removed as they were non-functional. -## See also +## See Also -* [DictionaryContainsValueConstraint](DictionaryContainsValueConstraint.md) -* [DictionaryContainsKeyValuePairConstraint](DictionaryContainsKeyValuePairConstraint.md) +* [DictionaryContainsValue Constraint](DictionaryContainsValueConstraint.md) +* [DictionaryContainsKeyValuePair Constraint](DictionaryContainsKeyValuePairConstraint.md) diff --git a/docs/articles/nunit/writing-tests/constraints/DictionaryContainsKeyValuePairConstraint.md b/docs/articles/nunit/writing-tests/constraints/DictionaryContainsKeyValuePairConstraint.md index 37a0306ee..5c113210c 100644 --- a/docs/articles/nunit/writing-tests/constraints/DictionaryContainsKeyValuePairConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/DictionaryContainsKeyValuePairConstraint.md @@ -2,54 +2,44 @@ uid: constraint-dictionarycontainskeyvaluepair --- -# DictionaryContainsKeyValuePairConstraint Constraint +# DictionaryContainsKeyValuePair Constraint -`DictionaryContainsKeyValuePairConstraint` is used to test whether a dictionary -contains an expected key along with an expected corresponding value. +`DictionaryContainsKeyValuePairConstraint` tests whether a dictionary contains a specific key-value pair. -## Constructor +## Usage ```csharp -public DictionaryContainsKeyValuePairConstraint(object key, object value) - : this(new KeyValuePair(key, value)) -{ -} - -protected DictionaryContainsKeyValuePairConstraint(KeyValuePair arg) - : base(arg) -{ - Expected = arg; -} +Does.ContainKey(object key).WithValue(object value) +Does.Not.ContainKey(object key).WithValue(object value) ``` -## Syntax +## Modifiers + +These modifiers apply to the **value** comparison: ```csharp -Assert.That(dictionary, new DictionaryContainsKeyValuePairConstraint("Hi", "Universe")); -Assert.That(dictionary, Does.ContainKey("Hola").WithValue("Mundo")); -Assert.That(dictionary, Does.Not.ContainKey("Hello").WithValue("NotValue")); -Assert.That(dictionary, new DictionaryContainsKeyValuePairConstraint("HI", "UNIVERSE").IgnoreCase); -Assert.That(dictionary, new DictionaryContainsKeyValuePairConstraint("HI", "UNIVERSE").Using((x, y) => string.Compare(x, y, StringComparison.CurrentCultureIgnoreCase))); +.IgnoreCase +.IgnoreWhiteSpace // NUnit 4.2+ +.Using(IComparer comparer) +.Using(IEqualityComparer comparer) +.Using(IComparer comparer) +.Using(IEqualityComparer comparer) +.Using(Comparison comparer) +.Using(Func comparer) +.UsingPropertiesComparer() // NUnit 4.1+ ``` -## Modifiers +## Examples -```csharp -...IgnoreCase -...IgnoreWhiteSpace // From version 4.2 -...Using(IComparer comparer) -...Using(IEqualityComparer comparer) -...Using(IComparer comparer) -...Using(Comparison comparer) -...Using(Func comparer) -...Using(IEqualityComparer comparer) -...UsingPropertiesComparer() // From version 4.1 -...UsingPropertiesComparer( - Func configure) // From version 4.4 -``` +[!code-csharp[DictionaryContainsKeyValuePairConstraintExamples](~/snippets/Snippets.NUnit/Constraints/DictionaryConstraintSnippets.cs#DictionaryContainsKeyValuePairConstraintExamples)] + +## Notes + +1. Key comparison uses the dictionary's comparer (cannot be overridden). +2. Value comparison modifiers (`.IgnoreCase`, `.Using()`, etc.) only apply to the value. +3. The preferred syntax is `Does.ContainKey(key).WithValue(value)` rather than the constructor form. -## See also +## See Also -* [DictionaryContainsValueConstraint](DictionaryContainsValueConstraint.md) -* [DictionaryContainsKeyConstraint](DictionaryContainsKeyConstraint.md) +* [DictionaryContainsKey Constraint](DictionaryContainsKeyConstraint.md) +* [DictionaryContainsValue Constraint](DictionaryContainsValueConstraint.md) diff --git a/docs/articles/nunit/writing-tests/constraints/DictionaryContainsValueConstraint.md b/docs/articles/nunit/writing-tests/constraints/DictionaryContainsValueConstraint.md index 1f68f478e..f06ef1863 100644 --- a/docs/articles/nunit/writing-tests/constraints/DictionaryContainsValueConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/DictionaryContainsValueConstraint.md @@ -4,51 +4,39 @@ uid: constraint-dictionarycontainsvalue # DictionaryContainsValue Constraint -`DictionaryContainsValueConstraint` is used to test whether a dictionary -contains an expected object as a value. +`DictionaryContainsValueConstraint` tests whether a dictionary contains an expected value. -## Constructor +## Usage ```csharp -DictionaryContainsValueConstraint(object) -``` - -## Syntax - -```csharp -Contains.Value(object) -Does.ContainValue(object) -Does.Not.ContainValue(object) +Contains.Value(object expectedValue) +Does.ContainValue(object expectedValue) +Does.Not.ContainValue(object expectedValue) ``` ## Modifiers ```csharp -...Using(IComparer comparer) -...Using(IEqualityComparer comparer) -...Using(IComparer comparer) -...Using(Comparison comparer) -...Using(Func comparer) -...Using(IEqualityComparer comparer) -...Using(Func comparison) -...UsingPropertiesComparer() // From version 4.1 -...UsingPropertiesComparer( - Func configure) // From version 4.4 +.IgnoreCase +.Using(IComparer comparer) +.Using(IEqualityComparer comparer) +.Using(IComparer comparer) +.Using(IEqualityComparer comparer) +.Using(Comparison comparer) +.Using(Func comparer) +.UsingPropertiesComparer() // NUnit 4.1+ ``` -## Examples of Use +## Examples -```csharp -IDictionary idict = new IDictionary { { 1, 4 }, { 2, 5 } }; +[!code-csharp[DictionaryContainsValueConstraintExamples](~/snippets/Snippets.NUnit/Constraints/DictionaryConstraintSnippets.cs#DictionaryContainsValueConstraintExamples)] -Assert.That(idict, Contains.Value(4)); -Assert.That(idict, Does.ContainValue(5)); -Assert.That(idict, Does.Not.ContainValue(3)); -Assert.That(mydict, Contains.Value(myOwnObject).Using(myComparer)); -``` +## Notes + +1. Unlike key comparison, value comparison can use NUnit's comparison modifiers. +2. The constraint checks if any value in the dictionary matches. -## See also +## See Also -* [DictionaryContainsKeyConstraint](DictionaryContainsKeyConstraint.md) -* [DictionaryContainsKeyValuePairConstraint.md](DictionaryContainsKeyValuePairConstraint.md) +* [DictionaryContainsKey Constraint](DictionaryContainsKeyConstraint.md) +* [DictionaryContainsKeyValuePair Constraint](DictionaryContainsKeyValuePairConstraint.md) diff --git a/docs/articles/nunit/writing-tests/constraints/EmptyCollectionConstraint.md b/docs/articles/nunit/writing-tests/constraints/EmptyCollectionConstraint.md index dcc004ea4..b954b30f6 100644 --- a/docs/articles/nunit/writing-tests/constraints/EmptyCollectionConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/EmptyCollectionConstraint.md @@ -4,28 +4,28 @@ uid: constraint-emptycollection # EmptyCollection Constraint -The **EmptyCollectionConstraint** tests if a Collection or other `IEnumerable` is empty. An `ArgumentException` is -thrown if the actual value is not an `IEnumerable` or is null. +`EmptyCollectionConstraint` tests that an `IEnumerable` contains no items. An `ArgumentException` is thrown if the +actual value is not an `IEnumerable` or is null. -## Constructor +## Usage ```csharp -EmptyCollectionConstraint() +Is.Empty +Is.Not.Empty ``` -## Syntax +## Examples -```csharp -Is.Empty -``` +[!code-csharp[EmptyCollectionConstraintExamples](~/snippets/Snippets.NUnit/Constraints/CollectionConstraintSnippets.cs#EmptyCollectionConstraintExamples)] -## Examples of Use +## Notes -```csharp -Assert.That(new int[] { }, Is.Empty); -Assert.That(new int[] { 1, 2, 3 }, Is.Not.Empty); -``` +1. `Is.Empty` is a polymorphic constraint that works with strings, collections, and directories. +2. When applied to an `IEnumerable`, it creates an `EmptyCollectionConstraint` internally. +3. Passing `null` throws an `ArgumentException`. Use `Is.Null.Or.Empty` pattern if null is acceptable. + +## See Also -> [!NOTE] -> `Is.Empty` actually creates an `EmptyConstraint`. Subsequently applying it to an `IEnumerable` or -> `ICollection` causes an `EmptyCollectionConstraint` to be created. +* [Empty Constraint](EmptyConstraint.md) - Polymorphic empty constraint +* [EmptyString Constraint](EmptyStringConstraint.md) - For string-specific empty tests +* [ExactCount Constraint](ExactCountConstraint.md) - Test for specific item count diff --git a/docs/articles/nunit/writing-tests/constraints/EmptyDirectoryConstraint.md b/docs/articles/nunit/writing-tests/constraints/EmptyDirectoryConstraint.md index 1310766af..f53d9f8b7 100644 --- a/docs/articles/nunit/writing-tests/constraints/EmptyDirectoryConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/EmptyDirectoryConstraint.md @@ -4,27 +4,26 @@ uid: constraint-emptydirectory # EmptyDirectory Constraint -The `EmptyDirectoryConstraint` tests if a Directory is empty. +`EmptyDirectoryConstraint` tests that a directory contains no files or subdirectories. -## Constructor +## Usage ```csharp -EmptyDirectoryConstraint() +Is.Empty +Is.Not.Empty ``` -## Syntax +## Examples -```csharp -Is.Empty -``` +[!code-csharp[EmptyDirectoryConstraintExamples](~/snippets/Snippets.NUnit/Constraints/SpecialConstraintSnippets.cs#EmptyDirectoryConstraintExamples)] -## Examples of Use +## Notes -```csharp -Assert.That(new DirectoryInfo(actual), Is.Empty); -Assert.That(new DirectoryInfo(actual), Is.Not.Empty); -``` +1. `Is.Empty` is a polymorphic constraint that works on strings, collections, and directories. +2. When applied to a `DirectoryInfo`, it checks for both files and subdirectories. +3. The directory must exist - passing a non-existent directory throws an exception. + +## See Also -> [!NOTE] -> `Is.Empty` actually creates an `EmptyConstraint`. Subsequently applying it to a `DirectoryInfo` causes an -> `EmptyDirectoryConstraint` to be created. +* [Empty Constraint](EmptyConstraint.md) - Polymorphic empty constraint +* [FileOrDirectoryExists Constraint](FileOrDirectoryExistsConstraint.md) - Test existence diff --git a/docs/articles/nunit/writing-tests/constraints/EmptyStringConstraint.md b/docs/articles/nunit/writing-tests/constraints/EmptyStringConstraint.md index 782bfccf2..22cb40491 100644 --- a/docs/articles/nunit/writing-tests/constraints/EmptyStringConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/EmptyStringConstraint.md @@ -4,27 +4,29 @@ uid: constraint-emptystring # EmptyString Constraint -The `EmptyStringConstraint` tests if a string is empty. +`EmptyStringConstraint` tests that a string has zero length. This is a specialized constraint created when `Is.Empty` is +applied to a string value. -## Constructor +## Usage ```csharp -EmptyStringConstraint() +Is.Empty +Is.Not.Empty ``` -## Syntax +## Examples -```csharp -Is.Empty -``` +[!code-csharp[EmptyStringConstraintExamples](~/snippets/Snippets.NUnit/Constraints/StringConstraintSnippets.cs#EmptyStringConstraintExamples)] -## Examples of Use +## Notes -```csharp -Assert.That(string.Empty, Is.Empty); -Assert.That("A String", Is.Not.Empty); -``` +1. `Is.Empty` is a polymorphic constraint that tests for empty strings, collections, or directories depending on the + actual value type. +2. For checking null-or-empty strings, you can combine constraints: `Is.Null.Or.Empty`. +3. To test for whitespace-only strings, use [WhiteSpaceConstraint](WhiteSpaceConstraint.md). + +## See Also -> [!NOTE] -> `Is.Empty` actually creates an `EmptyConstraint`. Subsequently applying it to a `string` causes an -> `EmptyStringConstraint` to be created. +* [Empty Constraint](EmptyConstraint.md) - Polymorphic constraint for strings, collections, directories +* [WhiteSpace Constraint](WhiteSpaceConstraint.md) +* [Null Constraint](NullConstraint.md) diff --git a/docs/articles/nunit/writing-tests/constraints/EndsWithConstraint.md b/docs/articles/nunit/writing-tests/constraints/EndsWithConstraint.md index 5c736cece..a5b96dfed 100644 --- a/docs/articles/nunit/writing-tests/constraints/EndsWithConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/EndsWithConstraint.md @@ -4,37 +4,26 @@ uid: constraint-endswith # EndsWith Constraint -`EndsWithConstraint` tests for an ending string. +`EndsWithConstraint` tests that a string ends with the expected substring. -## Constructor - -```csharp -EndsWithConstraint(string expected) -``` - -## Syntax +## Usage ```csharp Does.EndWith(string expected) -EndsWith(string expected) +Does.Not.EndWith(string expected) ``` ## Modifiers ```csharp -...IgnoreCase -...Using(StringComparison comparisonType) -...Using(CultureInfo culture) +.IgnoreCase +.Using(StringComparison comparisonType) +.Using(CultureInfo culture) ``` -## Examples of Use +## Examples -```csharp -string phrase = "Make your tests fail before passing!"; - -Assert.That(phrase, Does.EndWith("!")); -Assert.That(phrase, Does.EndWith("PASSING!").IgnoreCase); -``` +[!code-csharp[EndsWithConstraintExamples](~/snippets/Snippets.NUnit/Constraints/StringConstraintSnippets.cs#EndsWithConstraintExamples)] ### Specifying a StringComparison @@ -58,6 +47,11 @@ Assert.That("Main Straße", Does.EndWith("Straße").Using(new CultureInfo("de-DE ## Notes -1. **EndsWith** may appear only in the body of a constraint expression or when the inherited syntax is used. -2. Only one `Using` modifier may be specified. Attempting to use multiple `Using` modifiers - will throw an `InvalidOperationException`. +1. Only one `Using` modifier may be specified. Attempting to use multiple `Using` modifiers will throw an + `InvalidOperationException`. + +## See Also + +* [StartsWith Constraint](StartsWithConstraint.md) +* [Substring Constraint](SubstringConstraint.md) +* [Regex Constraint](RegexConstraint.md) diff --git a/docs/articles/nunit/writing-tests/constraints/ExactCountConstraint.md b/docs/articles/nunit/writing-tests/constraints/ExactCountConstraint.md index d38763eac..ad39b0e1b 100644 --- a/docs/articles/nunit/writing-tests/constraints/ExactCountConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/ExactCountConstraint.md @@ -4,46 +4,29 @@ uid: constraint-exactcount # ExactCount Constraint -`ExactCountConstraint` has two functions. +`ExactCountConstraint` tests that an `IEnumerable` contains exactly a specified number of items that match an optional +constraint. An exception is thrown if the actual value does not implement `IEnumerable`. -In its simplest use, it simply verifies the number of items in an array, collection or `IEnumerable`, providing a way to -count items that is independent of any `Length` or `Count` property. - -When used with another constraint, it applies that constraint to each item in the array, collection or `IEnumerable`, -succeeding if the specified number of items succeed. - -An exception is thrown if the actual value passed does not implement `IEnumerable`. - -## Constructor +## Usage ```csharp -ExactCountConstraint(int expectedCount) -ExactCountConstraint(int expectedCount, Constraint itemConstraint) +Has.Exactly(int count).Items +Has.Exactly(int count). ``` -## Syntax +## Examples -```csharp -Has.Exactly(int expectedCount)... -``` +[!code-csharp[ExactCountConstraintExamples](~/snippets/Snippets.NUnit/Constraints/CollectionConstraintSnippets.cs#ExactCountConstraintExamples)] -## Examples of Use - -```csharp -int[] array = new int[] { 1, 2, 3 }; - -Assert.That(array, Has.Exactly(3).Items); -Assert.That(array, Has.Exactly(2).Items.GreaterThan(1)); -Assert.That(array, Has.Exactly(3).LessThan(100)); -Assert.That(array, Has.Exactly(2).Items.EqualTo(1).Or.EqualTo(3)); -Assert.That(array, Has.Exactly(1).EqualTo(1).And.Exactly(1).EqualTo(3)); -``` +## Notes -> [!NOTE] -> The keyword `Items` is optional when used before a constraint but required when merely counting items with no -> constraint specified. +1. The `Items` keyword is required when counting total items (no constraint). It's optional when a constraint follows. +2. `Has.Exactly(0)` is useful for asserting that no items match a condition. +3. For simple count/length checks, consider using [PropertyConstraint](PropertyConstraint.md) with `Has.Count` or + `Has.Length`. -## See also +## See Also -* [PropertyConstraint](PropertyConstraint.md) - For constraints on the `Count` or `Length` property, e.g. - `Has.Count.GreaterThan(10)` or `Has.Length.EqualTo(6)`. +* [AllItems Constraint](AllItemsConstraint.md) - All items must match +* [SomeItems Constraint](SomeItemsConstraint.md) - At least one item matches +* [Property Constraint](PropertyConstraint.md) - Test `Count` or `Length` properties directly diff --git a/docs/articles/nunit/writing-tests/constraints/ExactTypeConstraint.md b/docs/articles/nunit/writing-tests/constraints/ExactTypeConstraint.md index 6d357fe97..9a335b0f3 100644 --- a/docs/articles/nunit/writing-tests/constraints/ExactTypeConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/ExactTypeConstraint.md @@ -4,21 +4,26 @@ uid: constraint-exacttype # ExactType Constraint -`ExactTypeConstraint` tests that an object is an exact Type. +`ExactTypeConstraint` tests that an object is exactly the specified type, not a derived type. -## Constructor +## Usage ```csharp -ExactTypeConstraint(Type) +Is.TypeOf(Type expectedType) +Is.TypeOf() ``` -## Syntax +## Examples -```csharp -Is.TypeOf(Type) -Is.TypeOf() -``` +[!code-csharp[ExactTypeConstraintExamples](~/snippets/Snippets.NUnit/Constraints/TypeConstraintSnippets.cs#ExactTypeConstraintExamples)] + +## Notes + +1. `Is.TypeOf()` checks that `actual.GetType() == typeof(T)`. +2. For inheritance-aware type checking (like C# `is`), use [InstanceOfTypeConstraint](InstanceOfTypeConstraint.md). +3. `null` values throw an exception since they have no type. -## Examples of Use +## See Also -[!code-csharp[TypeConstraintExamples](~/snippets/Snippets.NUnit/ConstraintExamples.cs#TypeConstraintExamples)] +* [InstanceOfType Constraint](InstanceOfTypeConstraint.md) - Inheritance-aware type checking +* [AssignableTo Constraint](AssignableToConstraint.md) - Type assignability check diff --git a/docs/articles/nunit/writing-tests/constraints/FalseConstraint.md b/docs/articles/nunit/writing-tests/constraints/FalseConstraint.md index d6c03f84c..93a12c377 100644 --- a/docs/articles/nunit/writing-tests/constraints/FalseConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/FalseConstraint.md @@ -16,15 +16,7 @@ Is.Not.False // equivalent to Is.True ## Examples -```csharp -Assert.That(2 + 2 == 5, Is.False); -Assert.That(isDisabled, Is.False); -Assert.That(list.IsReadOnly, Is.False); - -// With nullable booleans -bool? isDeleted = false; -Assert.That(isDeleted, Is.False); -``` +[!code-csharp[FalseConstraintExamples](~/snippets/Snippets.NUnit/Constraints/ComparisonConstraintSnippets.cs#FalseConstraintExamples)] ## Notes diff --git a/docs/articles/nunit/writing-tests/constraints/FileOrDirectoryExistsConstraint.md b/docs/articles/nunit/writing-tests/constraints/FileOrDirectoryExistsConstraint.md index 2cf9ccd75..39f728bfb 100644 --- a/docs/articles/nunit/writing-tests/constraints/FileOrDirectoryExistsConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/FileOrDirectoryExistsConstraint.md @@ -4,15 +4,9 @@ uid: constraint-fileordirectoryexists # FileOrDirectoryExists Constraint -`FileOrDirectoryExistsConstraint` tests that a File or Directory exists. +`FileOrDirectoryExistsConstraint` tests that a file or directory exists at the specified path. -## Constructor - -```csharp -FileOrDirectoryExistsConstraint() -``` - -## Syntax +## Usage ```csharp Does.Exist @@ -22,10 +16,22 @@ Does.Not.Exist ## Modifiers ```csharp -.IgnoreDirectories -.IgnoreFiles +.IgnoreDirectories // Only check for file existence +.IgnoreFiles // Only check for directory existence ``` -## Examples of Use +## Examples + +[!code-csharp[FileOrDirectoryExistsConstraintExamples](~/snippets/Snippets.NUnit/Constraints/SpecialConstraintSnippets.cs#FileOrDirectoryExistsConstraintExamples)] + +## Notes + +1. The constraint accepts string paths, `FileInfo`, or `DirectoryInfo` objects. +2. By default, the constraint passes if either a file or directory exists at the path. +3. Use `.IgnoreDirectories` to require a file specifically. +4. Use `.IgnoreFiles` to require a directory specifically. + +## See Also -[!code-csharp[FileConstraintExamples](~/snippets/Snippets.NUnit/ConstraintExamples.cs#FileConstraintExamples)] +* [EmptyDirectory Constraint](EmptyDirectoryConstraint.md) - Test if directory is empty +* [SamePath Constraint](SamePathConstraint.md) - Compare paths diff --git a/docs/articles/nunit/writing-tests/constraints/GreaterThanConstraint.md b/docs/articles/nunit/writing-tests/constraints/GreaterThanConstraint.md index c8c2bcd0e..28a062004 100644 --- a/docs/articles/nunit/writing-tests/constraints/GreaterThanConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/GreaterThanConstraint.md @@ -26,17 +26,7 @@ Is.Positive // Equivalent to Is.GreaterThan(0) ## Examples -```csharp -Assert.That(7, Is.GreaterThan(3)); -Assert.That(5, Is.Positive); -Assert.That(-3, Is.Not.Positive); - -// With DateTime -Assert.That(DateTime.Now, Is.GreaterThan(DateTime.Today)); - -// With tolerance -Assert.That(10.5, Is.GreaterThan(10.0).Within(0.1)); -``` +[!code-csharp[GreaterThanConstraintExamples](~/snippets/Snippets.NUnit/Constraints/ComparisonConstraintSnippets.cs#GreaterThanConstraintExamples)] ### Using Custom Comparers diff --git a/docs/articles/nunit/writing-tests/constraints/GreaterThanOrEqualConstraint.md b/docs/articles/nunit/writing-tests/constraints/GreaterThanOrEqualConstraint.md index 15d44db3c..72d4ddb72 100644 --- a/docs/articles/nunit/writing-tests/constraints/GreaterThanOrEqualConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/GreaterThanOrEqualConstraint.md @@ -4,34 +4,41 @@ uid: constraint-greaterthanorequal # GreaterThanOrEqual Constraint -`GreaterThanOrEqualConstraint` tests that one value is greater than or equal to another. +`GreaterThanOrEqualConstraint` tests that one value is greater than or equal to another. It works with numeric types, +`DateTime`, `TimeSpan`, and any type implementing `IComparable`. For custom types, a user-specified comparer can be +provided using the `Using` modifier. -It works with numeric types, `DateTime`, `TimeSpan`, and any type implementing `IComparable`. For custom types, a -user-specified comparer can be provided using the `Using` modifier. - -## Constructor - -```csharp -GreaterThanOrEqualConstraint(object expected) -``` - -## Syntax +## Usage ```csharp Is.GreaterThanOrEqualTo(object expected) -Is.AtLeast(object expected) +Is.AtLeast(object expected) // Alias for GreaterThanOrEqualTo ``` ## Modifiers ```csharp -...Using(IComparer comparer) -...Using(IComparer comparer) -...Using(Comparison comparer) -...Within(object tolerance) +.Using(IComparer comparer) +.Using(IComparer comparer) +.Using(Comparison comparer) +.Within(object tolerance) ``` -## Examples of Use +## Examples + +[!code-csharp[GreaterThanOrEqualConstraintExamples](~/snippets/Snippets.NUnit/Constraints/ComparisonConstraintSnippets.cs#GreaterThanOrEqualConstraintExamples)] + +### Using Custom Comparers -[!code-csharp[GreaterThanOrEqualExamples](~/snippets/Snippets.NUnit/ConstraintExamples.cs#GreaterThanOrEqualExamples)] [!code-csharp[With Comparer](~/snippets/Snippets.NUnit/ConstraintExamples.cs#MyComparerExample)] + +## Notes + +1. `Is.AtLeast` is a more readable alias for `Is.GreaterThanOrEqualTo`. +2. When comparing floating-point numbers, consider using `.Within()` to specify a tolerance. + +## See Also + +* [GreaterThan Constraint](GreaterThanConstraint.md) +* [LessThanOrEqual Constraint](LessThanOrEqualConstraint.md) +* [Range Constraint](RangeConstraint.md) diff --git a/docs/articles/nunit/writing-tests/constraints/InstanceOfTypeConstraint.md b/docs/articles/nunit/writing-tests/constraints/InstanceOfTypeConstraint.md index e31345da5..904ec48c2 100644 --- a/docs/articles/nunit/writing-tests/constraints/InstanceOfTypeConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/InstanceOfTypeConstraint.md @@ -4,21 +4,28 @@ uid: constraint-instanceoftype # InstanceOfType Constraint -`InstanceOfTypeConstraint` tests that an object is of the type supplied or a derived type. +`InstanceOfTypeConstraint` tests that an object is an instance of the specified type or any derived type. This is +equivalent to the C# `is` operator. -## Constructor +## Usage ```csharp -InstanceOfTypeConstraint(Type) +Is.InstanceOf(Type expectedType) +Is.InstanceOf() ``` -## Syntax +## Examples -```csharp -Is.InstanceOf(Type) -Is.InstanceOf() -``` +[!code-csharp[InstanceOfTypeConstraintExamples](~/snippets/Snippets.NUnit/Constraints/TypeConstraintSnippets.cs#InstanceOfTypeConstraintExamples)] + +## Notes + +1. `Is.InstanceOf()` is equivalent to C#'s `value is T` expression. +2. For exact type matching (no inheritance), use [ExactTypeConstraint](ExactTypeConstraint.md). +3. `null` always fails `Is.InstanceOf` for any type. -## Examples of Use +## See Also -[!code-csharp[TypeConstraintExamples](~/snippets/Snippets.NUnit/ConstraintExamples.cs#TypeConstraintExamples)] +* [ExactType Constraint](ExactTypeConstraint.md) - Exact type match, no inheritance +* [AssignableTo Constraint](AssignableToConstraint.md) - Type assignability check +* [AssignableFrom Constraint](AssignableFromConstraint.md) - Reverse assignability check diff --git a/docs/articles/nunit/writing-tests/constraints/LessThanConstraint.md b/docs/articles/nunit/writing-tests/constraints/LessThanConstraint.md index 8dae48f1d..c520a1a24 100644 --- a/docs/articles/nunit/writing-tests/constraints/LessThanConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/LessThanConstraint.md @@ -26,17 +26,7 @@ Is.Negative // Equivalent to Is.LessThan(0) ## Examples -```csharp -Assert.That(3, Is.LessThan(7)); -Assert.That(-5, Is.Negative); -Assert.That(5, Is.Not.Negative); - -// With DateTime -Assert.That(DateTime.Today, Is.LessThan(DateTime.Now)); - -// With tolerance -Assert.That(9.5, Is.LessThan(10.0).Within(0.1)); -``` +[!code-csharp[LessThanConstraintExamples](~/snippets/Snippets.NUnit/Constraints/ComparisonConstraintSnippets.cs#LessThanConstraintExamples)] ### Using Custom Comparers diff --git a/docs/articles/nunit/writing-tests/constraints/LessThanOrEqualConstraint.md b/docs/articles/nunit/writing-tests/constraints/LessThanOrEqualConstraint.md index 636373251..06288b62d 100644 --- a/docs/articles/nunit/writing-tests/constraints/LessThanOrEqualConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/LessThanOrEqualConstraint.md @@ -4,34 +4,41 @@ uid: constraint-lessthanorequal # LessThanOrEqual Constraint -`LessThanOrEqualConstraint` tests that one value is less than or equal to another. +`LessThanOrEqualConstraint` tests that one value is less than or equal to another. It works with numeric types, +`DateTime`, `TimeSpan`, and any type implementing `IComparable`. For custom types, a user-specified comparer can be +provided using the `Using` modifier. -It works with numeric types, `DateTime`, `TimeSpan`, and any type implementing `IComparable`. For custom types, a -user-specified comparer can be provided using the `Using` modifier. - -## Constructor - -```csharp -LessThanOrEqualConstraint(object expected) -``` - -## Syntax +## Usage ```csharp Is.LessThanOrEqualTo(object expected) -Is.AtMost(object expected) +Is.AtMost(object expected) // Alias for LessThanOrEqualTo ``` ## Modifiers ```csharp -...Using(IComparer comparer) -...Using(IComparer comparer) -...Using(Comparison comparer) -...Within(object tolerance) +.Using(IComparer comparer) +.Using(IComparer comparer) +.Using(Comparison comparer) +.Within(object tolerance) ``` -## Examples of Use +## Examples + +[!code-csharp[LessThanOrEqualConstraintExamples](~/snippets/Snippets.NUnit/Constraints/ComparisonConstraintSnippets.cs#LessThanOrEqualConstraintExamples)] + +### Using Custom Comparers -[!code-csharp[LessThanOrEqualExamples](~/snippets/Snippets.NUnit/ConstraintExamples.cs#LessThanOrEqualExamples)] [!code-csharp[With Comparer](~/snippets/Snippets.NUnit/ConstraintExamples.cs#MyComparerExample)] + +## Notes + +1. `Is.AtMost` is a more readable alias for `Is.LessThanOrEqualTo`. +2. When comparing floating-point numbers, consider using `.Within()` to specify a tolerance. + +## See Also + +* [LessThan Constraint](LessThanConstraint.md) +* [GreaterThanOrEqual Constraint](GreaterThanOrEqualConstraint.md) +* [Range Constraint](RangeConstraint.md) diff --git a/docs/articles/nunit/writing-tests/constraints/MultipleOfConstraint.md b/docs/articles/nunit/writing-tests/constraints/MultipleOfConstraint.md new file mode 100644 index 000000000..9c3fdc298 --- /dev/null +++ b/docs/articles/nunit/writing-tests/constraints/MultipleOfConstraint.md @@ -0,0 +1,32 @@ +--- +uid: constraint-multipleof +--- + +# MultipleOf Constraint + +`MultipleOfConstraint` tests that a numeric value is a multiple of a specified number. It also provides convenient +shortcuts for testing even and odd numbers. + +## Usage + +```csharp +Is.MultipleOf(int factor) +Is.Even +Is.Odd +``` + +## Examples + +[!code-csharp[MultipleOfConstraintExamples](~/snippets/Snippets.NUnit/Constraints/SpecialConstraintSnippets.cs#MultipleOfConstraintExamples)] + +## Notes + +1. `Is.Even` is equivalent to `Is.MultipleOf(2)`. +2. `Is.Odd` is the negation - a number that is not a multiple of 2. +3. Works with all integer types (`int`, `long`, `short`, etc.). +4. Zero is considered even (`Is.MultipleOf(n)` passes for any `n` when actual is 0). + +## See Also + +* [Range Constraint](RangeConstraint.md) - Test if value is within a range +* [GreaterThan Constraint](GreaterThanConstraint.md) - Numeric comparisons diff --git a/docs/articles/nunit/writing-tests/constraints/NaNConstraint.md b/docs/articles/nunit/writing-tests/constraints/NaNConstraint.md index 602a94130..3c5d54d4c 100644 --- a/docs/articles/nunit/writing-tests/constraints/NaNConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/NaNConstraint.md @@ -4,23 +4,25 @@ uid: constraint-nan # NaN Constraint -`NaNConstraint` tests that a value is floating-point NaN. +`NaNConstraint` tests that a floating-point value is `NaN` (Not a Number). -## Constructor +## Usage ```csharp -NaNConstraint() +Is.NaN +Is.Not.NaN ``` -## Syntax +## Examples -```csharp -Is.NaN -``` +[!code-csharp[NaNConstraintExamples](~/snippets/Snippets.NUnit/Constraints/SpecialConstraintSnippets.cs#NaNConstraintExamples)] -## Examples of Use +## Notes -```csharp -Assert.That(aDouble, Is.NaN); -Assert.That(aDouble, Is.Not.NaN); -``` +1. NaN is the only value that is not equal to itself (`NaN != NaN` is true). +2. Both `double.NaN` and `float.NaN` are supported. +3. Infinity values are not NaN. + +## See Also + +* [EqualConstraint](EqualConstraint.md) - For numeric comparisons with tolerance diff --git a/docs/articles/nunit/writing-tests/constraints/NoItemConstraint.md b/docs/articles/nunit/writing-tests/constraints/NoItemConstraint.md index 0817def8d..47c6994a6 100644 --- a/docs/articles/nunit/writing-tests/constraints/NoItemConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/NoItemConstraint.md @@ -4,27 +4,27 @@ uid: constraint-noitem # NoItem Constraint -`NoItemConstraint` applies a constraint to each item in a collection, succeeding only if all of them fail. An exception -is thrown if the actual value passed does not implement `IEnumerable`. +`NoItemConstraint` applies a constraint to each item in an `IEnumerable`, succeeding only if no items satisfy the +constraint. An exception is thrown if the actual value does not implement `IEnumerable`. -## Constructor +## Usage ```csharp -NoItemConstraint(Constraint itemConstraint) +Has.None. ``` -## Syntax +## Examples -```csharp -Has.None... -``` +[!code-csharp[NoItemConstraintExamples](~/snippets/Snippets.NUnit/Constraints/CollectionConstraintSnippets.cs#NoItemConstraintExamples)] -## Examples of Use +## Notes -```csharp -int[] iarray = new int[] { 1, 2, 3 }; -string[] sarray = new string[] { "a", "b", "c" }; -Assert.That(iarray, Has.None.Null); -Assert.That(sarray, Has.None.EqualTo("d")); -Assert.That(iarray, Has.None.LessThan(0)); -``` +1. `Has.None` is the inverse of `Has.Some` - the constraint passes if no items match. +2. The constraint fails as soon as the first matching item is found. +3. An empty collection satisfies `Has.None` for any constraint. + +## See Also + +* [AllItems Constraint](AllItemsConstraint.md) - All items must match +* [SomeItems Constraint](SomeItemsConstraint.md) - At least one item matches +* [ExactCount Constraint](ExactCountConstraint.md) - Specific number of items match diff --git a/docs/articles/nunit/writing-tests/constraints/NotConstraint.md b/docs/articles/nunit/writing-tests/constraints/NotConstraint.md index 0b4a1b6fe..6e8c643a3 100644 --- a/docs/articles/nunit/writing-tests/constraints/NotConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/NotConstraint.md @@ -4,21 +4,28 @@ uid: constraint-not # Not Constraint -`NotConstraint` reverses the effect of another constraint. If the base constraint fails, NotConstraint succeeds. If the -base constraint succeeds, NotConstraint fails. +`NotConstraint` negates another constraint. It succeeds when the inner constraint fails, and fails when the inner +constraint succeeds. -## Constructor +## Usage ```csharp -NotConstraint() +Is.Not. +Does.Not. +Has.No. ``` -## Syntax +## Examples -```csharp -Is.Not... -``` +[!code-csharp[NotConstraintExamples](~/snippets/Snippets.NUnit/Constraints/CompoundConstraintSnippets.cs#NotConstraintExamples)] + +## Notes + +1. `Is.Not`, `Does.Not`, and `Has.No` are all ways to negate constraints. +2. `Has.No` is specifically for collection constraints (equivalent to `Has.None`). +3. Negation applies to the immediately following constraint. -## Examples of Use +## See Also -[!code-csharp[NotConstraintExamples](~/snippets/Snippets.NUnit/ConstraintExamples.cs#NotConstraintExamples)] +* [And Constraint](AndConstraint.md) - Combine constraints +* [Or Constraint](OrConstraint.md) - Alternative constraints diff --git a/docs/articles/nunit/writing-tests/constraints/NullConstraint.md b/docs/articles/nunit/writing-tests/constraints/NullConstraint.md index 03025e95f..526f62cf4 100644 --- a/docs/articles/nunit/writing-tests/constraints/NullConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/NullConstraint.md @@ -16,17 +16,7 @@ Is.Not.Null ## Examples -```csharp -object? obj = null; -Assert.That(obj, Is.Null); - -string? name = GetName(); -Assert.That(name, Is.Not.Null); - -// Combining with other constraints -Assert.That(result, Is.Not.Null.And.Not.Empty); -Assert.That(GetOptionalValue(), Is.Null.Or.GreaterThan(0)); -``` +[!code-csharp[NullConstraintExamples](~/snippets/Snippets.NUnit/Constraints/ComparisonConstraintSnippets.cs#NullConstraintExamples)] ## Notes diff --git a/docs/articles/nunit/writing-tests/constraints/OrConstraint.md b/docs/articles/nunit/writing-tests/constraints/OrConstraint.md index 4d6fb4c08..7b52e8ea2 100644 --- a/docs/articles/nunit/writing-tests/constraints/OrConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/OrConstraint.md @@ -4,33 +4,29 @@ uid: constraint-or # Or Constraint -`OrConstraint` combines two other constraints and succeeds if either of them succeeds. +`OrConstraint` combines two constraints and succeeds if either one succeeds. -## Constructor +## Usage ```csharp -OrConstraint(Constraint left, Constraint right) +.Or. ``` -## Syntax +## Examples -```csharp -.Or. -``` - -## Examples of Use - -[!code-csharp[OrConstraintExamples](~/snippets/Snippets.NUnit/ConstraintExamples.cs#OrConstraintExamples)] +[!code-csharp[OrConstraintExamples](~/snippets/Snippets.NUnit/Constraints/CompoundConstraintSnippets.cs#OrConstraintExamples)] ## Evaluation Order and Precedence -Note that the constraint evaluates the sub-constraints left to right, meaning that -`Assert.That(i,Is.Null.Or.GreaterThan(9));` where `i` is a nullable `int` will work for both `12` and `null`. On the -other hand, `Assert.That(i, Is.GreaterThan(9).Or.Null);` will only work for `12`, but throw an exception for `null`, as -`null` cannot be compared to `9`. +Constraints are evaluated **left to right** and short-circuit when one succeeds: + +[!code-csharp[OrConstraintNullPatternExamples](~/snippets/Snippets.NUnit/Constraints/CompoundConstraintSnippets.cs#OrConstraintNullPatternExamples)] -The **OrConstraint** has precedence over the **AndConstraint**. +> [!NOTE] +> `Or` has higher precedence than `And`. The expression `A.And.B.Or.C` is evaluated as `A.And.(B.Or.C)`. -## See also +## See Also -* [AndConstraint](AndConstraint.md) +* [And Constraint](AndConstraint.md) - Both conditions must be true +* [Not Constraint](NotConstraint.md) - Negate a constraint +* [AnyOf Constraint](AnyOfConstraint.md) - Value equals any of several options diff --git a/docs/articles/nunit/writing-tests/constraints/PropertyConstraint.md b/docs/articles/nunit/writing-tests/constraints/PropertyConstraint.md index 572cdbb03..1c037137a 100644 --- a/docs/articles/nunit/writing-tests/constraints/PropertyConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/PropertyConstraint.md @@ -4,35 +4,38 @@ uid: constraint-property # Property Constraint -`PropertyConstraint` tests for the existence of a named property on an object and then applies a constraint test to the -property value. +`PropertyConstraint` tests the value of a named property on an object against a further constraint. -## Constructor +## Usage ```csharp -PropertyConstraint(string name, IConstraint baseConstraint) +Has.Property(string propertyName). +Has.Length. +Has.Count. +Has.Message. +Has.InnerException. ``` -## Syntax +## Examples -```csharp -Has.Property(string name)... // followed by further constraint syntax -``` - -## Examples of Use +[!code-csharp[PropertyConstraintExamples](~/snippets/Snippets.NUnit/Constraints/SpecialConstraintSnippets.cs#PropertyConstraintExamples)] -[!code-csharp[PropertyConstraintExamples](~/snippets/Snippets.NUnit/ConstraintExamples.cs#PropertyConstraintExamples)] - -As shown in the example, certain common properties are known to NUnit and may be tested using a shorter form. The -following properties are supported: +### Built-in Property Shortcuts ```csharp -Has.Length... -Has.Count... -Has.Message... -Has.InnerException... +Has.Length // Equivalent to Has.Property("Length") +Has.Count // Equivalent to Has.Property("Count") +Has.Message // Equivalent to Has.Property("Message") +Has.InnerException // Equivalent to Has.Property("InnerException") ``` -## See also +## Notes + +1. If no constraint follows `Has.Property()`, it becomes a [PropertyExistsConstraint](PropertyExistsConstraint.md). +2. The property must be public and readable. +3. If the property doesn't exist, the constraint fails with a descriptive message. + +## See Also -* [PropertyExistsConstraint](PropertyExistsConstraint.md) +* [PropertyExists Constraint](PropertyExistsConstraint.md) - Just test for property existence +* [ExactCount Constraint](ExactCountConstraint.md) - Count items matching a constraint diff --git a/docs/articles/nunit/writing-tests/constraints/PropertyExistsConstraint.md b/docs/articles/nunit/writing-tests/constraints/PropertyExistsConstraint.md index d9b020388..51990b69a 100644 --- a/docs/articles/nunit/writing-tests/constraints/PropertyExistsConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/PropertyExistsConstraint.md @@ -4,26 +4,24 @@ uid: constraint-propertyexists # PropertyExists Constraint -The `PropertyExistsConstraint` tests for the existence of a named property on an object. +`PropertyExistsConstraint` tests for the existence of a named property on an object. -## Constructor +## Usage ```csharp -PropertyExistsConstraint(string name) +Has.Property(string propertyName) ``` -## Syntax +## Examples -```csharp -Has.Property(string) -``` +[!code-csharp[PropertyExistsConstraintExamples](~/snippets/Snippets.NUnit/Constraints/SpecialConstraintSnippets.cs#PropertyExistsConstraintExamples)] -## Examples of Use +## Notes -```csharp -Assert.That(someObject, Has.Property("Version")); -``` +1. When no constraint is chained after `Has.Property()`, it creates a `PropertyExistsConstraint`. +2. When a constraint follows (e.g., `.EqualTo(5)`), it becomes a [PropertyConstraint](PropertyConstraint.md). +3. The property must be public and readable. -## See also +## See Also -* [PropertyConstraint](PropertyConstraint.md) +* [Property Constraint](PropertyConstraint.md) - Test property values diff --git a/docs/articles/nunit/writing-tests/constraints/RangeConstraint.md b/docs/articles/nunit/writing-tests/constraints/RangeConstraint.md index bc1095cc6..7bca81ec0 100644 --- a/docs/articles/nunit/writing-tests/constraints/RangeConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/RangeConstraint.md @@ -4,15 +4,10 @@ uid: constraint-range # Range Constraint -`RangeConstraint` tests that a value is in an (inclusive) range. +`RangeConstraint` tests that a value falls within an inclusive range. Both the lower and upper bounds are included in +the valid range. -## Constructor - -```csharp -RangeConstraint(IComparable from, IComparable to) -``` - -## Syntax +## Usage ```csharp Is.InRange(IComparable from, IComparable to) @@ -21,11 +16,26 @@ Is.InRange(IComparable from, IComparable to) ## Modifiers ```csharp -...Using(IComparer comparer) -...Using(IComparer comparer) -...Using(Comparison comparer) +.Using(IComparer comparer) +.Using(IComparer comparer) +.Using(Comparison comparer) ``` -## Examples of Use +## Examples + +[!code-csharp[RangeConstraintExamples](~/snippets/Snippets.NUnit/Constraints/ComparisonConstraintSnippets.cs#RangeConstraintExamples)] + +## Notes + +1. The range is **inclusive** on both ends: `Is.InRange(1, 10)` passes for values 1, 10, and everything in between. +2. For exclusive bounds, combine `Is.GreaterThan` and `Is.LessThan` with `And`: + ```csharp + Assert.That(5, Is.GreaterThan(1).And.LessThan(10)); // Exclusive bounds + ``` + +## See Also -[!code-csharp[RangeConstraintExamples](~/snippets/Snippets.NUnit/ConstraintExamples.cs#RangeConstraintExamples)] +* [GreaterThan Constraint](GreaterThanConstraint.md) +* [LessThan Constraint](LessThanConstraint.md) +* [GreaterThanOrEqual Constraint](GreaterThanOrEqualConstraint.md) +* [LessThanOrEqual Constraint](LessThanOrEqualConstraint.md) diff --git a/docs/articles/nunit/writing-tests/constraints/RegexConstraint.md b/docs/articles/nunit/writing-tests/constraints/RegexConstraint.md index a8037076d..6e19b024c 100644 --- a/docs/articles/nunit/writing-tests/constraints/RegexConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/RegexConstraint.md @@ -2,40 +2,39 @@ uid: constraint-regex --- -# RegexConstraint +# Regex Constraint -`RegexConstraint` tests that a pattern is matched. +`RegexConstraint` tests that a string matches a regular expression pattern. -## Constructor - -```csharp -RegexConstraint(string pattern) -``` - -## Syntax +## Usage ```csharp Does.Match(string pattern) -Matches(string pattern) +Does.Not.Match(string pattern) ``` ## Modifiers ```csharp -...IgnoreCase +.IgnoreCase ``` -## Examples of Use +## Examples -```csharp -string phrase = "Make your tests fail before passing!"; +[!code-csharp[RegexConstraintExamples](~/snippets/Snippets.NUnit/Constraints/StringConstraintSnippets.cs#RegexConstraintExamples)] -Assert.That(phrase, Does.Match("Make.*tests.*pass")); -Assert.That(phrase, Does.Match("make.*tests.*PASS").IgnoreCase); -Assert.That(phrase, Does.Not.Match("your.*passing.*tests")); -``` +### Common Pattern Examples + +[!code-csharp[RegexConstraintPatternExamples](~/snippets/Snippets.NUnit/Constraints/StringConstraintSnippets.cs#RegexConstraintPatternExamples)] ## Notes -1. **Matches** may appear only in the body of a constraint - expression or when the inherited syntax is used. +1. The pattern uses .NET regular expression syntax. +2. The entire string does not need to match - use `^` and `$` anchors if you need a full match. +3. For simple substring matching, consider using [SubstringConstraint](SubstringConstraint.md) instead. + +## See Also + +* [Substring Constraint](SubstringConstraint.md) +* [StartsWith Constraint](StartsWithConstraint.md) +* [EndsWith Constraint](EndsWithConstraint.md) diff --git a/docs/articles/nunit/writing-tests/constraints/SameAsConstraint.md b/docs/articles/nunit/writing-tests/constraints/SameAsConstraint.md index cd38c388a..a19d202b6 100644 --- a/docs/articles/nunit/writing-tests/constraints/SameAsConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/SameAsConstraint.md @@ -4,28 +4,26 @@ uid: constraint-sameas # SameAs Constraint -A `SameAsConstraint` is used to test whether the object passed -as an actual value has the same identity as the object supplied -in its constructor. +`SameAsConstraint` tests whether the actual value is the same object instance as the expected value (reference +equality). This is different from `Is.EqualTo`, which tests for value equality. -## Constructor +## Usage ```csharp -SameAsConstraint(object expected) +Is.SameAs(object expected) +Is.Not.SameAs(object expected) ``` -## Syntax +## Examples -```csharp -Is.SameAs(object expected) -``` +[!code-csharp[SameAsConstraintExamples](~/snippets/Snippets.NUnit/Constraints/SpecialConstraintSnippets.cs#SameAsConstraintExamples)] -## Examples of Use +## Notes -```csharp -Exception ex1 = new Exception(); -Exception ex2 = ex1; -Assert.That(ex2, Is.SameAs(ex1)); -Exception ex3 = new Exception(); -Assert.That(ex3, Is.Not.SameAs(ex1)); -``` +1. `Is.SameAs` uses `object.ReferenceEquals()` internally - it tests object identity, not equality. +2. For value types, `Is.SameAs` will always fail because value types are boxed into different objects. +3. Use `Is.EqualTo` when you want to compare values; use `Is.SameAs` when you need to verify the exact same instance. + +## See Also + +* [Equal Constraint](EqualConstraint.md) - For value equality diff --git a/docs/articles/nunit/writing-tests/constraints/SamePathConstraint.md b/docs/articles/nunit/writing-tests/constraints/SamePathConstraint.md index f402469db..615d923d9 100644 --- a/docs/articles/nunit/writing-tests/constraints/SamePathConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/SamePathConstraint.md @@ -27,13 +27,7 @@ Is.SamePath(string expectedPath) ## Examples of Use -```csharp -Assert.That("/folder1/./junk/../folder2", Is.SamePath("/folder1/folder2")); -Assert.That("/folder1/./junk/../folder2/x", Is.Not.SamePath("/folder1/folder2")); - -Assert.That(@"C:\folder1\folder2", Is.SamePath(@"C:\Folder1\Folder2").IgnoreCase); -Assert.That("/folder1/folder2", Is.Not.SamePath("/Folder1/Folder2").RespectCase); -``` +[!code-csharp[SamePathConstraintExamples](~/snippets/Snippets.NUnit/Constraints/PathConstraintSnippets.cs#SamePathConstraintExamples)] ## Notes diff --git a/docs/articles/nunit/writing-tests/constraints/SamePathOrUnderConstraint.md b/docs/articles/nunit/writing-tests/constraints/SamePathOrUnderConstraint.md index 4a2b18ac6..b1e2bebda 100644 --- a/docs/articles/nunit/writing-tests/constraints/SamePathOrUnderConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/SamePathOrUnderConstraint.md @@ -27,14 +27,7 @@ Is.SamePathOrUnder(string expectedPath) ## Examples of Use -```csharp -Assert.That("/folder1/./junk/../folder2", Is.SamePathOrUnder("/folder1/folder2")); -Assert.That("/folder1/junk/../folder2/./folder3", Is.SamePathOrUnder("/folder1/folder2")); -Assert.That("/folder1/junk/folder2/folder3", Is.Not.SamePathOrUnder("/folder1/folder2")); - -Assert.That(@"C:\folder1\folder2\folder3", Is.SamePathOrUnder(@"C:\Folder1\Folder2").IgnoreCase); -Assert.That("/folder1/folder2/folder3", Is.Not.SamePathOrUnder("/Folder1/Folder2").RespectCase); -``` +[!code-csharp[SamePathOrUnderConstraintExamples](~/snippets/Snippets.NUnit/Constraints/PathConstraintSnippets.cs#SamePathOrUnderConstraintExamples)] ## Notes diff --git a/docs/articles/nunit/writing-tests/constraints/SomeItemsConstraint.md b/docs/articles/nunit/writing-tests/constraints/SomeItemsConstraint.md index ca6807c09..5cd928480 100644 --- a/docs/articles/nunit/writing-tests/constraints/SomeItemsConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/SomeItemsConstraint.md @@ -1,58 +1,52 @@ --- uid: constraint-someitems --- -# SomeItems Constraint - -`SomeItemsConstraint` applies a constraint to each item in an `IEnumerable`, succeeding if at least one of them -succeeds. An exception is thrown if the actual value passed does not implement `IEnumerable`. - -This constraint will also cover `Contains` functionality. See examples below. -## Constructor +# SomeItems Constraint -```csharp -SomeItemsConstraint(Constraint itemConstraint) -``` +`SomeItemsConstraint` applies a constraint to each item in an `IEnumerable`, succeeding if at least one item satisfies +the constraint. An exception is thrown if the actual value does not implement `IEnumerable`. -## Syntax +## Usage ```csharp -Has.Some... -Has.Member(object) -Contains.Item(object) -Does.Contain(object) +Has.Some. +Has.Member(object expected) +Contains.Item(object expected) +Does.Contain(object expected) ``` ## Modifiers ```csharp -...IgnoreCase -...IgnoreWhiteSpace // From version 4.2 -...Using(IEqualityComparer comparer) -...Using(IComparer comparer) -...Using(IEqualityComparer comparer) -...Using(IComparer comparer) -...Using(Comparison comparer) -...Using(Func comparer) -...UsingPropertiesComparer() // From version 4.1 -...UsingPropertiesComparer( - Func configure) // From version 4.4 +.IgnoreCase +.IgnoreWhiteSpace // NUnit 4.2+ +.Using(IComparer comparer) +.Using(IEqualityComparer comparer) +.Using(IComparer comparer) +.Using(IEqualityComparer comparer) +.Using(Comparison comparer) +.Using(Func comparer) +.UsingPropertiesComparer() // NUnit 4.1+ ``` -## Examples of Use +## Examples -```csharp -int[] iarray = new int[] { 1, 2, 3 }; -string[] sarray = new string[] { "a", "b", "c" }; -Assert.That(iarray, Has.Some.GreaterThan(2)); -Assert.That(sarray, Has.Some.Length.EqualTo(1)); -``` +[!code-csharp[SomeItemsConstraintExamples](~/snippets/Snippets.NUnit/Constraints/CollectionConstraintSnippets.cs#SomeItemsConstraintExamples)] ### Contains examples [!code-csharp[Collection Contains Examples](~/snippets/Snippets.NUnit/ConstraintExamples.cs#CollectionContainsExamples)] -## Note +## Notes + +1. `Has.Member()`, `Contains.Item()`, and `Does.Contain()` are all equivalent to `Has.Some.EqualTo()`. +2. The constraint succeeds as soon as the first matching item is found. +3. An empty collection always fails this constraint. +4. For testing substring containment in strings, see [SubstringConstraint](SubstringConstraint.md). + +## See Also -`Has.Member()`, `Contains.Item()` and `Does.Contain()` work the same as `Has.Some.EqualTo()`. +* [AllItems Constraint](AllItemsConstraint.md) - All items must match +* [NoItem Constraint](NoItemConstraint.md) - No items match +* [Contains Constraint](ContainsConstraint.md) - Polymorphic containment testing diff --git a/docs/articles/nunit/writing-tests/constraints/StartsWithConstraint.md b/docs/articles/nunit/writing-tests/constraints/StartsWithConstraint.md index dd2e6fd7e..c86852028 100644 --- a/docs/articles/nunit/writing-tests/constraints/StartsWithConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/StartsWithConstraint.md @@ -4,44 +4,30 @@ uid: constraint-startswith # StartsWith Constraint -`StartsWithConstraint` tests for an initial string. +`StartsWithConstraint` tests that a string begins with the expected substring. -## Constructor - -```csharp -StartsWithConstraint(string expected) -``` - -## Syntax +## Usage ```csharp Does.StartWith(string expected) -StartsWith(string expected) +Does.Not.StartWith(string expected) ``` ## Modifiers ```csharp -...IgnoreCase -...Using(StringComparison comparisonType) -...Using(CultureInfo culture) +.IgnoreCase +.Using(StringComparison comparisonType) +.Using(CultureInfo culture) ``` -## Examples of Use +## Examples -```csharp -string phrase = "Make your tests fail before passing!"; - -Assert.That(phrase, Does.StartWith("Make")); -Assert.That(phrase, Does.Not.StartWith("Break")); -``` +[!code-csharp[StartsWithConstraintExamples](~/snippets/Snippets.NUnit/Constraints/StringConstraintSnippets.cs#StartsWithConstraintExamples)] ### Specifying a StringComparison -```csharp -Assert.That("Hello World!", Does.StartWith("HELLO").Using(StringComparison.OrdinalIgnoreCase)); -Assert.That("Hello World!", Does.StartWith("Hello").Using(StringComparison.Ordinal)); -``` +[!code-csharp[StartsWithConstraintStringComparisonExamples](~/snippets/Snippets.NUnit/Constraints/StringConstraintSnippets.cs#StartsWithConstraintStringComparisonExamples)] ### Specifying a CultureInfo @@ -58,7 +44,11 @@ Assert.That("Straße Street", Does.StartWith("Straße").Using(new CultureInfo("d ## Notes -1. **StartsWith** may appear only in the body of a constraint - expression or when the inherited syntax is used. -2. Only one `Using` modifier may be specified. Attempting to use multiple `Using` modifiers - will throw an `InvalidOperationException`. +1. Only one `Using` modifier may be specified. Attempting to use multiple `Using` modifiers will throw an + `InvalidOperationException`. + +## See Also + +* [EndsWith Constraint](EndsWithConstraint.md) +* [Substring Constraint](SubstringConstraint.md) +* [Regex Constraint](RegexConstraint.md) diff --git a/docs/articles/nunit/writing-tests/constraints/SubPathConstraint.md b/docs/articles/nunit/writing-tests/constraints/SubPathConstraint.md index 9c9fdceba..e1514606d 100644 --- a/docs/articles/nunit/writing-tests/constraints/SubPathConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/SubPathConstraint.md @@ -27,13 +27,7 @@ Is.SubPathOf(string expectedPath) ## Examples of Use -```csharp -Assert.That("/folder1/./junk/../folder2", Is.SubPathOf("/folder1/")); -Assert.That("/folder1/junk/folder2", Is.Not.SubPathOf("/folder1/folder2")); - -Assert.That(@"C:\folder1\folder2\Folder3", Is.SubPathOf(@"C:\Folder1\Folder2").IgnoreCase); -Assert.That("/folder1/folder2/folder3", Is.Not.SubPathOf("/Folder1/Folder2/Folder3").RespectCase); -``` +[!code-csharp[SubPathConstraintExamples](~/snippets/Snippets.NUnit/Constraints/PathConstraintSnippets.cs#SubPathConstraintExamples)] ## Notes diff --git a/docs/articles/nunit/writing-tests/constraints/SubstringConstraint.md b/docs/articles/nunit/writing-tests/constraints/SubstringConstraint.md index b65cdd82a..2d6b18f32 100644 --- a/docs/articles/nunit/writing-tests/constraints/SubstringConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/SubstringConstraint.md @@ -4,38 +4,30 @@ uid: constraint-substring # Substring Constraint -`SubstringConstraint` tests for a substring. +`SubstringConstraint` tests that a string contains the expected substring. -## Constructor - -```csharp -SubstringConstraint(string expected) -``` - -## Syntax +## Usage ```csharp Does.Contain(string expected) +Does.Not.Contain(string expected) ``` ## Modifiers ```csharp -...IgnoreCase -...Using(StringComparison comparisonType) -...Using(CultureInfo culture) +.IgnoreCase +.Using(StringComparison comparisonType) +.Using(CultureInfo culture) ``` -## Examples of Use +## Examples -[!code-csharp[StringConstraintExamples](~/snippets/Snippets.NUnit/ConstraintExamples.cs#StringConstraintExamples)] +[!code-csharp[SubstringConstraintExamples](~/snippets/Snippets.NUnit/Constraints/StringConstraintSnippets.cs#SubstringConstraintExamples)] ### Specifying a StringComparison -```csharp -Assert.That("Hello World!", Does.Contain("WORLD").Using(StringComparison.OrdinalIgnoreCase)); -Assert.That("Hello World!", Does.Contain("World").Using(StringComparison.Ordinal)); -``` +[!code-csharp[SubstringConstraintStringComparisonExamples](~/snippets/Snippets.NUnit/Constraints/StringConstraintSnippets.cs#SubstringConstraintStringComparisonExamples)] ### Specifying a CultureInfo @@ -52,5 +44,14 @@ Assert.That("Straße Street", Does.Contain("Straße").Using(new CultureInfo("de- ## Notes -1. Only one `Using` modifier may be specified. Attempting to use multiple `Using` modifiers - will throw an `InvalidOperationException`. +1. Only one `Using` modifier may be specified. Attempting to use multiple `Using` modifiers will throw an + `InvalidOperationException`. +2. When using `Does.Contain()` with a non-string actual value, it tests for collection membership instead. See + [ContainsConstraint](ContainsConstraint.md) for details. + +## See Also + +* [StartsWith Constraint](StartsWithConstraint.md) +* [EndsWith Constraint](EndsWithConstraint.md) +* [Regex Constraint](RegexConstraint.md) +* [Contains Constraint](ContainsConstraint.md) diff --git a/docs/articles/nunit/writing-tests/constraints/ThrowsConstraint.md b/docs/articles/nunit/writing-tests/constraints/ThrowsConstraint.md index 184b448de..d15115236 100644 --- a/docs/articles/nunit/writing-tests/constraints/ThrowsConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/ThrowsConstraint.md @@ -38,21 +38,7 @@ Throws.Nothing ## Examples -```csharp -// Test for specific exception type -Assert.That(() => MethodThatThrows(), Throws.TypeOf()); -Assert.That(() => MethodThatThrows(), Throws.InstanceOf()); - -// Test exception message -Assert.That(() => throw new ArgumentException("bad value"), - Throws.ArgumentException.With.Message.EqualTo("bad value")); - -// Test with lambda expression -Assert.That(() => int.Parse("abc"), Throws.TypeOf()); - -// Assert no exception is thrown -Assert.That(() => SafeMethod(), Throws.Nothing); -``` +[!code-csharp[ThrowsConstraintBasicExamples](~/snippets/Snippets.NUnit/Constraints/ComparisonConstraintSnippets.cs#ThrowsConstraintBasicExamples)] ### Additional Examples diff --git a/docs/articles/nunit/writing-tests/constraints/ThrowsNothingConstraint.md b/docs/articles/nunit/writing-tests/constraints/ThrowsNothingConstraint.md index b63b2af14..f49032720 100644 --- a/docs/articles/nunit/writing-tests/constraints/ThrowsNothingConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/ThrowsNothingConstraint.md @@ -4,22 +4,24 @@ uid: constraint-throwsnothing # ThrowsNothing Constraint -`ThrowsNothingConstraint` asserts that the delegate passed as its argument does not throw an exception. +`ThrowsNothingConstraint` tests that the code under test does not throw any exception. -## Constructor +## Usage ```csharp -ThrowsNothingConstraint() +Throws.Nothing ``` -## Syntax +## Examples -```csharp -Throws.Nothing -``` +[!code-csharp[ThrowsNothingConstraintExamples](~/snippets/Snippets.NUnit/Constraints/SpecialConstraintSnippets.cs#ThrowsNothingConstraintExamples)] -## Example of Use +## Notes -```csharp -Assert.That(() => SomeMethod(actual), Throws.Nothing); -``` +1. Use `Throws.Nothing` to explicitly verify that code doesn't throw. +2. This is different from not testing at all - it documents the expectation. +3. If the delegate throws any exception, the constraint fails with the exception details. + +## See Also + +* [Throws Constraint](ThrowsConstraint.md) - Test that code throws specific exceptions diff --git a/docs/articles/nunit/writing-tests/constraints/TrueConstraint.md b/docs/articles/nunit/writing-tests/constraints/TrueConstraint.md index 0b97bec7f..76eadfa60 100644 --- a/docs/articles/nunit/writing-tests/constraints/TrueConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/TrueConstraint.md @@ -16,15 +16,7 @@ Is.Not.True // equivalent to Is.False ## Examples -```csharp -Assert.That(2 + 2 == 4, Is.True); -Assert.That(isValid, Is.True); -Assert.That(list.Contains(item), Is.True); - -// With nullable booleans -bool? hasValue = true; -Assert.That(hasValue, Is.True); -``` +[!code-csharp[TrueConstraintExamples](~/snippets/Snippets.NUnit/Constraints/ComparisonConstraintSnippets.cs#TrueConstraintExamples)] ## Notes diff --git a/docs/articles/nunit/writing-tests/constraints/UniqueItemsConstraint.md b/docs/articles/nunit/writing-tests/constraints/UniqueItemsConstraint.md index 55f0e2e01..a78e00c51 100644 --- a/docs/articles/nunit/writing-tests/constraints/UniqueItemsConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/UniqueItemsConstraint.md @@ -4,16 +4,9 @@ uid: constraint-uniqueitems # UniqueItems Constraint -**UniqueItemsConstraint** tests that an array, collection or other IEnumerable is composed -of unique items with no duplicates. +`UniqueItemsConstraint` tests that an `IEnumerable` contains no duplicate items. -## Constructor - -```csharp -UniqueItemsConstraint() -``` - -## Syntax +## Usage ```csharp Is.Unique @@ -22,23 +15,27 @@ Is.Unique ## Modifiers ```csharp -...IgnoreCase -...IgnoreWhiteSpace // From version 4.2 -...Using(IEqualityComparer comparer) -...Using(IComparer comparer) -...Using(IEqualityComparer comparer) -...Using(IComparer comparer) -...Using(Comparison comparer) -...Using(Func comparer) -...UsingPropertiesComparer() // From version 4.1 -...UsingPropertiesComparer( - Func configure) // From version 4.4 +.IgnoreCase +.IgnoreWhiteSpace // NUnit 4.2+ +.Using(IComparer comparer) +.Using(IEqualityComparer comparer) +.Using(IComparer comparer) +.Using(IEqualityComparer comparer) +.Using(Comparison comparer) +.Using(Func comparer) +.UsingPropertiesComparer() // NUnit 4.1+ ``` -## Example of Use +## Examples -```csharp -int[] iarray = new int[] { 1, 2, 3 }; -Assert.That(iarray, Is.Unique); -``` +[!code-csharp[UniqueItemsConstraintExamples](~/snippets/Snippets.NUnit/Constraints/CollectionConstraintSnippets.cs#UniqueItemsConstraintExamples)] + +## Notes + +1. An empty collection is considered unique (no duplicates possible). +2. Duplicates are determined using the default equality comparer unless a custom comparer is specified. + +## See Also + +* [CollectionEquivalent Constraint](CollectionEquivalentConstraint.md) - Test collection equivalence +* [AllItems Constraint](AllItemsConstraint.md) - Test all items against a constraint diff --git a/docs/articles/nunit/writing-tests/constraints/WhiteSpaceConstraint.md b/docs/articles/nunit/writing-tests/constraints/WhiteSpaceConstraint.md index 173e3615a..ce08cdec5 100644 --- a/docs/articles/nunit/writing-tests/constraints/WhiteSpaceConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/WhiteSpaceConstraint.md @@ -4,29 +4,31 @@ uid: constraint-whitespace # WhiteSpace Constraint -The `WhiteSpaceConstraint` tests if a string contains only white-space. +`WhiteSpaceConstraint` tests that a string is null, empty, or contains only whitespace characters. It is equivalent to +`string.IsNullOrWhiteSpace()`. -The constraint is the equivalent of -[String.IsNullOrWhiteSpace](https://learn.microsoft.com/en-us/dotnet/api/system.string.isnullorwhitespace?view=net-8.0) +> [!NOTE] +> This constraint was added in NUnit 4.2. -White-space characters are defined by the Unicode standard as interpreted by -[Char.IsWhiteSpace](https://learn.microsoft.com/en-us/dotnet/api/system.char.iswhitespace?view=net-8.0) method. - -## Constructor +## Usage ```csharp -WhiteSpaceConstraint() +Is.WhiteSpace +Is.Not.WhiteSpace ``` -## Syntax +## Examples -```csharp -Is.WhiteSpace // From version 4.2 -``` +[!code-csharp[WhiteSpaceConstraintExamples](~/snippets/Snippets.NUnit/Constraints/StringConstraintSnippets.cs#WhiteSpaceConstraintExamples)] -## Examples of Use +## Notes -```csharp -Assert.That(" ", Is.WhiteSpace); -Assert.That("A String", Is.Not.WhiteSpace); -``` +1. Whitespace characters are defined by the Unicode standard as interpreted by `Char.IsWhiteSpace()`. +2. Unlike `Is.Empty`, `Is.WhiteSpace` also returns true for `null` values. +3. Common whitespace characters include: space (` `), tab (`\t`), newline (`\n`), carriage return (`\r`). + +## See Also + +* [EmptyString Constraint](EmptyStringConstraint.md) +* [Empty Constraint](EmptyConstraint.md) +* [Null Constraint](NullConstraint.md) diff --git a/docs/articles/nunit/writing-tests/constraints/toc.yml b/docs/articles/nunit/writing-tests/constraints/toc.yml index 4e106fa2a..adc96266b 100644 --- a/docs/articles/nunit/writing-tests/constraints/toc.yml +++ b/docs/articles/nunit/writing-tests/constraints/toc.yml @@ -1,5 +1,9 @@ - name: Constraints href: Constraints.md +- name: Async Constraint Support + href: AsyncConstraints.md +- name: Contains Helper + href: ContainsHelper.md - name: AllItemsConstraint href: AllItemsConstraint.md - name: AndConstraint @@ -66,6 +70,8 @@ href: LessThanConstraint.md - name: LessThanOrEqualConstraint href: LessThanOrEqualConstraint.md +- name: MultipleOfConstraint + href: MultipleOfConstraint.md - name: NaNConstraint href: NaNConstraint.md - name: NoItemConstraint diff --git a/docs/snippets/Snippets.NUnit/Constraints/CollectionConstraintSnippets.cs b/docs/snippets/Snippets.NUnit/Constraints/CollectionConstraintSnippets.cs new file mode 100644 index 000000000..fcad8c9c8 --- /dev/null +++ b/docs/snippets/Snippets.NUnit/Constraints/CollectionConstraintSnippets.cs @@ -0,0 +1,237 @@ +using NUnit.Framework; + +#pragma warning disable NUnit2045 + +namespace Snippets.NUnit.Constraints; + +public class CollectionConstraintSnippets +{ + #region AllItemsConstraintExamples + [Test] + public void AllItemsConstraint_Examples() + { + int[] numbers = { 1, 2, 3, 4, 5 }; + string[] names = { "Alice", "Bob", "Carol" }; + + // All items must satisfy the constraint + Assert.That(numbers, Is.All.GreaterThan(0)); // All positive + Assert.That(numbers, Is.All.LessThan(10)); // All less than 10 + Assert.That(names, Is.All.Not.Null); // No nulls + Assert.That(names, Is.All.Not.Empty); // No empty strings + Assert.That(names, Is.All.InstanceOf()); // All are strings + + // Has.All is equivalent to Is.All + Assert.That(numbers, Has.All.GreaterThan(0)); + + // Combining with property constraints + Assert.That(names, Is.All.Length.GreaterThan(2)); // All names > 2 chars + + // Complex constraints + Assert.That(numbers, Is.All.InRange(1, 10)); + Assert.That(names, Is.All.Matches(n => n.Length <= 5)); + } + #endregion + + #region SomeItemsConstraintExamples + [Test] + public void SomeItemsConstraint_Examples() + { + int[] numbers = { 1, 2, 3, 4, 5 }; + string[] names = { "Alice", "Bob", "Carol" }; + + // At least one item must satisfy the constraint + Assert.That(numbers, Has.Some.GreaterThan(3)); // At least one > 3 + Assert.That(numbers, Has.Some.EqualTo(3)); // Contains 3 + Assert.That(names, Has.Some.Length.EqualTo(3)); // At least one 3-char name + + // Collection membership (all equivalent) + Assert.That(numbers, Has.Member(3)); + Assert.That(numbers, Contains.Item(3)); + Assert.That(numbers, Does.Contain(3)); + Assert.That(numbers, Has.Some.EqualTo(3)); + + // Custom comparison for membership + Assert.That(names, Has.Some.EqualTo("alice").IgnoreCase); + Assert.That(names, Has.Some.EqualTo("bob").Using(StringComparer.OrdinalIgnoreCase)); + } + #endregion + + #region NoItemConstraintExamples + [Test] + public void NoItemConstraint_Examples() + { + int[] numbers = { 1, 2, 3, 4, 5 }; + string[] names = { "Alice", "Bob", "Carol" }; + + // No items should satisfy the constraint + Assert.That(numbers, Has.None.LessThan(0)); // No negatives + Assert.That(numbers, Has.None.GreaterThan(100)); // None > 100 + Assert.That(names, Has.None.Null); // No nulls + Assert.That(names, Has.None.Empty); // No empty strings + Assert.That(names, Has.None.EqualTo("Dave")); // "Dave" not in list + + // Property-based constraints + Assert.That(names, Has.None.Length.GreaterThan(10)); // No name > 10 chars + + // Multiple conditions + Assert.That(numbers, Has.None.LessThanOrEqualTo(0)); + } + #endregion + + #region UniqueItemsConstraintExamples + [Test] + public void UniqueItemsConstraint_Examples() + { + int[] numbers = { 1, 2, 3, 4, 5 }; + string[] names = { "Alice", "Bob", "Carol" }; + + // Basic uniqueness check + Assert.That(numbers, Is.Unique); + Assert.That(names, Is.Unique); + + // Fails: contains duplicates + Assert.That(new[] { 1, 2, 2, 3 }, Is.Not.Unique); + + // Case-insensitive uniqueness + Assert.That(new[] { "Alice", "ALICE" }, Is.Unique); // Passes: different case + Assert.That(new[] { "Alice", "ALICE" }, Is.Not.Unique.IgnoreCase); // Passes: same when ignoring case + } + #endregion + + #region CollectionOrderedConstraintExamples + [Test] + public void CollectionOrderedConstraint_Examples() + { + int[] ascending = { 1, 2, 3, 4, 5 }; + int[] descending = { 5, 4, 3, 2, 1 }; + string[] alphabetical = { "Alice", "Bob", "Carol" }; + + // Simple ordering + Assert.That(ascending, Is.Ordered); // Default is ascending + Assert.That(ascending, Is.Ordered.Ascending); // Explicit ascending + Assert.That(descending, Is.Ordered.Descending); // Descending order + Assert.That(alphabetical, Is.Ordered); // Alphabetical order + + // Property-based ordering + string[] byLength = { "a", "bb", "ccc" }; + Assert.That(byLength, Is.Ordered.By("Length")); + Assert.That(byLength.Reverse(), Is.Ordered.Descending.By("Length")); + + // Custom comparison + var words = new[] { "apple", "Banana", "cherry" }; + Assert.That(words, Is.Ordered.Using((IComparer)StringComparer.OrdinalIgnoreCase)); + } + #endregion + + #region CollectionOrderedMultiplePropertiesExamples + [Test] + public void CollectionOrdered_MultipleProperties_Examples() + { + var people = new[] + { + new { Name = "Alice", Age = 25 }, + new { Name = "Bob", Age = 25 }, + new { Name = "Carol", Age = 30 } + }; + + // Order by Age ascending, then by Name ascending + Assert.That(people, Is.Ordered.By("Age").Then.By("Name")); + } + #endregion + + #region CollectionSubsetConstraintExamples + [Test] + public void CollectionSubsetConstraint_Examples() + { + int[] superset = { 1, 2, 3, 4, 5 }; + + Assert.That(new[] { 1, 3 }, Is.SubsetOf(superset)); // Passes + Assert.That(new[] { 1, 2, 3, 4, 5 }, Is.SubsetOf(superset)); // Passes (equal sets are subsets) + Assert.That(new int[] { }, Is.SubsetOf(superset)); // Passes (empty set is subset of any set) + Assert.That(new[] { 1, 6 }, Is.Not.SubsetOf(superset)); // Passes (6 not in superset) + + // Case-insensitive string comparison + string[] colors = { "Red", "Green", "Blue" }; + Assert.That(new[] { "red", "blue" }, Is.SubsetOf(colors).Using((IEqualityComparer)StringComparer.OrdinalIgnoreCase)); + } + #endregion + + #region CollectionSupersetConstraintExamples + [Test] + public void CollectionSupersetConstraint_Examples() + { + int[] actual = { 1, 2, 3, 4, 5 }; + + Assert.That(actual, Is.SupersetOf(new[] { 1, 3 })); // Passes + Assert.That(actual, Is.SupersetOf(new[] { 1, 2, 3, 4, 5 })); // Passes (equal sets) + Assert.That(actual, Is.SupersetOf(new int[] { })); // Passes (superset of empty) + Assert.That(actual, Is.Not.SupersetOf(new[] { 1, 6 })); // Passes (missing 6) + + // Case-insensitive string comparison + string[] colors = { "Red", "Green", "Blue", "Yellow" }; + Assert.That(colors, Is.SupersetOf(new[] { "red", "blue" }).Using((IEqualityComparer)StringComparer.OrdinalIgnoreCase)); + } + #endregion + + #region ExactCountConstraintExamples + [Test] + public void ExactCountConstraint_Examples() + { + int[] numbers = { 1, 2, 3, 4, 5 }; + string[] names = { "Alice", "Bob", "Carol" }; + + // Count total items + Assert.That(numbers, Has.Exactly(5).Items); + Assert.That(names, Has.Exactly(3).Items); + + // Count items matching a constraint + Assert.That(numbers, Has.Exactly(2).GreaterThan(3)); // 4 and 5 + Assert.That(numbers, Has.Exactly(3).LessThanOrEqualTo(3)); // 1, 2, and 3 + Assert.That(names, Has.Exactly(1).Length.EqualTo(3)); // "Bob" + + // Combining multiple counts + Assert.That(numbers, Has.Exactly(2).LessThan(3).And.Exactly(2).GreaterThan(3)); + + // Zero items matching + Assert.That(numbers, Has.Exactly(0).LessThan(0)); // No negatives + } + #endregion + + #region EmptyCollectionConstraintExamples + [Test] + public void EmptyCollectionConstraint_Examples() + { + // Empty collections + Assert.That(new int[] { }, Is.Empty); + Assert.That(new List(), Is.Empty); + Assert.That(Array.Empty(), Is.Empty); + Assert.That(Enumerable.Empty(), Is.Empty); + + // Non-empty collections + Assert.That(new[] { 1, 2, 3 }, Is.Not.Empty); + Assert.That(new List { "item" }, Is.Not.Empty); + } + #endregion + + #region CollectionEquivalentConstraintExamples + [Test] + public void CollectionEquivalentConstraint_Examples() + { + int[] expected = { 1, 2, 3 }; + int[] actual = { 3, 2, 1 }; + + // Order doesn't matter + Assert.That(actual, Is.EquivalentTo(expected)); + + // Different collections with same elements + Assert.That(new List { 1, 2, 3 }, Is.EquivalentTo(new[] { 3, 1, 2 })); + + // Duplicates matter + Assert.That(new[] { 1, 1, 2 }, Is.Not.EquivalentTo(new[] { 1, 2, 2 })); + Assert.That(new[] { 1, 1, 2 }, Is.EquivalentTo(new[] { 2, 1, 1 })); + + // Case-insensitive for strings + Assert.That(new[] { "A", "B" }, Is.EquivalentTo(new[] { "b", "a" }).IgnoreCase); + } + #endregion +} diff --git a/docs/snippets/Snippets.NUnit/Constraints/ComparisonConstraintSnippets.cs b/docs/snippets/Snippets.NUnit/Constraints/ComparisonConstraintSnippets.cs new file mode 100644 index 000000000..0bb1cb595 --- /dev/null +++ b/docs/snippets/Snippets.NUnit/Constraints/ComparisonConstraintSnippets.cs @@ -0,0 +1,188 @@ +using System.Collections.Generic; +using NUnit.Framework; + +#pragma warning disable NUnit2045 + +namespace Snippets.NUnit.Constraints; + +public class ComparisonConstraintSnippets +{ + #region GreaterThanConstraintExamples + [Test] + public void GreaterThanConstraint_Examples() + { + Assert.That(7, Is.GreaterThan(3)); + Assert.That(5, Is.Positive); + Assert.That(-3, Is.Not.Positive); + + // With DateTime + Assert.That(DateTime.Now, Is.GreaterThan(DateTime.Today)); + + // With tolerance + Assert.That(10.5, Is.GreaterThan(10.0).Within(0.1)); + } + #endregion + + #region LessThanConstraintExamples + [Test] + public void LessThanConstraint_Examples() + { + Assert.That(3, Is.LessThan(7)); + Assert.That(-5, Is.Negative); + Assert.That(5, Is.Not.Negative); + + // With DateTime + Assert.That(DateTime.Today, Is.LessThan(DateTime.Now)); + + // With tolerance + Assert.That(9.5, Is.LessThan(10.0).Within(0.1)); + } + #endregion + + #region GreaterThanOrEqualConstraintExamples + [Test] + public void GreaterThanOrEqualConstraint_Examples() + { + Assert.That(7, Is.GreaterThanOrEqualTo(7)); + Assert.That(7, Is.GreaterThanOrEqualTo(3)); + Assert.That(7, Is.AtLeast(7)); + + // With DateTime + Assert.That(DateTime.Now, Is.GreaterThanOrEqualTo(DateTime.Today)); + + // With tolerance + Assert.That(10.1, Is.GreaterThanOrEqualTo(10.0).Within(0.5)); + } + #endregion + + #region LessThanOrEqualConstraintExamples + [Test] + public void LessThanOrEqualConstraint_Examples() + { + Assert.That(7, Is.LessThanOrEqualTo(7)); + Assert.That(3, Is.LessThanOrEqualTo(7)); + Assert.That(3, Is.AtMost(7)); + + // With DateTime + Assert.That(DateTime.Today, Is.LessThanOrEqualTo(DateTime.Now)); + + // With tolerance + Assert.That(9.9, Is.LessThanOrEqualTo(10.0).Within(0.5)); + } + #endregion + + #region RangeConstraintExamples + [Test] + public void RangeConstraint_Examples() + { + // Numeric ranges (inclusive) + Assert.That(5, Is.InRange(1, 10)); + Assert.That(1, Is.InRange(1, 10)); // Lower bound is included + Assert.That(10, Is.InRange(1, 10)); // Upper bound is included + Assert.That(0, Is.Not.InRange(1, 10)); + + // DateTime ranges + var start = new DateTime(2024, 1, 1); + var end = new DateTime(2024, 12, 31); + Assert.That(new DateTime(2024, 6, 15), Is.InRange(start, end)); + + // String ranges (alphabetical comparison) + Assert.That("banana", Is.InRange("apple", "cherry")); + } + #endregion + + #region NullConstraintExamples + [Test] + public void NullConstraint_Examples() + { + object? obj = null; + Assert.That(obj, Is.Null); + + string name = "Alice"; + Assert.That(name, Is.Not.Null); + + // Combining with other constraints + object? result = "value"; + Assert.That(result, Is.Not.Null.And.Not.EqualTo("")); + } + #endregion + + #region TrueConstraintExamples + [Test] + public void TrueConstraint_Examples() + { + Assert.That(2 + 2 == 4, Is.True); + var isValid = true; + Assert.That(isValid, Is.True); + var list = new List { 1, 2, 3 }; + Assert.That(list.Contains(2), Is.True); + + // With nullable booleans + bool? hasValue = true; + Assert.That(hasValue, Is.True); + } + #endregion + + #region FalseConstraintExamples + [Test] + public void FalseConstraint_Examples() + { + Assert.That(2 + 2 == 5, Is.False); + var isDisabled = false; + Assert.That(isDisabled, Is.False); + ICollection list = new List(); + Assert.That(list.IsReadOnly, Is.False); + + // With nullable booleans + bool? isDeleted = false; + Assert.That(isDeleted, Is.False); + } + #endregion + + #region ContainsConstraintStringExamples + [Test] + public void ContainsConstraint_String_Examples() + { + Assert.That("Hello World", Does.Contain("World")); + Assert.That("Hello World", Does.Contain("world").IgnoreCase); + Assert.That("Hello World", Does.Not.Contain("Goodbye")); + } + #endregion + + #region ContainsConstraintCollectionExamples + [Test] + public void ContainsConstraint_Collection_Examples() + { + int[] numbers = { 1, 2, 3, 4, 5 }; + Assert.That(numbers, Does.Contain(3)); + Assert.That(numbers, Does.Not.Contain(99)); + + string[] names = { "Alice", "Bob", "Charlie" }; + Assert.That(names, Does.Contain("Bob")); + Assert.That(names, Does.Contain("bob").IgnoreCase); + } + #endregion + + #region ThrowsConstraintBasicExamples + [Test] + public void ThrowsConstraint_Basic_Examples() + { + // Test for specific exception type + Assert.That(() => ThrowArgumentException(), Throws.TypeOf()); + Assert.That(() => ThrowArgumentException(), Throws.InstanceOf()); + + // Test exception message + Assert.That(() => throw new ArgumentException("bad value"), + Throws.ArgumentException.With.Message.EqualTo("bad value")); + + // Test with lambda expression + Assert.That(() => int.Parse("abc"), Throws.TypeOf()); + + // Assert no exception is thrown + Assert.That(() => SafeMethod(), Throws.Nothing); + } + + private static void ThrowArgumentException() => throw new ArgumentException("test"); + private static void SafeMethod() { } + #endregion +} diff --git a/docs/snippets/Snippets.NUnit/Constraints/CompoundConstraintSnippets.cs b/docs/snippets/Snippets.NUnit/Constraints/CompoundConstraintSnippets.cs new file mode 100644 index 000000000..3e971cf66 --- /dev/null +++ b/docs/snippets/Snippets.NUnit/Constraints/CompoundConstraintSnippets.cs @@ -0,0 +1,103 @@ +using NUnit.Framework; + +#pragma warning disable NUnit2045 + +namespace Snippets.NUnit.Constraints; + +public class CompoundConstraintSnippets +{ + #region AndConstraintExamples + [Test] + public void AndConstraint_Examples() + { + int value = 42; + + // Both conditions must be true + Assert.That(value, Is.GreaterThan(0).And.LessThan(100)); + Assert.That(value, Is.Positive.And.LessThanOrEqualTo(50).Or.GreaterThanOrEqualTo(40)); + + // String constraints + Assert.That("Hello World", Does.StartWith("Hello").And.EndWith("World")); + Assert.That("test@example.com", Does.Contain("@").And.EndWith(".com")); + + // Null checking pattern (check null first!) + int? nullable = 42; + Assert.That(nullable, Is.Not.Null.And.GreaterThan(0)); + + // Collection constraints + Assert.That(new[] { 1, 2, 3 }, Is.Not.Empty.And.All.Positive); + } + #endregion + + #region AndConstraintNullCheckExamples + [Test] + public void AndConstraint_NullCheck_Examples() + { + int? value = 42; + + // CORRECT: Check null first - fails gracefully with message for null + Assert.That(value, Is.Not.Null.And.GreaterThan(9)); + } + #endregion + + #region OrConstraintExamples + [Test] + public void OrConstraint_Examples() + { + int value = 42; + + // Either condition can be true + Assert.That(value, Is.LessThan(10).Or.GreaterThan(40)); + Assert.That(value, Is.EqualTo(0).Or.Positive); + + // String constraints + Assert.That("test", Does.StartWith("te").Or.EndWith("ing")); + + // Multiple alternatives + Assert.That(value, Is.EqualTo(1).Or.EqualTo(42).Or.EqualTo(100)); + } + #endregion + + #region OrConstraintNullPatternExamples + [Test] + public void OrConstraint_NullPattern_Examples() + { + int? nullable = null; + + // Null-or-value pattern (check null first!) + Assert.That(nullable, Is.Null.Or.GreaterThan(0)); // Passes for null + + // Collection: empty or contains specific item + var items = new List(); + Assert.That(items, Is.Empty.Or.Contains(1)); + } + #endregion + + #region NotConstraintExamples + [Test] + public void NotConstraint_Examples() + { + // Basic negation + Assert.That(42, Is.Not.EqualTo(0)); + Assert.That("Hello", Is.Not.Null); + Assert.That("Hello", Is.Not.Empty); + + // String negation + Assert.That("Hello World", Does.Not.Contain("Goodbye")); + Assert.That("test.txt", Does.Not.EndWith(".pdf")); + + // Collection negation + Assert.That(new[] { 1, 2, 3 }, Has.No.Member(0)); + Assert.That(new[] { 1, 2, 3 }, Is.Not.Empty); + Assert.That(new[] { 1, 2, 3 }, Has.None.Negative); + + // Type negation + Assert.That("Hello", Is.Not.InstanceOf()); + + // Combined with And/Or + object obj = 42; + Assert.That(obj, Is.Not.Null.And.InstanceOf()); + Assert.That("test", Is.Not.Null.And.Not.Empty); + } + #endregion +} diff --git a/docs/snippets/Snippets.NUnit/Constraints/DictionaryConstraintSnippets.cs b/docs/snippets/Snippets.NUnit/Constraints/DictionaryConstraintSnippets.cs new file mode 100644 index 000000000..5f350ad55 --- /dev/null +++ b/docs/snippets/Snippets.NUnit/Constraints/DictionaryConstraintSnippets.cs @@ -0,0 +1,99 @@ +using NUnit.Framework; + +#pragma warning disable NUnit2045 + +namespace Snippets.NUnit.Constraints; + +public class DictionaryConstraintSnippets +{ + #region DictionaryContainsKeyConstraintExamples + [Test] + public void DictionaryContainsKeyConstraint_Examples() + { + var dictionary = new Dictionary + { + ["Alice"] = 30, + ["Bob"] = 25 + }; + + // Basic key checks + Assert.That(dictionary, Contains.Key("Alice")); + Assert.That(dictionary, Does.ContainKey("Bob")); + Assert.That(dictionary, Does.Not.ContainKey("Carol")); + + // Check key with corresponding value + Assert.That(dictionary, Does.ContainKey("Alice").WithValue(30)); + Assert.That(dictionary, Does.ContainKey("Bob").WithValue(25)); + } + #endregion + + #region DictionaryContainsKeyComparerExamples + [Test] + public void DictionaryContainsKey_Comparer_Examples() + { + // Case-sensitive dictionary (default) + var caseSensitive = new Dictionary { ["Hello"] = "World" }; + Assert.That(caseSensitive, Does.ContainKey("Hello")); + Assert.That(caseSensitive, Does.Not.ContainKey("hello")); // Different case + + // Case-insensitive dictionary + var caseInsensitive = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["Hello"] = "World" + }; + Assert.That(caseInsensitive, Does.ContainKey("Hello")); + Assert.That(caseInsensitive, Does.ContainKey("hello")); // Same due to comparer + + // Note: .IgnoreCase on WithValue applies to the VALUE, not the key + Assert.That(caseInsensitive, Does.ContainKey("hello").WithValue("world").IgnoreCase); + } + #endregion + + #region DictionaryContainsValueConstraintExamples + [Test] + public void DictionaryContainsValueConstraint_Examples() + { + var scores = new Dictionary + { + ["Alice"] = 100, + ["Bob"] = 85, + ["Carol"] = 100 + }; + + // Basic value checks + Assert.That(scores, Contains.Value(100)); + Assert.That(scores, Does.ContainValue(85)); + Assert.That(scores, Does.Not.ContainValue(50)); + + // String values with case-insensitive comparison + var names = new Dictionary + { + [1] = "Alice", + [2] = "Bob" + }; + Assert.That(names, Does.ContainValue("alice").IgnoreCase); + } + #endregion + + #region DictionaryContainsKeyValuePairConstraintExamples + [Test] + public void DictionaryContainsKeyValuePairConstraint_Examples() + { + var translations = new Dictionary + { + ["Hello"] = "World", + ["Hola"] = "Mundo" + }; + + // Check for specific key-value pair + Assert.That(translations, Does.ContainKey("Hello").WithValue("World")); + Assert.That(translations, Does.ContainKey("Hola").WithValue("Mundo")); + + // Negative: key exists but value doesn't match + Assert.That(translations, Does.Not.ContainKey("Hello").WithValue("Universe")); + + // Case-insensitive value comparison + Assert.That(translations, Does.ContainKey("Hello").WithValue("WORLD").IgnoreCase); + } + #endregion +} diff --git a/docs/snippets/Snippets.NUnit/Constraints/PathConstraintSnippets.cs b/docs/snippets/Snippets.NUnit/Constraints/PathConstraintSnippets.cs new file mode 100644 index 000000000..24b0fc015 --- /dev/null +++ b/docs/snippets/Snippets.NUnit/Constraints/PathConstraintSnippets.cs @@ -0,0 +1,43 @@ +using NUnit.Framework; + +namespace Snippets.NUnit.Constraints; + +public class PathConstraintSnippets +{ + #region SamePathConstraintExamples + [Test] + public void SamePathConstraint_Examples() + { + Assert.That("/folder1/./junk/../folder2", Is.SamePath("/folder1/folder2")); + Assert.That("/folder1/./junk/../folder2/x", Is.Not.SamePath("/folder1/folder2")); + + Assert.That(@"C:\folder1\folder2", Is.SamePath(@"C:\Folder1\Folder2").IgnoreCase); + Assert.That("/folder1/folder2", Is.Not.SamePath("/Folder1/Folder2").RespectCase); + } + #endregion + + #region SamePathOrUnderConstraintExamples + [Test] + public void SamePathOrUnderConstraint_Examples() + { + Assert.That("/folder1/./junk/../folder2", Is.SamePathOrUnder("/folder1/folder2")); + Assert.That("/folder1/junk/../folder2/./folder3", Is.SamePathOrUnder("/folder1/folder2")); + Assert.That("/folder1/junk/folder2/folder3", Is.Not.SamePathOrUnder("/folder1/folder2")); + + Assert.That(@"C:\folder1\folder2\folder3", Is.SamePathOrUnder(@"C:\Folder1\Folder2").IgnoreCase); + Assert.That("/folder1/folder2/folder3", Is.Not.SamePathOrUnder("/Folder1/Folder2").RespectCase); + } + #endregion + + #region SubPathConstraintExamples + [Test] + public void SubPathConstraint_Examples() + { + Assert.That("/folder1/./junk/../folder2", Is.SubPathOf("/folder1/")); + Assert.That("/folder1/junk/folder2", Is.Not.SubPathOf("/folder1/folder2")); + + Assert.That(@"C:\folder1\folder2\Folder3", Is.SubPathOf(@"C:\Folder1\Folder2").IgnoreCase); + Assert.That("/folder1/folder2/folder3", Is.Not.SubPathOf("/Folder1/Folder2/Folder3").RespectCase); + } + #endregion +} diff --git a/docs/snippets/Snippets.NUnit/Constraints/SpecialConstraintSnippets.cs b/docs/snippets/Snippets.NUnit/Constraints/SpecialConstraintSnippets.cs new file mode 100644 index 000000000..18132cedb --- /dev/null +++ b/docs/snippets/Snippets.NUnit/Constraints/SpecialConstraintSnippets.cs @@ -0,0 +1,236 @@ +using NUnit.Framework; + +#pragma warning disable NUnit2045 + +namespace Snippets.NUnit.Constraints; + +public class SpecialConstraintSnippets +{ + #region MultipleOfConstraintExamples + [Test] + public void MultipleOfConstraint_Examples() + { + // Test for multiples + Assert.That(12, Is.MultipleOf(3)); // 12 is a multiple of 3 + Assert.That(12, Is.MultipleOf(4)); // 12 is a multiple of 4 + Assert.That(12, Is.Not.MultipleOf(5)); // 12 is not a multiple of 5 + + // Even numbers + Assert.That(0, Is.Even); + Assert.That(2, Is.Even); + Assert.That(100, Is.Even); + Assert.That(-4, Is.Even); + Assert.That(3, Is.Not.Even); + + // Odd numbers + Assert.That(1, Is.Odd); + Assert.That(3, Is.Odd); + Assert.That(99, Is.Odd); + Assert.That(-7, Is.Odd); + Assert.That(4, Is.Not.Odd); + } + #endregion + + #region NaNConstraintExamples + [Test] + public void NaNConstraint_Examples() + { + // NaN results from undefined operations + Assert.That(double.NaN, Is.NaN); + Assert.That(float.NaN, Is.NaN); + Assert.That(0.0 / 0.0, Is.NaN); + Assert.That(Math.Sqrt(-1), Is.NaN); + + // Regular numbers are not NaN + Assert.That(42.0, Is.Not.NaN); + Assert.That(double.PositiveInfinity, Is.Not.NaN); + Assert.That(double.NegativeInfinity, Is.Not.NaN); + } + #endregion + + #region AnyOfConstraintExamples + [Test] + public void AnyOfConstraint_Examples() + { + // Value must equal one of the options + Assert.That(42, Is.AnyOf(0, -1, 42, 100)); + Assert.That("red", Is.AnyOf("red", "green", "blue")); + + // With string comparison modifiers + Assert.That("RED", Is.AnyOf("red", "green", "blue").IgnoreCase); + + // Negative test + Assert.That("yellow", Is.Not.AnyOf("red", "green", "blue")); + } + #endregion + + #region ThrowsNothingConstraintExamples + [Test] + public void ThrowsNothingConstraint_Examples() + { + // Test that method completes without throwing + Assert.That(() => Add(1, 2), Throws.Nothing); + + // Verify cleanup doesn't throw + var resource = new DisposableResource(); + Assert.That(() => resource.Dispose(), Throws.Nothing); + } + + private static int Add(int a, int b) => a + b; + + private class DisposableResource : IDisposable + { + public void Dispose() { } + } + #endregion + + #region DelayedConstraintExamples + [Test] + public void DelayedConstraint_Examples() + { + var flag = false; + Task.Run(async () => + { + await Task.Delay(50); + flag = true; + }); + + // Poll until condition is true (or timeout) + Assert.That(() => flag, Is.True.After(500).MilliSeconds.PollEvery(50).MilliSeconds); + } + #endregion + + #region DelayedConstraintFluentExamples + [Test] + public void DelayedConstraint_Fluent_Examples() + { + var counter = 0; + Task.Run(async () => + { + await Task.Delay(50); + counter = 10; + }); + + // Fluent time syntax + Assert.That(() => counter, Is.GreaterThan(0).After(1).Seconds.PollEvery(100).MilliSeconds); + } + #endregion + + #region PropertyConstraintExamples + public class Person + { + public string Name { get; set; } = ""; + public int Age { get; set; } + } + + [Test] + public void PropertyConstraint_Examples() + { + // Test property values + Assert.That("Hello", Has.Property("Length").EqualTo(5)); + Assert.That(new int[] { 1, 2, 3 }, Has.Property("Length").EqualTo(3)); + + // Common properties have shortcuts + Assert.That("Hello", Has.Length.EqualTo(5)); + Assert.That(new List { 1, 2, 3 }, Has.Count.EqualTo(3)); + + // Exception properties + var ex = new InvalidOperationException("Test error", new ArgumentException()); + Assert.That(ex, Has.Message.EqualTo("Test error")); + Assert.That(ex, Has.InnerException.InstanceOf()); + + // Custom object properties + var person = new Person { Name = "Alice", Age = 30 }; + Assert.That(person, Has.Property("Name").EqualTo("Alice")); + Assert.That(person, Has.Property("Age").GreaterThan(18)); + } + #endregion + + #region PropertyExistsConstraintExamples + [Test] + public void PropertyExistsConstraint_Examples() + { + // Check that property exists + Assert.That("Hello", Has.Property("Length")); + Assert.That(new List(), Has.Property("Count")); + + // Negative test + Assert.That("Hello", Has.No.Property("NonExistent")); + + // Check that multiple properties exist + var person = new Person { Name = "Alice", Age = 30 }; + Assert.That(person, Has.Property("Name").And.Property("Age")); + } + #endregion + + #region SameAsConstraintExamples + [Test] + public void SameAsConstraint_Examples() + { + var obj1 = new object(); + var obj2 = obj1; + var obj3 = new object(); + + // Same reference + Assert.That(obj2, Is.SameAs(obj1)); + + // Different objects (even if equal) + Assert.That(obj3, Is.Not.SameAs(obj1)); + + // String interning example + var str1 = "Hello"; + var str2 = "Hello"; + Assert.That(str2, Is.SameAs(str1)); // Interned strings are same reference + } + #endregion + + #region FileOrDirectoryExistsConstraintExamples + [Test] + public void FileOrDirectoryExistsConstraint_Examples() + { + var tempFile = Path.GetTempFileName(); + var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + Directory.CreateDirectory(tempDir); + + try + { + // Test file or directory existence + Assert.That(tempFile, Does.Exist); + Assert.That(tempDir, Does.Exist); + Assert.That("nonexistent.txt", Does.Not.Exist); + + // Test with FileInfo/DirectoryInfo + Assert.That(new FileInfo(tempFile), Does.Exist); + Assert.That(new DirectoryInfo(tempDir), Does.Exist); + } + finally + { + File.Delete(tempFile); + Directory.Delete(tempDir); + } + } + #endregion + + #region EmptyDirectoryConstraintExamples + [Test] + public void EmptyDirectoryConstraint_Examples() + { + var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + Directory.CreateDirectory(tempDir); + + try + { + // Test directory is empty + Assert.That(new DirectoryInfo(tempDir), Is.Empty); + + // Add a file and verify not empty + File.WriteAllText(Path.Combine(tempDir, "test.txt"), "content"); + Assert.That(new DirectoryInfo(tempDir), Is.Not.Empty); + } + finally + { + Directory.Delete(tempDir, recursive: true); + } + } + #endregion +} diff --git a/docs/snippets/Snippets.NUnit/Constraints/StringConstraintSnippets.cs b/docs/snippets/Snippets.NUnit/Constraints/StringConstraintSnippets.cs new file mode 100644 index 000000000..bd55a15f5 --- /dev/null +++ b/docs/snippets/Snippets.NUnit/Constraints/StringConstraintSnippets.cs @@ -0,0 +1,129 @@ +using System.Globalization; +using NUnit.Framework; + +#pragma warning disable NUnit2045 + +namespace Snippets.NUnit.Constraints; + +public class StringConstraintSnippets +{ + #region StartsWithConstraintExamples + [Test] + public void StartsWithConstraint_Examples() + { + string phrase = "Make your tests fail before passing!"; + + Assert.That(phrase, Does.StartWith("Make")); + Assert.That(phrase, Does.StartWith("MAKE").IgnoreCase); + Assert.That(phrase, Does.Not.StartWith("Break")); + } + #endregion + + #region StartsWithConstraintStringComparisonExamples + [Test] + public void StartsWithConstraint_StringComparison_Examples() + { + Assert.That("Hello World!", Does.StartWith("HELLO").Using(StringComparison.OrdinalIgnoreCase)); + Assert.That("Hello World!", Does.StartWith("Hello").Using(StringComparison.Ordinal)); + } + #endregion + + #region EndsWithConstraintExamples + [Test] + public void EndsWithConstraint_Examples() + { + string phrase = "Make your tests fail before passing!"; + + Assert.That(phrase, Does.EndWith("!")); + Assert.That(phrase, Does.EndWith("passing!")); + Assert.That(phrase, Does.EndWith("PASSING!").IgnoreCase); + Assert.That(phrase, Does.Not.EndWith("failing")); + } + #endregion + + #region SubstringConstraintExamples + [Test] + public void SubstringConstraint_Examples() + { + string phrase = "Make your tests fail before passing!"; + + Assert.That(phrase, Does.Contain("tests")); + Assert.That(phrase, Does.Contain("TESTS").IgnoreCase); + Assert.That(phrase, Does.Not.Contain("missing")); + } + #endregion + + #region SubstringConstraintStringComparisonExamples + [Test] + public void SubstringConstraint_StringComparison_Examples() + { + // IgnoreCase modifier + Assert.That("Hello World!", Does.Contain("WORLD").IgnoreCase); + Assert.That("Hello World!", Does.Contain("World")); + } + #endregion + + #region RegexConstraintExamples + [Test] + public void RegexConstraint_Examples() + { + string phrase = "Make your tests fail before passing!"; + + Assert.That(phrase, Does.Match("Make.*tests.*pass")); + Assert.That(phrase, Does.Match("make.*tests.*PASS").IgnoreCase); + Assert.That(phrase, Does.Not.Match("your.*passing.*tests")); + } + #endregion + + #region RegexConstraintPatternExamples + [Test] + public void RegexConstraint_Pattern_Examples() + { + // Email validation (simplified) + Assert.That("user@example.com", Does.Match(@"^[\w.-]+@[\w.-]+\.\w+$")); + + // Phone number format + Assert.That("555-123-4567", Does.Match(@"^\d{3}-\d{3}-\d{4}$")); + + // Starts with digit + Assert.That("42 is the answer", Does.Match(@"^\d")); + + // Contains only letters and spaces + Assert.That("Hello World", Does.Match(@"^[a-zA-Z\s]+$")); + + // ISO date format + Assert.That("2024-01-15", Does.Match(@"^\d{4}-\d{2}-\d{2}$")); + } + #endregion + + #region EmptyStringConstraintExamples + [Test] + public void EmptyStringConstraint_Examples() + { + Assert.That("", Is.Empty); + Assert.That(string.Empty, Is.Empty); + Assert.That("Hello", Is.Not.Empty); + + // Common pattern: check for null or empty + string? result = ""; + Assert.That(result, Is.Null.Or.Empty); + + string name = "Alice"; + Assert.That(name, Is.Not.Null.And.Not.Empty); + } + #endregion + + #region WhiteSpaceConstraintExamples + [Test] + public void WhiteSpaceConstraint_Examples() + { + Assert.That("", Is.WhiteSpace); // Empty string + Assert.That(" ", Is.WhiteSpace); // Space + Assert.That(" \t\n", Is.WhiteSpace); // Mixed whitespace + Assert.That(null, Is.WhiteSpace); // Null + + Assert.That("Hello", Is.Not.WhiteSpace); + Assert.That(" Hello ", Is.Not.WhiteSpace); // Has non-whitespace content + } + #endregion +} diff --git a/docs/snippets/Snippets.NUnit/Constraints/TypeConstraintSnippets.cs b/docs/snippets/Snippets.NUnit/Constraints/TypeConstraintSnippets.cs new file mode 100644 index 000000000..16aa4be63 --- /dev/null +++ b/docs/snippets/Snippets.NUnit/Constraints/TypeConstraintSnippets.cs @@ -0,0 +1,125 @@ +using NUnit.Framework; + +#pragma warning disable NUnit2045 + +namespace Snippets.NUnit.Constraints; + +public class TypeConstraintSnippets +{ + #region InstanceOfTypeConstraintExamples + [Test] + public void InstanceOfTypeConstraint_Examples() + { + // Basic type checking + Assert.That("Hello", Is.InstanceOf(typeof(string))); + Assert.That("Hello", Is.InstanceOf()); + Assert.That(42, Is.InstanceOf()); + + // Inheritance: derived types pass + Assert.That("Hello", Is.InstanceOf()); // string derives from object + Assert.That(new List(), Is.InstanceOf>()); + + // Interface checking + Assert.That(new List(), Is.InstanceOf>()); + Assert.That(new Dictionary(), Is.InstanceOf>()); + + // Negative tests + Assert.That("Hello", Is.Not.InstanceOf()); + Assert.That(null, Is.Not.InstanceOf()); // null is not an instance of any type + } + #endregion + + #region ExactTypeConstraintExamples + [Test] + public void ExactTypeConstraint_Examples() + { + // Exact type match + Assert.That("Hello", Is.TypeOf(typeof(string))); + Assert.That("Hello", Is.TypeOf()); + Assert.That(42, Is.TypeOf()); + + // Derived types fail - exact match required + Assert.That("Hello", Is.Not.TypeOf()); // string is not exactly object + Assert.That(new List(), Is.TypeOf>()); + Assert.That(new List(), Is.Not.TypeOf>()); // List is not exactly IList + + // Common use: distinguish between value types + Assert.That(42, Is.TypeOf()); + Assert.That(42L, Is.TypeOf()); + Assert.That(42L, Is.Not.TypeOf()); + } + #endregion + + #region AssignableFromConstraintExamples + [Test] + public void AssignableFromConstraint_Examples() + { + // A string variable can be assigned from string + Assert.That("Hello", Is.AssignableFrom(typeof(string))); + Assert.That("Hello", Is.AssignableFrom()); + + // An object variable can be assigned from string (string derives from object) + Assert.That(new object(), Is.AssignableFrom()); + + // An IEnumerable variable can be assigned from List + IEnumerable items = new List(); + Assert.That(items, Is.AssignableFrom>()); + + // Negative: an int variable cannot be assigned from string + Assert.That(5, Is.Not.AssignableFrom(typeof(string))); + } + #endregion + + #region AssignableToConstraintExamples + [Test] + public void AssignableToConstraint_Examples() + { + // A string can be assigned to object (string derives from object) + Assert.That("Hello", Is.AssignableTo(typeof(object))); + Assert.That("Hello", Is.AssignableTo()); + + // A string can be assigned to IEnumerable + Assert.That("Hello", Is.AssignableTo>()); + + // A List can be assigned to IList + Assert.That(new List(), Is.AssignableTo>()); + Assert.That(new List(), Is.AssignableTo>()); + + // Negative: an int cannot be assigned to string + Assert.That(5, Is.Not.AssignableTo(typeof(string))); + } + #endregion + + #region AttributeConstraintExamples + [TestFixture(Description = "Integration tests")] + [Category("Database")] + public class AttributeConstraintExamplesFixture + { + [Test] + public void AttributeConstraint_Examples() + { + // Test that a type has an attribute with specific properties + Assert.That(typeof(AttributeConstraintExamplesFixture), Has.Attribute() + .Property("Description").EqualTo("Integration tests")); + + Assert.That(typeof(AttributeConstraintExamplesFixture), Has.Attribute(typeof(CategoryAttribute)) + .Property("Name").EqualTo("Database")); + } + } + #endregion + + #region AttributeExistsConstraintExamples + [Serializable] + public class SerializableClass { } + + [Test] + public void AttributeExistsConstraint_Examples() + { + // Test that a type has an attribute + Assert.That(typeof(SerializableClass), Has.Attribute()); + + // Negative test + Assert.That(typeof(TypeConstraintSnippets), Has.No.Attribute()); + } + #endregion +} From 7919ae9cf53d50083f15867911c2dad4cdbaa307 Mon Sep 17 00:00:00 2001 From: Terje Sandstrom Date: Fri, 8 May 2026 09:49:32 +0200 Subject: [PATCH 05/11] improvements constraints --- .../nunit/writing-tests/constraints/AsyncConstraints.md | 4 ++++ .../nunit/writing-tests/constraints/ContainsConstraint.md | 2 ++ 2 files changed, 6 insertions(+) diff --git a/docs/articles/nunit/writing-tests/constraints/AsyncConstraints.md b/docs/articles/nunit/writing-tests/constraints/AsyncConstraints.md index 119364a4f..c9ff373e3 100644 --- a/docs/articles/nunit/writing-tests/constraints/AsyncConstraints.md +++ b/docs/articles/nunit/writing-tests/constraints/AsyncConstraints.md @@ -96,11 +96,13 @@ Assert.That(await ToListAsync(service.GetItemsAsync()), Has.Some.GreaterThan(100 ## Best Practices 1. **Use async lambdas** when testing methods that return `Task` or `Task`: + ```csharp Assert.That(async () => await method(), constraint); ``` 2. **Avoid blocking calls** like `.Result` or `.Wait()` - they can cause deadlocks: + ```csharp // BAD - can deadlock Assert.That(service.GetValueAsync().Result, Is.EqualTo(42)); @@ -110,11 +112,13 @@ Assert.That(await ToListAsync(service.GetItemsAsync()), Has.Some.GreaterThan(100 ``` 3. **Use `Throws.Nothing`** to explicitly verify async code doesn't throw: + ```csharp Assert.That(async () => await service.ProcessAsync(), Throws.Nothing); ``` 4. **Use `DelayedConstraint`** for eventually-consistent operations instead of `Task.Delay`: + ```csharp // BAD - arbitrary wait await Task.Delay(1000); diff --git a/docs/articles/nunit/writing-tests/constraints/ContainsConstraint.md b/docs/articles/nunit/writing-tests/constraints/ContainsConstraint.md index b9e1ad965..d30f17d0d 100644 --- a/docs/articles/nunit/writing-tests/constraints/ContainsConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/ContainsConstraint.md @@ -57,10 +57,12 @@ When the actual value is a collection, `Does.Contain` tests for item membership: with string containment, they throw `InvalidOperationException`. This is because `SubstringConstraint` doesn't support these modifiers, while `EqualConstraint` (used for collection item comparison) does. 3. For collections of strings, `.IgnoreWhiteSpace` affects item equality comparison: + ```csharp // Works: checks if any item equals "hello world" ignoring whitespace Assert.That(new[] { "hello world" }, Does.Contain("hello world").IgnoreWhiteSpace); ``` + 4. For more explicit control, use the specific constraints directly: - [SubstringConstraint](SubstringConstraint.md) for string containment - [SomeItemsConstraint](SomeItemsConstraint.md) for collection membership From 9bd1ef732ec36b07f4f352136801a42b5508077c Mon Sep 17 00:00:00 2001 From: Terje Sandstrom Date: Fri, 8 May 2026 09:51:33 +0200 Subject: [PATCH 06/11] improvements constraints --- docs/articles/nunit/writing-tests/constraints/RangeConstraint.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/articles/nunit/writing-tests/constraints/RangeConstraint.md b/docs/articles/nunit/writing-tests/constraints/RangeConstraint.md index 7bca81ec0..a344693d7 100644 --- a/docs/articles/nunit/writing-tests/constraints/RangeConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/RangeConstraint.md @@ -29,6 +29,7 @@ Is.InRange(IComparable from, IComparable to) 1. The range is **inclusive** on both ends: `Is.InRange(1, 10)` passes for values 1, 10, and everything in between. 2. For exclusive bounds, combine `Is.GreaterThan` and `Is.LessThan` with `And`: + ```csharp Assert.That(5, Is.GreaterThan(1).And.LessThan(10)); // Exclusive bounds ``` From 50ff524aa83dbd9bc2513ede52af1d66fbafa434 Mon Sep 17 00:00:00 2001 From: Terje Sandstrom Date: Fri, 8 May 2026 09:59:10 +0200 Subject: [PATCH 07/11] improvements constraints --- .../nunit/writing-tests/constraints/ThrowsConstraint.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/articles/nunit/writing-tests/constraints/ThrowsConstraint.md b/docs/articles/nunit/writing-tests/constraints/ThrowsConstraint.md index d15115236..8ddf01140 100644 --- a/docs/articles/nunit/writing-tests/constraints/ThrowsConstraint.md +++ b/docs/articles/nunit/writing-tests/constraints/ThrowsConstraint.md @@ -56,5 +56,5 @@ Throws.Nothing ## See Also * [ThrowsNothing Constraint](ThrowsNothingConstraint.md) -* [Assert.Throws](xref:classicassertthrows) -* [Assert.ThrowsAsync](xref:classicassertthrowsasync) +* [Assert.Throws](../assertions/classic-assertions/Assert.Throws.md) +* [Assert.ThrowsAsync](../assertions/classic-assertions/Assert.ThrowsAsync.md) From bf5f25d6f5283b8c935c3a6ff55e5a634b64babf Mon Sep 17 00:00:00 2001 From: Terje Sandstrom Date: Fri, 8 May 2026 10:03:43 +0200 Subject: [PATCH 08/11] improvements constraints --- .claude/settings.local.json | 3 +- .../constraints/ContainsHelper.md | 52 +----------- .../Constraints/ContainsHelperSnippets.cs | 83 +++++++++++++++++++ 3 files changed, 89 insertions(+), 49 deletions(-) create mode 100644 docs/snippets/Snippets.NUnit/Constraints/ContainsHelperSnippets.cs diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 17a390775..f3a574b07 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -12,7 +12,8 @@ "Bash(done)", "Bash(ls:*)", "Bash(do grep \"^public class\\\\|^public sealed class\" \"$f\")", - "Bash(do grep \"^public class\" \"$f\")" + "Bash(do grep \"^public class\" \"$f\")", + "Bash(npx markdownlint-cli2:*)" ], "deny": [], "ask": [] diff --git a/docs/articles/nunit/writing-tests/constraints/ContainsHelper.md b/docs/articles/nunit/writing-tests/constraints/ContainsHelper.md index 2a53e9ac4..c0c5b326a 100644 --- a/docs/articles/nunit/writing-tests/constraints/ContainsHelper.md +++ b/docs/articles/nunit/writing-tests/constraints/ContainsHelper.md @@ -23,49 +23,15 @@ Contains.Substring(string expected) // String contains substring ## String Containment -```csharp -string text = "Hello World"; - -// Test for substring -Assert.That(text, Contains.Substring("World")); -Assert.That(text, Contains.Substring("WORLD").IgnoreCase); - -// Equivalent to Does.Contain for strings -Assert.That(text, Does.Contain("World")); -``` +[!code-csharp[ContainsHelperStringExamples](~/snippets/Snippets.NUnit/Constraints/ContainsHelperSnippets.cs#ContainsHelperStringExamples)] ## Collection Containment -```csharp -int[] numbers = { 1, 2, 3, 4, 5 }; - -// Test for item in collection -Assert.That(numbers, Contains.Item(3)); -Assert.That(numbers, Contains.Item(3).And.Contains.Item(5)); - -// Equivalent forms -Assert.That(numbers, Does.Contain(3)); -Assert.That(numbers, Has.Member(3)); -``` +[!code-csharp[ContainsHelperCollectionExamples](~/snippets/Snippets.NUnit/Constraints/ContainsHelperSnippets.cs#ContainsHelperCollectionExamples)] ## Dictionary Containment -```csharp -var dict = new Dictionary -{ - ["Alice"] = 30, - ["Bob"] = 25 -}; - -// Test for key -Assert.That(dict, Contains.Key("Alice")); - -// Test for value -Assert.That(dict, Contains.Value(30)); - -// Test for key-value pair -Assert.That(dict, Contains.Key("Alice").WithValue(30)); -``` +[!code-csharp[ContainsHelperDictionaryExamples](~/snippets/Snippets.NUnit/Constraints/ContainsHelperSnippets.cs#ContainsHelperDictionaryExamples)] ## Comparison with Other Helpers @@ -82,17 +48,7 @@ Assert.That(dict, Contains.Key("Alice").WithValue(30)); `Does.Contain()` automatically routes to the appropriate constraint: -```csharp -// String -> SubstringConstraint -Assert.That("Hello World", Does.Contain("World")); - -// Collection -> SomeItemsConstraint -Assert.That(new[] { 1, 2, 3 }, Does.Contain(2)); - -// Dictionary key check -Assert.That(dict, Does.ContainKey("Alice")); -Assert.That(dict, Does.ContainValue(30)); -``` +[!code-csharp[ContainsHelperSmartRoutingExamples](~/snippets/Snippets.NUnit/Constraints/ContainsHelperSnippets.cs#ContainsHelperSmartRoutingExamples)] ## Modifiers diff --git a/docs/snippets/Snippets.NUnit/Constraints/ContainsHelperSnippets.cs b/docs/snippets/Snippets.NUnit/Constraints/ContainsHelperSnippets.cs new file mode 100644 index 000000000..fa82332ec --- /dev/null +++ b/docs/snippets/Snippets.NUnit/Constraints/ContainsHelperSnippets.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +using NUnit.Framework; + +#pragma warning disable NUnit2045 + +namespace Snippets.NUnit.Constraints; + +public class ContainsHelperSnippets +{ + #region ContainsHelperStringExamples + [Test] + public void ContainsHelper_String_Examples() + { + string text = "Hello World"; + + // Test for substring + Assert.That(text, Contains.Substring("World")); + Assert.That(text, Contains.Substring("WORLD").IgnoreCase); + + // Equivalent to Does.Contain for strings + Assert.That(text, Does.Contain("World")); + } + #endregion + + #region ContainsHelperCollectionExamples + [Test] + public void ContainsHelper_Collection_Examples() + { + int[] numbers = { 1, 2, 3, 4, 5 }; + + // Test for item in collection + Assert.That(numbers, Contains.Item(3)); + Assert.That(numbers, Does.Contain(3).And.Contain(5)); + + // Equivalent forms + Assert.That(numbers, Does.Contain(3)); + Assert.That(numbers, Has.Member(3)); + } + #endregion + + #region ContainsHelperDictionaryExamples + [Test] + public void ContainsHelper_Dictionary_Examples() + { + var dict = new Dictionary + { + ["Alice"] = 30, + ["Bob"] = 25 + }; + + // Test for key + Assert.That(dict, Contains.Key("Alice")); + + // Test for value + Assert.That(dict, Contains.Value(30)); + + // Test for key-value pair + Assert.That(dict, Contains.Key("Alice").WithValue(30)); + } + #endregion + + #region ContainsHelperSmartRoutingExamples + [Test] + public void ContainsHelper_SmartRouting_Examples() + { + var dict = new Dictionary + { + ["Alice"] = 30, + ["Bob"] = 25 + }; + + // String -> SubstringConstraint + Assert.That("Hello World", Does.Contain("World")); + + // Collection -> SomeItemsConstraint + Assert.That(new[] { 1, 2, 3 }, Does.Contain(2)); + + // Dictionary key check + Assert.That(dict, Does.ContainKey("Alice")); + Assert.That(dict, Does.ContainValue(30)); + } + #endregion +} From 95a1f56e466ae5b3db8bc8714eed03520e072df1 Mon Sep 17 00:00:00 2001 From: Terje Sandstrom Date: Fri, 8 May 2026 10:12:30 +0200 Subject: [PATCH 09/11] improvements constraints --- .../Constraints/SpecialConstraintSnippets.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/snippets/Snippets.NUnit/Constraints/SpecialConstraintSnippets.cs b/docs/snippets/Snippets.NUnit/Constraints/SpecialConstraintSnippets.cs index 18132cedb..43787ade6 100644 --- a/docs/snippets/Snippets.NUnit/Constraints/SpecialConstraintSnippets.cs +++ b/docs/snippets/Snippets.NUnit/Constraints/SpecialConstraintSnippets.cs @@ -1,3 +1,4 @@ +using System.Threading; using NUnit.Framework; #pragma warning disable NUnit2045 @@ -88,15 +89,16 @@ public void Dispose() { } [Test] public void DelayedConstraint_Examples() { - var flag = false; + var flag = 0; // Use int for Interlocked Task.Run(async () => { await Task.Delay(50); - flag = true; + Interlocked.Exchange(ref flag, 1); }); // Poll until condition is true (or timeout) - Assert.That(() => flag, Is.True.After(500).MilliSeconds.PollEvery(50).MilliSeconds); + Assert.That(() => Interlocked.CompareExchange(ref flag, 0, 0) == 1, + Is.True.After(500).MilliSeconds.PollEvery(50).MilliSeconds); } #endregion @@ -108,11 +110,12 @@ public void DelayedConstraint_Fluent_Examples() Task.Run(async () => { await Task.Delay(50); - counter = 10; + Interlocked.Exchange(ref counter, 10); }); // Fluent time syntax - Assert.That(() => counter, Is.GreaterThan(0).After(1).Seconds.PollEvery(100).MilliSeconds); + Assert.That(() => Interlocked.CompareExchange(ref counter, 0, 0), + Is.GreaterThan(0).After(1).Seconds.PollEvery(100).MilliSeconds); } #endregion From 6b8bb84161578715353aba03bceb5998fdeccc9e Mon Sep 17 00:00:00 2001 From: Terje Sandstrom Date: Tue, 12 May 2026 11:57:03 +0200 Subject: [PATCH 10/11] deleted plan file --- .claude/plans/constraints-improvement-plan.md | 289 ------------------ 1 file changed, 289 deletions(-) delete mode 100644 .claude/plans/constraints-improvement-plan.md diff --git a/.claude/plans/constraints-improvement-plan.md b/.claude/plans/constraints-improvement-plan.md deleted file mode 100644 index 621291289..000000000 --- a/.claude/plans/constraints-improvement-plan.md +++ /dev/null @@ -1,289 +0,0 @@ -# NUnit Constraints Documentation Improvement Plan - -This plan tracks the implementation of constraint documentation improvements. For the documentation template and guidelines, see the [Constraint Documentation Skill](../.claude/skills/constraint-documentation/skill.md). - -## Source Code Analysis (2024) - -Analysis of NUnit framework source code revealed significant documentation gaps: - -### Missing Constraint Documentation - -These constraints exist in source but have NO documentation: - -| Constraint | Syntax | Description | Priority | -|------------|--------|-------------|----------| -| MultipleOfConstraint | `Is.MultipleOf(n)`, `Is.Even`, `Is.Odd` | Tests if value is multiple of another | High | -| EmptyGuidConstraint | (internal, via `Is.Empty` on Guid) | Tests if a Guid is empty/default | Low | -| ContainsConstraint | `Does.Contain()` | Routes to Substring/SomeItems based on type | Medium | - -### Undocumented Features/Modifiers - -These features exist in source but are not well documented: - -| Feature | Constraints Affected | Status | -|---------|---------------------|--------| -| `UsingPropertiesComparer()` | EqualConstraint | ✅ **Well documented** in EqualConstraint.md | -| `IgnoreWhiteSpace` | EqualConstraint, ContainsConstraint | ✅ Documented in EqualConstraint.md | -| `Is.Even`, `Is.Odd`, `Is.MultipleOf(n)` | MultipleOfConstraint | ❌ **Not documented** | -| `ApplyToAsync()` | All constraints via IAsyncConstraint | ❌ **Not documented** | -| `IgnoreLineEndingFormat` | ContainsConstraint | ❌ **Not documented** (ContainsConstraint needs docs) | -| `Contains.*` syntax helper | Various | ⚠️ Partially documented within other constraint pages | - -### Deprecated/Removed Constraints - -| Constraint | Status | Notes | -|------------|--------|-------| -| BinarySerializableConstraint | **DEPRECATED** | Removed in NUnit 4.x due to .NET 8 binary serialization removal | - -### Syntax Helper Coverage - -The source exposes constraints via 4 helper classes: - -- **Is.*** - 50+ members (most well-documented) -- **Does.*** - 10+ members (partially documented) -- **Has.*** - 20+ members (partially documented) -- **Contains.*** - 4 members (needs documentation) - -## Constraint Inventory - -### Priority 1: High-Traffic Constraints (Improve First) - -These are commonly used and should have excellent documentation: - -| Constraint | Current State | Needs | -|------------|---------------|-------| -| EqualConstraint | ✅ **Excellent** - comprehensive with UsingPropertiesComparer | UID fixed ✅ | -| NullConstraint | Minimal (1 example ref) | Full rewrite with inline examples | -| TrueConstraint | Minimal | Full rewrite | -| FalseConstraint | Minimal | Full rewrite | -| GreaterThanConstraint | Good examples, has modifiers | UID fixed ✅, add section headers | -| LessThanConstraint | Same as GreaterThan | UID fixed ✅, add section headers | -| ThrowsConstraint | Good | UID fixed ✅, minor cleanup | -| ContainsConstraint | **No dedicated doc** | Create new doc explaining routing | -| CollectionEquivalentConstraint | Moderate | Add more examples, sections | - -### Priority 2: Comparison Constraints - -| Constraint | Current State | Needs | -|------------|---------------|-------| -| GreaterThanOrEqualConstraint | Moderate | Section headers, more context | -| LessThanOrEqualConstraint | Moderate | Section headers, more context | -| RangeConstraint | External ref only | Add inline examples | -| SameAsConstraint | Minimal | Add examples showing reference equality | - -### Priority 3: String Constraints - -| Constraint | Current State | Needs | -|------------|---------------|-------| -| StartsWithConstraint | Good | Minor cleanup | -| EndsWithConstraint | Moderate | Match StartsWithConstraint quality | -| SubstringConstraint | Good | Minor cleanup | -| RegexConstraint | Moderate | Add pattern examples | -| EmptyStringConstraint | Minimal | Add examples | -| WhiteSpaceConstraint | Unknown | Review and improve | - -### Priority 4: Collection Constraints - -| Constraint | Current State | Needs | -|------------|---------------|-------| -| AllItemsConstraint | Moderate | Add subsections | -| SomeItemsConstraint | Good modifiers | Add example sections | -| NoItemConstraint | Minimal | Add examples | -| UniqueItemsConstraint | Good modifiers | Add example sections | -| CollectionOrderedConstraint | Excellent | Minor cleanup only | -| CollectionSubsetConstraint | Moderate | Add examples | -| CollectionSupersetConstraint | Moderate | Add examples | -| ExactCountConstraint | Unknown | Review | -| EmptyCollectionConstraint | Minimal | Add examples | - -### Priority 5: Type Constraints - -| Constraint | Current State | Needs | -|------------|---------------|-------| -| InstanceOfTypeConstraint | External ref only | Add inline examples | -| ExactTypeConstraint | Minimal | Add examples | -| AssignableFromConstraint | Minimal (2 one-liners) | Add context, examples | -| AssignableToConstraint | Minimal | Add examples | -| AttributeConstraint | Unknown | Review | -| AttributeExistsConstraint | Unknown | Review | - -### Priority 6: Dictionary Constraints - -| Constraint | Current State | Needs | -|------------|---------------|-------| -| DictionaryContainsKeyConstraint | Excellent | Minor cleanup | -| DictionaryContainsValueConstraint | Unknown | Review, match Key quality | -| DictionaryContainsKeyValuePairConstraint | Unknown | Review | - -### Priority 7: Property Constraints - -| Constraint | Current State | Needs | -|------------|---------------|-------| -| PropertyConstraint | External ref only | Add inline examples | -| PropertyExistsConstraint | Unknown | Review | - -### Priority 8: Path/File Constraints - -| Constraint | Current State | Needs | -|------------|---------------|-------| -| FileOrDirectoryExistsConstraint | Has modifiers (wrong format) | Fix modifier format | -| SamePathConstraint | Unknown | Review | -| SamePathOrUnderConstraint | Unknown | Review | -| SubPathConstraint | Unknown | Review | -| EmptyDirectoryConstraint | Minimal | Add examples | - -### Priority 9: Compound Constraints - -| Constraint | Current State | Needs | -|------------|---------------|-------| -| AndConstraint | Minimal | Add examples of combining | -| OrConstraint | Minimal | Add examples | -| NotConstraint | **BROKEN** - wrong example ref | Fix reference, add examples | - -### Priority 10: Special Constraints - -| Constraint | Current State | Needs | -|------------|---------------|-------| -| DelayedConstraint | Has table format | Standardize, document async support | -| ReusableConstraint | Unknown | Review | -| DefaultConstraint | Has version info | Review | -| ThrowsNothingConstraint | Unknown | Review | -| NaNConstraint | Minimal (2 one-liners) | Add context | -| BinarySerializableConstraint | **DEPRECATED** | Add deprecation notice, mark as removed in NUnit 4.x | -| XmlSerializableConstraint | Unknown | Review | -| AnyOfConstraint | Unknown | Review | - -### Priority 11: Missing Documentation (NEW) - -| Constraint | Syntax | Needs | -|------------|--------|-------| -| MultipleOfConstraint | `Is.MultipleOf(n)`, `Is.Even`, `Is.Odd` | Create new doc page | -| ContainsConstraint | `Does.Contain()` | Create clarification doc explaining routing behavior | - -### Priority 12: Feature Documentation (NEW) - -| Feature | Current State | Needs | -|---------|---------------|-------| -| Async Constraint Support | Not documented | Create guide for ApplyToAsync patterns | -| Contains.* syntax helper | Partially documented | Consider dedicated Contains helper page | -| IgnoreLineEndingFormat | Not documented | Add to ContainsConstraint when created | - -## Critical Fixes (Do First) - -1. **NotConstraint.md** - Fix wrong example reference (currently points to PropertyConstraintExamples) -2. **FileOrDirectoryExistsConstraint.md** - Fix modifier format (missing `.` prefix) -3. **UID standardization** - Update all UIDs to `constraint-` pattern - -## Snippet File Organization - -Current: All examples in single `ConstraintExamples.cs` file with regions. - -Proposed: Keep single file but ensure: -- Every constraint has at least one region -- Regions are named consistently: `Examples` -- Each region has comments explaining what's being demonstrated -- Complex constraints have multiple regions for different scenarios - -## Estimated Scope - -| Category | Files | Effort | -|----------|-------|--------| -| Critical fixes | 3 | Small | ✅ Complete | -| Full rewrites needed | ~25 | Large | -| Moderate improvements | ~15 | Medium | -| Minor cleanup only | ~12 | Small | -| **Existing docs subtotal** | **55** | | -| New constraint docs needed | 2 | Small (MultipleOf, ContainsConstraint) | -| New feature docs needed | 2 | Medium (Async support, Contains.* helper) | -| **Total** | **59** | | - -## Implementation Order - -1. **Phase 1**: Critical fixes (NotConstraint, FileOrDirectoryExists, UID standardization) ✅ Complete -2. **Phase 2**: Priority 1 high-traffic constraints -3. **Phase 3**: Priority 2-4 constraints (comparison, string, collection) -4. **Phase 4**: Priority 5-10 remaining constraints -5. **Phase 5**: Priority 11 missing constraint documentation (MultipleOfConstraint, ContainsConstraint) -6. **Phase 6**: Priority 12 feature documentation (Async support, Contains.* helper) - -## Progress Tracking - -### Phase 1: Critical Fixes -| Task | Status | Notes | -|------|--------|-------| -| Fix NotConstraint.md example reference | Complete | Fixed #PropertyConstraintExamples → #NotConstraintExamples | -| Fix FileOrDirectoryExistsConstraint.md modifiers | Complete | Added `.` prefix to IgnoreDirectories and IgnoreFiles | -| Standardize all UIDs to `constraint-` | Complete | Added UIDs to all 55 constraint files, updated 11 xref references | - -### Phase 2: Priority 1 Constraints -| Constraint | Status | Notes | -|------------|--------|-------| -| EqualConstraint | Complete | Already excellent - UID fixed | -| NullConstraint | Complete | Full rewrite with inline examples | -| TrueConstraint | Complete | Full rewrite with inline examples | -| FalseConstraint | Complete | Full rewrite with inline examples | -| GreaterThanConstraint | Complete | Restructured with Usage section, inline examples | -| LessThanConstraint | Complete | Restructured with Usage section, inline examples | -| ThrowsConstraint | Complete | Added modifiers section, inline examples | -| ContainsConstraint | Complete | **NEW** - Created doc explaining routing behavior | -| CollectionEquivalentConstraint | Complete | Restructured with better examples | - -### Phase 3: Priority 2-4 Constraints -| Constraint | Status | Notes | -|------------|--------|-------| -| GreaterThanOrEqualConstraint | Complete | Added Is.AtLeast alias, inline examples | -| LessThanOrEqualConstraint | Complete | Added Is.AtMost alias, inline examples | -| RangeConstraint | Complete | Added inline examples, noted inclusive bounds | -| SameAsConstraint | Complete | Added reference equality examples | -| StartsWithConstraint | Complete | Minor cleanup, added See Also | -| EndsWithConstraint | Complete | Minor cleanup, added See Also | -| SubstringConstraint | Complete | Minor cleanup, added See Also | -| RegexConstraint | Complete | Added common pattern examples | -| EmptyStringConstraint | Complete | Full rewrite with null-or-empty patterns | -| WhiteSpaceConstraint | Complete | Full rewrite, clarified null behavior | -| AllItemsConstraint | Complete | Full rewrite with inline examples | -| SomeItemsConstraint | Complete | Restructured, clarified membership aliases | -| NoItemConstraint | Complete | Full rewrite with inline examples | -| UniqueItemsConstraint | Complete | Restructured, added custom comparison examples | -| CollectionOrderedConstraint | Complete | Restructured with clearer examples | -| CollectionSubsetConstraint | Complete | Restructured with inline examples | -| CollectionSupersetConstraint | Complete | Restructured with inline examples | -| ExactCountConstraint | Complete | Restructured with inline examples | -| EmptyCollectionConstraint | Complete | Restructured with inline examples | - -### Phase 4: Priority 5-10 Constraints -| Constraint | Status | Notes | -|------------|--------|-------| -| InstanceOfTypeConstraint | Complete | Full rewrite with inline examples | -| ExactTypeConstraint | Complete | Full rewrite with inline examples | -| AssignableFromConstraint | Complete | Full rewrite with inline examples | -| AssignableToConstraint | Complete | Full rewrite with inline examples | -| AttributeConstraint | Complete | Restructured with clearer examples | -| AttributeExistsConstraint | Complete | Restructured with inline examples | -| DictionaryContainsKeyConstraint | Complete | Restructured, clarified comparer behavior | -| DictionaryContainsValueConstraint | Complete | Restructured with inline examples | -| DictionaryContainsKeyValuePairConstraint | Complete | Restructured with inline examples | -| PropertyConstraint | Complete | Full rewrite with shortcuts and examples | -| PropertyExistsConstraint | Complete | Restructured with inline examples | -| FileOrDirectoryExistsConstraint | Complete | Restructured with inline examples | -| EmptyDirectoryConstraint | Complete | Restructured with inline examples | -| AndConstraint | Complete | Full rewrite with precedence examples | -| OrConstraint | Complete | Full rewrite with precedence examples | -| NotConstraint | Complete | Full rewrite with inline examples | -| DelayedConstraint | Complete | Restructured with polling and time examples | -| ThrowsNothingConstraint | Complete | Restructured with inline examples | -| NaNConstraint | Complete | Restructured with inline examples | -| AnyOfConstraint | Complete | Restructured with inline examples | - -### Phase 5: Missing Constraint Documentation -| Constraint | Status | Notes | -|------------|--------|-------| -| MultipleOfConstraint | Complete | **NEW** - Created doc for Is.MultipleOf, Is.Even, Is.Odd | -| ContainsConstraint | Complete | Created in Phase 2 - explains routing behavior | - -### Phase 6: Feature Documentation -| Feature | Status | Notes | -|---------|--------|-------| -| AsyncConstraints.md | Complete | **NEW** - Guide for using constraints with async code | -| ContainsHelper.md | Complete | **NEW** - Documentation for Contains.* syntax helper | -| Constraints.md updates | Complete | Added links to new pages, added missing constraints to lists | From b095985efac0fc43c2be46e4c33dcfe5f60bd322 Mon Sep 17 00:00:00 2001 From: Terje Sandstrom Date: Tue, 12 May 2026 14:45:14 +0200 Subject: [PATCH 11/11] updated gitignore and deleted claude local settings --- .claude/settings.local.json | 21 --------------------- .gitignore | 7 ++++++- 2 files changed, 6 insertions(+), 22 deletions(-) delete mode 100644 .claude/settings.local.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json deleted file mode 100644 index f3a574b07..000000000 --- a/.claude/settings.local.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(dotnet build:*)", - "Bash(dotnet test:*)", - "Bash(docfx:*)", - "Bash(dir:*)", - "Bash(grep:*)", - "Bash(for:*)", - "Bash(do grep \"^public.*class\" \"$f\")", - "Bash(echo:*)", - "Bash(done)", - "Bash(ls:*)", - "Bash(do grep \"^public class\\\\|^public sealed class\" \"$f\")", - "Bash(do grep \"^public class\" \"$f\")", - "Bash(npx markdownlint-cli2:*)" - ], - "deny": [], - "ask": [] - } -} diff --git a/.gitignore b/.gitignore index ba1e4cd90..10da51706 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,6 @@ -code-output/ \ No newline at end of file +code-output/ +**/.claude/settings.local.json +CLAUDE.local.md +**/.claude/history/ +.claude/**/*.log +