Files
bookhoard/internal/services/collection_service_test.go
john-okeefe 00a083b60b Rename backend code references: Bookmann → Bookhoard
Backend changes:
- Update import paths: bookmann/internal → bookhoard/internal
- Rename struct fields: BookmannUUID → BookhoardUUID
- Update handler function names: mapContentIdToBookmannUUID → mapContentIdToBookhoardUUID
- Update HTTP response headers: X-Bookmann-* → X-Bookhoard-*
- Update service and middleware references
- Update main.go imports and references

This is part 2 of the project rename to Bookhoard.
2026-02-01 16:11:54 -05:00

279 lines
6.1 KiB
Go

package services
import (
"bookhoard/internal/database"
"testing"
"github.com/jackc/pgx/v5/pgtype"
)
func TestEvaluateRules_Equality(t *testing.T) {
service := &CollectionService{}
mediaItem := database.ListMediaItemsRow{
Genre: pgtype.Text{String: "Science Fiction", Valid: true},
}
rules := []Rule{
{
ID: "rule-1",
Field: "genre",
Operator: "equals",
Value: "Science Fiction",
Priority: 5,
},
}
evaluations := service.EvaluateRules(mediaItem, rules)
if len(evaluations) != 1 {
t.Fatalf("expected 1 evaluation, got %d", len(evaluations))
}
if !evaluations[0].Matches {
t.Errorf("expected rule to match, but it didn't")
}
if evaluations[0].Confidence <= 0.85 {
t.Errorf("expected confidence > 0.85, got %f", evaluations[0].Confidence)
}
}
func TestEvaluateRules_NoMatch(t *testing.T) {
service := &CollectionService{}
mediaItem := database.ListMediaItemsRow{
Genre: pgtype.Text{String: "Fantasy", Valid: true},
}
rules := []Rule{
{
ID: "rule-1",
Field: "genre",
Operator: "equals",
Value: "Science Fiction",
Priority: 5,
},
}
evaluations := service.EvaluateRules(mediaItem, rules)
if len(evaluations) != 1 {
t.Fatalf("expected 1 evaluation, got %d", len(evaluations))
}
if evaluations[0].Matches {
t.Errorf("expected rule not to match, but it did")
}
if evaluations[0].Confidence != 0 {
t.Errorf("expected confidence 0, got %f", evaluations[0].Confidence)
}
}
func TestEvaluateRules_Contains(t *testing.T) {
service := &CollectionService{}
mediaItem := database.ListMediaItemsRow{
Series: pgtype.Text{String: "The Expanse", Valid: true},
}
rules := []Rule{
{
ID: "rule-1",
Field: "series",
Operator: "contains",
Value: "Expanse",
Priority: 7,
},
}
evaluations := service.EvaluateRules(mediaItem, rules)
if len(evaluations) != 1 {
t.Fatalf("expected 1 evaluation, got %d", len(evaluations))
}
if !evaluations[0].Matches {
t.Errorf("expected rule to match, but it didn't")
}
if evaluations[0].Confidence <= 0.9 {
t.Errorf("expected confidence > 0.9 with priority boost, got %f", evaluations[0].Confidence)
}
}
func TestEvaluateRules_PriorityOrder(t *testing.T) {
service := &CollectionService{}
mediaItem := database.ListMediaItemsRow{
Genre: pgtype.Text{String: "Science Fiction", Valid: true},
Series: pgtype.Text{String: "Foundation", Valid: true},
}
rules := []Rule{
{
ID: "rule-1",
Field: "genre",
Operator: "equals",
Value: "Science Fiction",
Priority: 5,
},
{
ID: "rule-2",
Field: "series",
Operator: "equals",
Value: "Foundation",
Priority: 9,
},
}
evaluations := service.EvaluateRules(mediaItem, rules)
if len(evaluations) != 2 {
t.Fatalf("expected 2 evaluations, got %d", len(evaluations))
}
if evaluations[0].RuleID != "rule-2" {
t.Errorf("expected rule-2 (higher priority) to be first, got %s", evaluations[0].RuleID)
}
if evaluations[1].RuleID != "rule-1" {
t.Errorf("expected rule-1 (lower priority) to be second, got %s", evaluations[1].RuleID)
}
if evaluations[0].Confidence <= evaluations[1].Confidence {
t.Errorf("expected higher priority rule to have higher confidence")
}
}
func TestEvaluateRules_CopyrightYear(t *testing.T) {
service := &CollectionService{}
mediaItem := database.ListMediaItemsRow{
CopyrightYear: pgtype.Int4{Int32: 2020, Valid: true},
}
rules := []Rule{
{
ID: "rule-1",
Field: "copyright_year",
Operator: "greater_than",
Value: "2019",
Priority: 5,
},
}
evaluations := service.EvaluateRules(mediaItem, rules)
if len(evaluations) != 1 {
t.Fatalf("expected 1 evaluation, got %d", len(evaluations))
}
if !evaluations[0].Matches {
t.Errorf("expected rule to match (2020 > 2019), but it didn't")
}
}
func TestEvaluateRules_MissingField(t *testing.T) {
service := &CollectionService{}
mediaItem := database.ListMediaItemsRow{}
rules := []Rule{
{
ID: "rule-1",
Field: "genre",
Operator: "equals",
Value: "Science Fiction",
Priority: 5,
},
}
evaluations := service.EvaluateRules(mediaItem, rules)
if len(evaluations) != 1 {
t.Fatalf("expected 1 evaluation, got %d", len(evaluations))
}
if evaluations[0].Matches {
t.Errorf("expected rule not to match when field is missing, but it did")
}
}
func TestEvaluateRules_CaseInsensitive(t *testing.T) {
service := &CollectionService{}
mediaItem := database.ListMediaItemsRow{
Genre: pgtype.Text{String: "science fiction", Valid: true},
}
rules := []Rule{
{
ID: "rule-1",
Field: "genre",
Operator: "equals",
Value: "SCIENCE FICTION",
Priority: 5,
},
}
evaluations := service.EvaluateRules(mediaItem, rules)
if len(evaluations) != 1 {
t.Fatalf("expected 1 evaluation, got %d", len(evaluations))
}
if !evaluations[0].Matches {
t.Errorf("expected case-insensitive match, but it didn't match")
}
}
func TestEvaluateRules_PriorityBoost(t *testing.T) {
service := &CollectionService{}
mediaItem := database.ListMediaItemsRow{
Genre: pgtype.Text{String: "Science Fiction", Valid: true},
}
rules := []Rule{
{
ID: "rule-1",
Field: "genre",
Operator: "equals",
Value: "Science Fiction",
Priority: 1,
},
{
ID: "rule-2",
Field: "genre",
Operator: "equals",
Value: "Science Fiction",
Priority: 10,
},
}
evaluations := service.EvaluateRules(mediaItem, rules)
if len(evaluations) != 2 {
t.Fatalf("expected 2 evaluations, got %d", len(evaluations))
}
// Higher priority (10) should give higher confidence than lower priority (1)
// Genre base confidence is 0.9
// Priority 1: 0.9 + 0.01 = 0.91
// Priority 10: 0.9 + 0.1 = 1.0 (capped)
if evaluations[0].Confidence != 1.0 {
t.Errorf("expected higher priority confidence to be 1.0, got %f", evaluations[0].Confidence)
}
if evaluations[1].Confidence != 0.91 {
t.Errorf("expected lower priority confidence to be 0.91, got %f", evaluations[1].Confidence)
}
// The higher priority rule should come first (sorted by priority descending)
if evaluations[0].RuleID != "rule-2" {
t.Errorf("expected higher priority rule to be first, got %s", evaluations[0].RuleID)
}
}