Skip to content

Commit 9aaf4ba

Browse files
committed
test: add tests for 8 previously untested packages
Added tests for privacy, dedup, intent, conflict, config, utils, hooks, and mental packages. All passing.
1 parent 4a05afa commit 9aaf4ba

8 files changed

Lines changed: 648 additions & 0 deletions

File tree

config/config_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package config
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"testing"
7+
)
8+
9+
func TestDefault(t *testing.T) {
10+
cfg := Default()
11+
12+
if cfg.Server.Port != 3456 {
13+
t.Errorf("expected port 3456, got %d", cfg.Server.Port)
14+
}
15+
if cfg.Server.Host != "127.0.0.1" {
16+
t.Errorf("expected host 127.0.0.1, got %s", cfg.Server.Host)
17+
}
18+
if cfg.Memory.HotTokenBudget != 800 {
19+
t.Errorf("expected hot token budget 800, got %d", cfg.Memory.HotTokenBudget)
20+
}
21+
if cfg.Decay.HalfLifeDays != 30 {
22+
t.Errorf("expected half life 30, got %d", cfg.Decay.HalfLifeDays)
23+
}
24+
if !cfg.Decay.Enabled {
25+
t.Error("expected decay to be enabled by default")
26+
}
27+
if !cfg.Git.Watch {
28+
t.Error("expected git watch to be enabled by default")
29+
}
30+
}
31+
32+
func TestLoad_NoConfigFile(t *testing.T) {
33+
cfg, err := Load("/nonexistent/path")
34+
if err != nil {
35+
t.Fatalf("loading from nonexistent path should not error: %v", err)
36+
}
37+
if cfg.Server.Port != 3456 {
38+
t.Errorf("expected defaults when no config file, got port %d", cfg.Server.Port)
39+
}
40+
}
41+
42+
func TestLoad_ProjectConfig(t *testing.T) {
43+
dir := t.TempDir()
44+
yaadDir := filepath.Join(dir, ".yaad")
45+
os.MkdirAll(yaadDir, 0o755)
46+
47+
configContent := `[server]
48+
port = 9999
49+
host = "0.0.0.0"
50+
51+
[memory]
52+
hot_token_budget = 1600
53+
54+
[decay]
55+
half_life_days = 60
56+
`
57+
os.WriteFile(filepath.Join(yaadDir, "config.toml"), []byte(configContent), 0o644)
58+
59+
cfg, err := Load(dir)
60+
if err != nil {
61+
t.Fatalf("unexpected error: %v", err)
62+
}
63+
if cfg.Server.Port != 9999 {
64+
t.Errorf("expected port 9999 from project config, got %d", cfg.Server.Port)
65+
}
66+
if cfg.Server.Host != "0.0.0.0" {
67+
t.Errorf("expected host 0.0.0.0, got %s", cfg.Server.Host)
68+
}
69+
if cfg.Memory.HotTokenBudget != 1600 {
70+
t.Errorf("expected hot budget 1600, got %d", cfg.Memory.HotTokenBudget)
71+
}
72+
if cfg.Decay.HalfLifeDays != 60 {
73+
t.Errorf("expected half life 60, got %d", cfg.Decay.HalfLifeDays)
74+
}
75+
}
76+
77+
func TestLoad_InvalidTOML(t *testing.T) {
78+
dir := t.TempDir()
79+
yaadDir := filepath.Join(dir, ".yaad")
80+
os.MkdirAll(yaadDir, 0o755)
81+
os.WriteFile(filepath.Join(yaadDir, "config.toml"), []byte("invalid [[[ toml"), 0o644)
82+
83+
_, err := Load(dir)
84+
if err == nil {
85+
t.Error("expected error for invalid TOML")
86+
}
87+
}

