Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/mdsmith
eval/corpus/config.local.yml
coverage.out
102 changes: 102 additions & 0 deletions internal/rules/catalog/rule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3494,3 +3494,105 @@ func TestBuildCatalogEntries_Normal_NoDiagnostics(t *testing.T) {
assert.Empty(t, diags)
assert.Equal(t, "A", entries[0].fields["title"])
}

// =====================================================================
// Phase 4 coverage: Rule.Category
// =====================================================================

func TestRule_Category(t *testing.T) {
r := &Rule{}
assert.Equal(t, "meta", r.Category())
}

// =====================================================================
// Phase 4 coverage: resolveGitignore param variations
// =====================================================================

func TestResolveGitignore_DisabledByParam(t *testing.T) {
f := newTestFile(t, "index.md", "")
matcher, base := resolveGitignore(f, map[string]string{"gitignore": "false"})
assert.Nil(t, matcher)
assert.Equal(t, "", base)
}

func TestResolveGitignore_NoMatcherAvailable(t *testing.T) {
f := newTestFile(t, "index.md", "")
// GitignoreFunc is nil → GetGitignore returns nil
matcher, base := resolveGitignore(f, map[string]string{})
assert.Nil(t, matcher)
assert.Equal(t, "", base)
}

func TestResolveGitignore_WithMatcherAndSourceDir(t *testing.T) {
dir := t.TempDir()
stub := &lint.GitignoreMatcher{}
f := &lint.File{
Path: filepath.Join(dir, "index.md"),
RootDir: dir,
GitignoreFunc: func() *lint.GitignoreMatcher {
return stub
},
}
params := map[string]string{"source-dir": "docs"}
matcher, base := resolveGitignore(f, params)
assert.Same(t, stub, matcher)
assert.NotEmpty(t, base)
assert.True(t, filepath.IsAbs(base))
}

// =====================================================================
// Phase 4 coverage: scanIncludesForTarget fallback paths
// =====================================================================

func TestScanIncludesForTarget_MaxDepthExceeded(t *testing.T) {
// Pass depth > maxIncludeDepth to immediately return false.
fsys := fstest.MapFS{
"a.md": &fstest.MapFile{Data: []byte("# A\n")},
}
visited := map[string]bool{}
result := scanIncludesForTarget(fsys, "a.md", "target.md", visited, maxIncludeDepth+1, 1000)
assert.False(t, result)
}

func TestScanIncludesForTarget_FileReadError(t *testing.T) {
// File does not exist in FS → read error → returns false.
fsys := fstest.MapFS{}
visited := map[string]bool{}
result := scanIncludesForTarget(fsys, "nonexistent.md", "target.md", visited, 0, 1000)
assert.False(t, result)
}

func TestScanIncludesForTarget_NoIncludes(t *testing.T) {
// File exists but has no <?include?> directives → returns false.
fsys := fstest.MapFS{
"a.md": &fstest.MapFile{Data: []byte("# A\n\nNo includes here.\n")},
}
visited := map[string]bool{}
result := scanIncludesForTarget(fsys, "a.md", "target.md", visited, 0, 1000)
assert.False(t, result)
}

func TestScanIncludesForTarget_DirectMatch(t *testing.T) {
// File directly includes target → returns true.
fsys := fstest.MapFS{
"a.md": &fstest.MapFile{
Data: []byte("<?include\nfile: target.md\n?>\nsome content\n<?/include?>"),
},
}
visited := map[string]bool{"a.md": true}
result := scanIncludesForTarget(fsys, "a.md", "target.md", visited, 0, 1000)
assert.True(t, result)
}

func TestScanIncludesForTarget_VisitedCycleSkipped(t *testing.T) {
// File includes itself (visited) → should not recurse, returns false.
fsys := fstest.MapFS{
"a.md": &fstest.MapFile{
Data: []byte("<?include\nfile: b.md\n?>\ncontent\n<?/include?>"),
},
}
// Mark b.md as already visited to prevent recursion.
visited := map[string]bool{"a.md": true, "b.md": true}
result := scanIncludesForTarget(fsys, "a.md", "target.md", visited, 0, 1000)
assert.False(t, result)
}
112 changes: 112 additions & 0 deletions internal/rules/concisenessscoring/classifier/model_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package classifier

