Skip to content

Strengthen fuzzy_match edge-case contracts in stringutil tests#35077

Merged
pelikhan merged 2 commits into
mainfrom
copilot/testify-expert-improve-stringutil-tests
May 27, 2026
Merged

Strengthen fuzzy_match edge-case contracts in stringutil tests#35077
pelikhan merged 2 commits into
mainfrom
copilot/testify-expert-improve-stringutil-tests

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 26, 2026

pkg/stringutil/fuzzy_match_test.go covered core behavior but left key contract edges implicit. This update adds focused table-driven cases to lock in exclusion thresholds, nil/zero-result behavior, and deterministic ordering.

  • FindClosestMatches: edge-case contract coverage

    • Adds explicit case where a distance-4 candidate is excluded (distance cutoff remains <= 3).
    • Adds nil candidates case to ensure return is nil (no panic/regression surface).
    • Adds maxResults: 0 case to ensure no suggestions are returned.
  • FindClosestMatches: deterministic ordering contract

    • Adds a tie case with equal distances to verify alphabetical tie-breaking is enforced.
  • LevenshteinDistance: byte-level behavior documentation

    • Adds a multibyte UTF-8 case ("é" vs "e") with an inline comment to document current byte-based distance semantics.
{
    name:       "alphabetical tie breaking for equal distances",
    target:     "zzzz",
    candidates: []string{"zzzb", "zzza"},
    maxResults: 2,
    want:       []string{"zzza", "zzzb"},
}

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
Copilot AI changed the title [WIP] Improve test quality for fuzzy_match_test.go Strengthen fuzzy_match edge-case contracts in stringutil tests May 26, 2026
Copilot AI requested a review from gh-aw-bot May 26, 2026 23:45
@pelikhan pelikhan marked this pull request as ready for review May 27, 2026 00:05
Copilot AI review requested due to automatic review settings May 27, 2026 00:05
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

🧪 Test Quality Sentinel completed test quality analysis.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR #35077 does not have the 'implementation' label and has only 30 new lines of code in business logic directories (threshold: 100).

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

PR Code Quality Reviewer completed the code quality review.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR strengthens the contract coverage for pkg/stringutil fuzzy-matching behavior by adding targeted, table-driven tests for edge cases and ordering rules, plus a clarifying UTF-8/byte semantics case for LevenshteinDistance.

Changes:

  • Adds explicit FindClosestMatches cases for nil candidates, maxResults == 0, and excluding candidates beyond the distance cutoff (> 3).
  • Adds a deterministic ordering test to lock in alphabetical tie-breaking when edit distances are equal.
  • Adds a multibyte UTF-8 example to document that LevenshteinDistance currently operates on bytes (not runes).
Show a summary per file
File Description
pkg/stringutil/fuzzy_match_test.go Adds table-driven edge-case, ordering, and UTF-8/byte-semantics test coverage for fuzzy matching and Levenshtein distance.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 1/1 changed files
  • Comments generated: 0

@github-actions github-actions Bot mentioned this pull request May 27, 2026
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All five new test cases are mathematically correct against the implementation. Clean, focused test coverage.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • proxy.golang.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "proxy.golang.org"

See Network Configuration for more information.

🔎 Code quality review by PR Code Quality Reviewer · sonnet46 683.5K

@github-actions
Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 100/100 — Excellent

Analyzed 5 new test case(s) across 2 table-driven functions: 5 design, 0 implementation, 0 guideline violation(s).

📊 Metrics & Test Classification (5 tests analyzed)
Metric Value
New/modified tests analyzed 5
✅ Design tests (behavioral contracts) 5 (100%)
⚠️ Implementation tests (low value) 0 (0%)
Tests with error/edge cases 5 (100%)
Duplicate test clusters 0
Test inflation detected No (pure test-addition PR; no production code changed)
🚨 Coding-guideline violations 0

Test Classification Details

Test File Classification Issues Detected
nil candidates returns nil pkg/stringutil/fuzzy_match_test.go:90 ✅ Design Verifies nil-safety contract; edge case covered
maxResults zero returns nil pkg/stringutil/fuzzy_match_test.go:96 ✅ Design Verifies zero-bound contract; edge case covered
distance four candidate excluded pkg/stringutil/fuzzy_match_test.go:103 ✅ Design Verifies distance-threshold exclusion contract; edge case covered
alphabetical tie breaking for equal distances pkg/stringutil/fuzzy_match_test.go:110 ✅ Design Verifies deterministic ordering contract
multibyte utf8 compares bytes (LevenshteinDistance) pkg/stringutil/fuzzy_match_test.go:144 ✅ Design Documents and enforces byte-level semantics for non-ASCII; edge case covered

Language Support