conflict/resolver_test.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package conflict
2+
3+
import (
4+
"testing"
5+
6+
"github.com/GrayCodeAI/yaad/storage"
7+
)
8+
9+
func TestIsContradiction_ExplicitSignal(t *testing.T) {
10+
newNode := &storage.Node{
11+
Content: "Use jose library instead of jsonwebtoken for JWT validation",
12+
Type: "convention",
13+
Confidence: 1.0,
14+
}
15+
oldNode := &storage.Node{
16+
Content: "Use jsonwebtoken library for JWT validation in the auth service",
17+
Type: "convention",
18+
Confidence: 1.0,
19+
}
20+
if !isContradiction(newNode, oldNode) {
21+
t.Error("expected contradiction: 'instead of' signal with shared terms")
22+
}
23+
}
24+
25+
func TestIsContradiction_NoOverlap(t *testing.T) {
26+
newNode := &storage.Node{
27+
Content: "Deploy using Docker containers",
28+
Type: "decision",
29+
Confidence: 1.0,
30+
}
31+
oldNode := &storage.Node{
32+
Content: "Use PostgreSQL for the main database",
33+
Type: "decision",
34+
Confidence: 1.0,
35+
}
36+
if isContradiction(newNode, oldNode) {
37+
t.Error("no shared terms should not be a contradiction")
38+
}
39+
}
40+
41+
func TestIsContradiction_SameDecisionUpdated(t *testing.T) {
42+
newNode := &storage.Node{
43+
Content: "Authentication uses RS256 algorithm with rotating keys for token signing",
44+
Type: "decision",
45+
Confidence: 1.0,
46+
}
47+
oldNode := &storage.Node{
48+
Content: "Authentication uses HS256 algorithm with static secret for token signing",
49+
Type: "decision",
50+
Confidence: 1.0,
51+
}
52+
if !isContradiction(newNode, oldNode) {
53+
t.Error("same-topic decisions with different content should be contradictions")
54+
}
55+
}
56+
57+
func TestIsContradiction_LowOverlap(t *testing.T) {
58+
newNode := &storage.Node{
59+
Content: "The server runs on port 8080",
60+
Type: "spec",
61+
Confidence: 1.0,
62+
}
63+
oldNode := &storage.Node{
64+
Content: "The database schema has 12 tables",
65+
Type: "spec",
66+
Confidence: 1.0,
67+
}
68+
if isContradiction(newNode, oldNode) {
69+
t.Error("low overlap specs should not be contradictions")
70+
}
71+
}
72+
73+
func TestExtractKeyTerms(t *testing.T) {
74+
terms := extractKeyTerms("Use the jose library for JWT validation")
75+
if !terms["jose"] {
76+
t.Error("expected 'jose' in key terms")
77+
}
78+
if !terms["library"] {
79+
t.Error("expected 'library' in key terms")
80+
}
81+
if terms["the"] {
82+
t.Error("stop word 'the' should be excluded")
83+
}
84+
if terms["for"] {
85+
t.Error("stop word 'for' should be excluded")
86+
}
87+
}
88+
89+
func TestIsStopWord(t *testing.T) {
90+
if !isStopWord("the") {
91+
t.Error("'the' should be a stop word")
92+
}
93+
if isStopWord("database") {
94+
t.Error("'database' should not be a stop word")
95+
}
96+
}

dedup/window_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package dedup
2+
3+
import (
4+
"testing"
5+
"time"
6+
)
7+
8+
func TestWindow_BasicDedup(t *testing.T) {
9+
w := New(5 * time.Minute)
10+
11+
if w.IsDuplicate("hello world") {
12+
t.Error("first submission should not be duplicate")
13+
}
14+
if !w.IsDuplicate("hello world") {
15+
t.Error("second identical submission should be duplicate")
16+
}
17+
}
18+
19+
func TestWindow_DifferentContent(t *testing.T) {
20+
w := New(5 * time.Minute)
21+
22+
w.IsDuplicate("content A")
23+
if w.IsDuplicate("content B") {
24+
t.Error("different content should not be duplicate")
25+
}
26+
}
27+
28+
func TestWindow_WhitespaceNormalization(t *testing.T) {
29+
w := New(5 * time.Minute)
30+
31+
w.IsDuplicate("hello world")
32+
if !w.IsDuplicate("hello\t\nworld") {
33+
t.Error("whitespace-only differences should be considered duplicates")
34+
}
35+
}
36+
37+
func TestWindow_Expiry(t *testing.T) {
38+
w := New(1 * time.Millisecond)
39+
40+
w.IsDuplicate("expires fast")
41+
time.Sleep(5 * time.Millisecond)
42+
43+
if w.IsDuplicate("expires fast") {
44+
t.Error("content should not be duplicate after window expires")
45+
}
46+
}
47+
48+
func TestWindow_DefaultDuration(t *testing.T) {
49+
w := New(0)
50+
if w.duration != 5*time.Minute {
51+
t.Errorf("expected default 5m, got %v", w.duration)
52+
}
53+
}
54+
55+
func TestWindow_ConcurrentAccess(t *testing.T) {
56+
w := New(5 * time.Minute)
57+
done := make(chan bool, 10)
58+
59+
for i := 0; i < 10; i++ {
60+
go func(n int) {
61+
w.IsDuplicate("concurrent content")
62+
done <- true
63+
}(i)
64+
}
65+
66+
for i := 0; i < 10; i++ {
67+
<-done
68+
}
69+
}