import (
"fmt"
"math"
"strings"
"testing"
Expand Down Expand Up @@ -278,6 +279,117 @@ func TestClassify_EmptyInputKeepsCueSliceNonNil(t *testing.T) {
}
}

// =====================================================================
// Phase 4 coverage: validateArtifact field validation
// =====================================================================

func TestValidateArtifact_EmptyModelID(t *testing.T) {
a := artifact{ModelID: "", Version: "1.0", Threshold: 0.5}
err := validateArtifact(a)
if err == nil {
t.Fatal("expected error for empty model_id")
}
if !strings.Contains(err.Error(), "model_id") {
t.Fatalf("unexpected error: %v", err)
}
}

func TestValidateArtifact_EmptyVersion(t *testing.T) {
a := artifact{ModelID: "test", Version: "", Threshold: 0.5}
err := validateArtifact(a)
if err == nil {
t.Fatal("expected error for empty version")
}
if !strings.Contains(err.Error(), "version") {
t.Fatalf("unexpected error: %v", err)
}
}

func TestValidateArtifact_InvalidThreshold(t *testing.T) {
for _, th := range []float64{0, 1, -0.1, 1.5} {
a := artifact{ModelID: "test", Version: "1.0", Threshold: th}
err := validateArtifact(a)
if err == nil {
t.Fatalf("expected error for threshold %v", th)
}
if !strings.Contains(err.Error(), "threshold") {
t.Fatalf("threshold %v: unexpected error: %v", th, err)
}
}
}

func TestValidateArtifact_EmptyWeights(t *testing.T) {
a := artifact{
ModelID: "test",
Version: "1.0",
Threshold: 0.5,
Weights: map[string]float64{},
}
err := validateArtifact(a)
if err == nil {
t.Fatal("expected error for empty weights")
}
if !strings.Contains(err.Error(), "weights") {
t.Fatalf("unexpected error: %v", err)
}
}

// =====================================================================
// Phase 4 coverage: compileLexicon per-list errors
// =====================================================================

func TestCompileLexicon_InsufficientFillerWords(t *testing.T) {
raw := lexiconArtifact{FillerWords: []string{}}
_, err := compileLexicon(raw)
if err == nil {
t.Fatal("expected error for insufficient filler_words")
}
if !strings.Contains(err.Error(), "filler_words") {
t.Fatalf("unexpected error: %v", err)
}
}

func TestCompileLexicon_InsufficientModalWords(t *testing.T) {
fillers := make([]string, minFillerWords)
for i := range fillers {
fillers[i] = fmt.Sprintf("filler%d", i)
}
raw := lexiconArtifact{
FillerWords: fillers,
ModalWords: []string{},
}
_, err := compileLexicon(raw)
if err == nil {
t.Fatal("expected error for insufficient modal_words")
}
if !strings.Contains(err.Error(), "modal_words") {
t.Fatalf("unexpected error: %v", err)
}
}

func TestCompileLexicon_InsufficientVagueWords(t *testing.T) {
fillers := make([]string, minFillerWords)
for i := range fillers {
fillers[i] = fmt.Sprintf("filler%d", i)
}
modals := make([]string, minModalWords)
for i := range modals {
modals[i] = fmt.Sprintf("modal%d", i)
}
raw := lexiconArtifact{
FillerWords: fillers,
ModalWords: modals,
VagueWords: []string{},
}
_, err := compileLexicon(raw)
if err == nil {
t.Fatal("expected error for insufficient vague_words")
}
if !strings.Contains(err.Error(), "vague_words") {
t.Fatalf("unexpected error: %v", err)
}
}

