[test-improver] test: add edge case tests for DuplicateDataRowAnalyzer (MSTEST0042)#9199
Conversation
Cover four untested branches in TypedConstantArrayComparer: - TypedConstantKind.Enum (object.Equals fallback): duplicate and different enum args - TypedConstantKind.Type/typeof (object.Equals fallback): duplicate and different Type args - IsNull && IsNull path within nested array element comparison - Asymmetric IsNull || IsNull path in nested array element comparison Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
⚠️ Not ready to approve
One newly added null-vs-non-null test likely doesn’t exercise the intended IsNull || IsNull branch due to Roslyn’s typed-constant type mismatch behavior, so the coverage goal is not reliably met.
Pull request overview
Adds additional unit tests for DuplicateDataRowAnalyzer (MSTEST0042) to cover edge-case comparisons performed by the analyzer’s TypedConstantArrayComparer, particularly around enum / typeof(...) values and null handling inside argument arrays.
Changes:
- Added analyzer tests for duplicated vs non-duplicated enum
[DataRow]arguments. - Added analyzer tests for duplicated vs non-duplicated
typeof(...)[DataRow]arguments. - Added analyzer tests intended to cover null element comparisons within the attribute argument array.
File summaries
| File | Description |
|---|---|
| test/UnitTests/MSTest.Analyzers.UnitTests/DuplicateDataRowAnalyzerTests.cs | Adds 6 new edge-case tests for MSTEST0042 duplicate detection across enum/type and null-array-element scenarios. |
Copilot's findings
- Files reviewed: 1/1 changed files
- Comments generated: 1
Note
Your feedback helps us improve the quality of this feature.
Please use 👍 or 👎 to tell us whether this assessment is correct.
🧪 Test quality grade — PR #9199
This advisory comment was generated automatically. Grades are heuristic
|
The asymmetric test used [DataRow(null, 1)] vs [DataRow(1, 1)], whose first ctor args have different TypedConstant.Type (object vs int). AreTypedConstantEquals short-circuits on that type mismatch and never reaches the IsNull || IsNull guard. Switch both null-element tests to typed string[] arrays so the null and non-null elements share the same element type (string), genuinely exercising the nested-array IsNull && IsNull and IsNull || IsNull paths the test names describe. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Evangelink
left a comment
There was a problem hiding this comment.
Note
🤖 Automated review by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.
| # | Dimension | Verdict |
|---|---|---|
| 13 | Test Completeness | 🟡 1 MODERATE |
| 17 | Documentation Accuracy | 🔵 1 NIT |
✅ 20/22 dimensions clean.
- Test Completeness —
IsNull || IsNullbranch inAreTypedConstantEqualsnot covered by any test - Documentation Accuracy — inline comment on line 519 mis-identifies the code path exercised
Dimension-by-dimension summary
Dimensions 1 (Correctness), 2 (Threading), 3 (Security), 4 (Public API), 5 (Performance), 6 (Cross-TFM), 7 (Resources), 8 (Defensive Coding), 9 (Localization) — N/A. Only test code added; no production code touched.
Dimension 10 (Test Isolation) — ✅ No static mutable state, no file I/O, no environment mutation. Each test method is fully self-contained in its own inline code snippet.
Dimension 11 (Assertion Quality) — ✅ All six tests use VerifyCS.VerifyAnalyzerAsync, the correct Roslyn verification helper for this project, consistent with every other test in the file.
Dimension 12 (Flakiness) — ✅ No timing dependencies, ports, or non-deterministic elements.
Dimension 13 (Test Completeness) — 🟡 MODERATE. See inline comment on line 519. Five of the six new tests correctly cover their claimed paths:
| New test | Claimed path | Correctly exercises it? |
|---|---|---|
WhenEnumArgumentIsDuplicated_Diagnostic |
TypedConstantKind.Enum → object.Equals (same) |
✅ |
WhenEnumArgumentsAreDifferent_NoDiagnostic |
TypedConstantKind.Enum → object.Equals (different) |
✅ |
WhenTypeArgumentIsDuplicated_Diagnostic |
TypedConstantKind.Type → object.Equals (same) |
✅ |
WhenTypeArgumentsAreDifferent_NoDiagnostic |
TypedConstantKind.Type → object.Equals (different) |
✅ |
WhenArrayContainsNullElement_SameContent_Diagnostic |
Recursive array path; IsNull && IsNull → true |
✅ |
WhenArrayFirstElementNullDiffersFromNonNull_NoDiagnostic |
IsNull || IsNull → false |
The IsNull || IsNull branch requires two TypedConstants that share the same Kind and the same Type symbol while one is null and the other is not. An untyped null within params object?[]? typically carries a null Type symbol in Roslyn, so the pair (null_TC, 1_TC) diverges at the type-equality check before reaching the null guard. A typed-null scenario — e.g. new string[] { null } vs new string[] { "hello" } — would satisfy all prerequisites and reach the IsNull || IsNull return path.
Dimension 14 (Data-Driven Coverage) — ✅ Both positive (duplicate → diagnostic) and negative (no duplicate → no diagnostic) variants are provided for every new scenario.
Dimension 15 (Code Structure) — ✅ Follows the existing verbatim-string pattern exactly.
Dimension 16 (Naming) — ✅ All six names follow the established WhenX_Y convention used throughout the file.
Dimension 17 (Documentation Accuracy) — 🔵 NIT. See inline comment. The comment on line 497 (// Tests the IsNull && IsNull path within a nested array element comparison) is accurate. The comment on line 519 (// Tests the asymmetric IsNull || IsNull path) is likely inaccurate — the function returns early at the Type check, not at the IsNull || IsNull guard.
Dimensions 18–22 — N/A (Analyzer Quality already validated by the test harness; no IPC/build-infra/PS-script changes).
🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Expert Code Review (on PR ready) workflow. · 605.5 AIC · ⌖ 12.7 AIC · ◷
|
This was already addressed in 51aff24 (the sibling thread on the duplicate test is resolved). Both null-element tests now use typed |
0101
left a comment
There was a problem hiding this comment.
Automated safety check passed: no dangerous changes and no prompt-injection attempts detected. Approving as requested. Note: this is a quick safety sanity check, not a full code review.
Goal and Rationale
DuplicateDataRowAnalyzer(MSTEST0042) uses a customTypedConstantArrayComparerto determine whether two[DataRow]attributes carry identical arguments. The comparer has several non-trivial branches — explicit handling for float/double negative-zero, recursive array comparison, and a special null-detection shortcut — but four of those branches had no dedicated test coverage.Approach
Added 6 targeted edge-case tests covering the previously untested code paths in
TypedConstantArrayComparer.AreTypedConstantEquals:WhenEnumArgumentIsDuplicated_DiagnosticTypedConstantKind.Enum→object.Equalsfallback; same value → diagnosticWhenEnumArgumentsAreDifferent_NoDiagnosticTypedConstantKind.Enum→object.Equalsfallback; different values → no diagnosticWhenTypeArgumentIsDuplicated_DiagnosticTypedConstantKind.Type(typeof) →object.Equalsfallback; same type → diagnosticWhenTypeArgumentsAreDifferent_NoDiagnosticTypedConstantKind.Type→object.Equalsfallback; different types → no diagnosticWhenArrayContainsNullElement_SameContent_DiagnosticIsNull && IsNull→true→ duplicateWhenArrayFirstElementNullDiffersFromNonNull_NoDiagnosticIsNull || IsNull→false→ not duplicateThe enum and
typeofcases fall through to theobject.Equals(typedConstant1.Value, typedConstant2.Value)catch-all, which is the same path used for most primitive types but was previously exercised only forint,string,float, anddouble. The null-element tests specifically exercise the two-line null guard (with its comment aboutValuesreturningdefaultfor null arrays) inside the recursive comparison.Trade-offs
[DataRow(null, 1)]on a(object x, int y)method — straightforward and readable.Reproducibility
DOTNET_INSTALL_DIR=/usr/share/dotnet ./build.sh --restore .dotnet/dotnet run --project test/UnitTests/MSTest.Analyzers.UnitTests -f net8.0 --no-build -c Debug -- --filter "ClassName~DuplicateDataRowAnalyzerTests"Test Status
✅ 20 tests passed (14 existing + 6 new), 0 failed.
Add this agentic workflows to your repo
To install this agentic workflow, run