Tests analyzed:

  • 🐹 Go (*_test.go): 5 tests — unit (//go:build !integration)

Verdict

Check passed. 0% of new tests are implementation tests (threshold: 30%). Every added case targets an observable behavioral contract: nil-safety, zero-bound, distance-cutoff exclusion, tie-breaking order, and multibyte byte semantics.

📖 Understanding Test Classifications

Design Tests (High Value) verify what the system does:

  • Assert on observable outputs, return values, or state changes
  • Cover error paths and boundary conditions
  • Would catch a behavioral regression if deleted
  • Remain valid even after internal refactoring

Implementation Tests (Low Value) verify how the system does it:

  • Assert on internal function calls (mocking internals)
  • Only test the happy path with typical inputs
  • Break during legitimate refactoring even when behavior is correct
  • Give false assurance: they pass even when the system is wrong

Goal: Shift toward tests that describe the system's behavioral contract — the promises it makes to its users and collaborators.

🧪 Test quality analysis by Test Quality Sentinel · sonnet46 1.1M ·

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Test Quality Sentinel: 100/100. Test quality is excellent — 0% of new tests are implementation tests (threshold: 30%). All 5 new table-driven cases enforce observable behavioral contracts.

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /tdd — approving with minor suggestions. All 30 additions are test-only, all distances are correct, and the new cases meaningfully extend the contract surface.

📋 Key Themes & Highlights

Positive Highlights

  • maxResults: 0 and nil candidates harden guard-rail contracts that weren't previously explicit
  • Alphabetical tie-breaking case locks in deterministic ordering that was only implicitly guaranteed
  • UTF-8 byte-semantics comment is accurate and the inline documentation approach is exactly right for a non-obvious implementation detail
  • ✅ Test names are descriptive and read well as specifications

Minor Suggestions (non-blocking)

  1. nil vs empty redundancy (line 91) — both cases hit the same range nil code path; either remove or add a comment explaining the distinction
  2. Distance cutoff comment (line 106) — an inline comment showing "abcdefg" distance = 4 would make the threshold self-evident without requiring the reader to trace into the function
  3. End-to-end UTF-8 test (line 141) — the byte-semantics test covers LevenshteinDistance in isolation; a companion case in FindClosestMatches would document the mixed rune/byte pipeline at the public API level

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 1.4M

},
{
name: "nil candidates returns nil",
target: "copilot",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] This nil candidates case duplicates the contract already proven by "empty candidates returns nothing" — both paths hit the same range no-op.

💡 Suggestion

Either remove this case, or add a clarifying comment that distinguishes why nil is worth a separate assertion (e.g., to guard against panics from a nil check that doesn't exist today but could be added):

// nil is distinct from []string{} in Go; both must be safe to pass.
{
    name:       "nil candidates returns nil (not a panic)",
    ...
},

Without that rationale the reader may wonder why both exist.

{
name: "distance four candidate excluded",
target: "abc",
candidates: []string{"abx", "abcdefg"},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] The test correctly excludes "abcdefg" but doesn't make the distance self-evident to a reader. Adding an inline comment documenting the exact distance makes this a stronger living specification.

💡 Suggestion
{
    name:       "distance four candidate excluded",
    target:     "abc",
    // "abcdefg" has distance 4 (> maxDistance of 3), so only "abx" (distance 1) is returned.
    candidates: []string{"abx", "abcdefg"},
    maxResults: 3,
    want:       []string{"abx"},
},

This is especially useful because the maxDistance = 3 constant is const-local to the function body — a reader can't easily cross-reference the cutoff value.

@@ -112,6 +140,8 @@ func TestLevenshteinDistance(t *testing.T) {
{name: "push vs pus", a: "push", b: "pus", want: 1},
{name: "contents vs scope typo", a: "contents", b: "cntents", want: 1},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] Great documentation of the byte-vs-rune semantic. One follow-up worth considering: FindClosestMatches applies strings.ToLower (rune-aware) before calling LevenshteinDistance (byte-based), creating a mixed-semantics pipeline for non-ASCII input.

💡 Suggested additional test for FindClosestMatches

A companion test in TestFindClosestMatches would make this gap explicit:

{
    // strings.ToLower is rune-aware; LevenshteinDistance is byte-based.
    // A multibyte candidate may appear closer or farther than expected.
    name:       "multibyte candidate utf8 byte distance",
    target:     "e",
    candidates: []string{"é"},  // byte distance 2 — exceeds cutoff, excluded
    maxResults: 3,
    want:       nil,
},

This is not a bug introduced by this PR — it's pre-existing — but the byte-level test only covers LevenshteinDistance in isolation. A FindClosestMatches counterpart makes the end-to-end contract explicit.

@github-actions
Copy link
Copy Markdown
Contributor

@copilot review all comments
Please resolve the open review threads and rerun checks.

Generated by 👨‍🍳 PR Sous Chef · gpt54 23.9M ·

@pelikhan pelikhan merged commit 787f61d into main May 27, 2026
75 of 85 checks passed
@pelikhan pelikhan deleted the copilot/testify-expert-improve-stringutil-tests branch May 27, 2026 00:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[testify-expert] Improve Test Quality: pkg/stringutil/fuzzy_match_test.go

4 participants