func BenchmarkClassify(b *testing.B) {
model, err := LoadEmbedded()
if err != nil {
Expand Down
107 changes: 107 additions & 0 deletions internal/rules/crossfilereferenceintegrity/rule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -459,3 +459,110 @@ func TestIsWithinRoot_NonexistentOutside(t *testing.T) {
root := resolveAbsRoot(dir)
require.False(t, isWithinRoot(root, filepath.Join(parent, "nonexistent.md")))
}

// =====================================================================
// Phase 4 coverage: DefaultSettings
// =====================================================================

func TestDefaultSettings(t *testing.T) {
r := &Rule{}
ds := r.DefaultSettings()
require.Equal(t, false, ds["strict"])
include, ok := ds["include"].([]string)
require.True(t, ok)
require.Len(t, include, 0)
exclude, ok := ds["exclude"].([]string)
require.True(t, ok)
require.Len(t, exclude, 0)
}

// =====================================================================
// Phase 4 coverage: configDiag (via invalid glob in Include field)
// =====================================================================

func TestCheck_InvalidIncludeGlobReturnsConfigDiag(t *testing.T) {
dir := t.TempDir()
sourcePath := filepath.Join(dir, "doc.md")
writeFile(t, sourcePath, "# Doc\n\nSee [link](file.md).\n")

f := newLintFile(t, sourcePath)
// Bypass ApplySettings by setting Include directly to an invalid glob.
r := &Rule{Include: []string{"["}}
diags := r.Check(f)
require.Len(t, diags, 1)
require.Contains(t, diags[0].Message, "invalid rule settings")
require.Equal(t, "MDS027", diags[0].RuleID)
}

// =====================================================================
// Phase 4 coverage: parseTarget edge cases
// =====================================================================

func TestParseTarget_AnchorOnly(t *testing.T) {
target, ok := parseTarget("#section")
require.True(t, ok)
require.Equal(t, "#section", target.Raw)
require.Equal(t, "section", target.Anchor)
require.True(t, target.LocalAnchor)
require.Equal(t, "", target.Path)
}

func TestParseTarget_Empty(t *testing.T) {
_, ok := parseTarget("")
require.False(t, ok)
}

func TestParseTarget_ProtocolRelative(t *testing.T) {
_, ok := parseTarget("//example.com/path")
require.False(t, ok)
}

func TestParseTarget_AbsoluteURL(t *testing.T) {
_, ok := parseTarget("https://example.com/path")
require.False(t, ok)
}

func TestParseTarget_PathWithAnchor(t *testing.T) {
target, ok := parseTarget("guide.md#intro")
require.True(t, ok)
require.Equal(t, "guide.md", target.Path)
require.Equal(t, "intro", target.Anchor)
require.False(t, target.LocalAnchor)
}

func TestParseTarget_EncodedPath(t *testing.T) {
target, ok := parseTarget("my%20file.md")
require.True(t, ok)
// url.Parse decodes percent-encoded characters in the path.
require.Equal(t, "my file.md", target.Path)
}

// =====================================================================
// Phase 4 coverage: toStringSlice edge cases
// =====================================================================

func TestToStringSlice_MixedTypes(t *testing.T) {
_, ok := toStringSlice([]any{"valid", 123})
require.False(t, ok)
}

func TestToStringSlice_NonSlice(t *testing.T) {
_, ok := toStringSlice("not a slice")
require.False(t, ok)
}

// =====================================================================
// Phase 4 coverage: anchor-only local ref validated against self anchors
// =====================================================================

func TestCheck_AnchorOnlyLinkMissingHeading(t *testing.T) {
dir := t.TempDir()
sourcePath := filepath.Join(dir, "doc.md")
// Link to #missing which doesn't exist in the doc.
writeFile(t, sourcePath, "# Doc\n\nSee [here](#missing).\n")

f := newLintFile(t, sourcePath)
diags := (&Rule{}).Check(f)
require.Len(t, diags, 1)
require.Contains(t, diags[0].Message, "#missing")
}
Loading
Loading