hooks/relevance_test.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package hooks
2+
3+
import "testing"
4+
5+
func TestScoreRelevance_Errors(t *testing.T) {
6+
score := ScoreRelevance("Bash", "npm install", "", "exit code 1")
7+
if score < 0.9 {
8+
t.Errorf("errors should score 0.9, got %f", score)
9+
}
10+
}
11+
12+
func TestScoreRelevance_FileModifications(t *testing.T) {
13+
score := ScoreRelevance("Write", "src/components/auth/main.go", "file written successfully to disk", "")
14+
if score < 0.7 {
15+
t.Errorf("Write tool should score >= 0.7, got %f", score)
16+
}
17+
}
18+
19+
func TestScoreRelevance_ReadLowSignal(t *testing.T) {
20+
score := ScoreRelevance("Read", "src/main.go", "package main...", "")
21+
if score > 0.5 {
22+
t.Errorf("Read tool should be low signal, got %f", score)
23+
}
24+
}
25+
26+
func TestScoreRelevance_BashInstall(t *testing.T) {
27+
score := ScoreRelevance("Bash", "npm install express morgan helmet", "added 50 packages in 3.2s", "")
28+
if score < 0.7 {
29+
t.Errorf("install commands should score >= 0.7, got %f", score)
30+
}
31+
}
32+
33+
func TestScoreRelevance_BashNavigation(t *testing.T) {
34+
score := ScoreRelevance("Bash", "ls src/", "main.go utils.go", "")
35+
if score > 0.3 {
36+
t.Errorf("navigation commands should be low signal, got %f", score)
37+
}
38+
}
39+
40+
func TestScoreRelevance_DecisionSignal(t *testing.T) {
41+
score := ScoreRelevance("Bash", "decided to use jose", "switched to jose library", "")
42+
if score < 0.5 {
43+
t.Errorf("decision signals should boost score, got %f", score)
44+
}
45+
}
46+
47+
func TestShouldCapture_HighSignal(t *testing.T) {
48+
if !ShouldCapture("Write", "writing config", "done", "") {
49+
t.Error("Write tool should pass capture threshold")
50+
}
51+
}
52+
53+
func TestShouldCapture_LowSignal(t *testing.T) {
54+
if ShouldCapture("Read", "x", "y", "") {
55+
t.Error("short Read output should not pass capture threshold")
56+
}
57+
}
58+
59+
func TestScoreRelevance_CappedAt1(t *testing.T) {
60+
score := ScoreRelevance("Write", "decided to always enforce convention required", "written pattern", "")
61+
if score > 1.0 {
62+
t.Errorf("score should never exceed 1.0, got %f", score)
63+
}
64+
}
65+
66+
func TestContainsDecisionSignal(t *testing.T) {
67+
if !containsDecisionSignal("we decided to use postgres") {
68+
t.Error("should detect 'decided'")
69+
}
70+
if containsDecisionSignal("the weather is nice") {
71+
t.Error("should not detect false positives")
72+
}
73+
}
74+
75+
func TestContainsConventionSignal(t *testing.T) {
76+
if !containsConventionSignal("always use camelCase") {
77+
t.Error("should detect 'always'")
78+
}
79+
if !containsConventionSignal("this is required for deployment") {
80+
t.Error("should detect 'required'")
81+
}
82+
}

0 commit comments

Comments
 (0)