package rules import ( "context" "testing" ) func TestEngine_Evaluate(t *testing.T) { tests := []struct { name string config *RuleConfig metadata *URLMetadata wantErr bool check func(t *testing.T, extractors []ArchiverConfig) }{ { name: "first rule matches", config: &RuleConfig{ Rules: []Rule{ &MimetypeRule{Mimetype: "text/html", Archivers: []ArchiverConfig{{Key: "obelisk"}}}, &MimetypeRule{Mimetype: "application/pdf", Archivers: []ArchiverConfig{{Key: "direct_download"}}}, }, DefaultArchivers: []ArchiverConfig{{Key: "direct_download"}}, }, metadata: &URLMetadata{ MimeType: "text/html", }, wantErr: false, check: func(t *testing.T, extractors []ArchiverConfig) { if len(extractors) != 1 || extractors[0].Key != "obelisk" { t.Errorf("Archivers = %v, want [{key: obelisk}]", extractors) } }, }, { name: "second rule matches", config: &RuleConfig{ Rules: []Rule{ &MimetypeRule{Mimetype: "text/html", Archivers: []ArchiverConfig{{Key: "obelisk"}}}, &MimetypeRule{Mimetype: "application/pdf", Archivers: []ArchiverConfig{{Key: "direct_download"}}}, }, DefaultArchivers: []ArchiverConfig{{Key: "direct_download"}}, }, metadata: &URLMetadata{ MimeType: "application/pdf", }, wantErr: false, check: func(t *testing.T, extractors []ArchiverConfig) { if len(extractors) != 1 || extractors[0].Key != "direct_download" { t.Errorf("Archivers = %v, want [{key: direct_download}]", extractors) } }, }, { name: "no rules match - use default", config: &RuleConfig{ Rules: []Rule{ &MimetypeRule{Mimetype: "text/html", Archivers: []ArchiverConfig{{Key: "obelisk"}}}, }, DefaultArchivers: []ArchiverConfig{{Key: "direct_download"}}, }, metadata: &URLMetadata{ MimeType: "application/pdf", }, wantErr: false, check: func(t *testing.T, extractors []ArchiverConfig) { if len(extractors) != 1 || extractors[0].Key != "direct_download" { t.Errorf("Archivers = %v, want [{key: direct_download}]", extractors) } }, }, { name: "empty extractors from rule", config: &RuleConfig{ Rules: []Rule{ &MimetypeRule{Mimetype: "text/html", Archivers: []ArchiverConfig{}}, }, DefaultArchivers: []ArchiverConfig{{Key: "direct_download"}}, }, metadata: &URLMetadata{ MimeType: "text/html", }, wantErr: false, check: func(t *testing.T, extractors []ArchiverConfig) { if len(extractors) != 0 { t.Errorf("Archivers = %v, want []", extractors) } }, }, { name: "no default extractor", config: &RuleConfig{ Rules: []Rule{ &MimetypeRule{Mimetype: "text/html", Archivers: []ArchiverConfig{{Key: "obelisk"}}}, }, DefaultArchivers: []ArchiverConfig{}, }, metadata: &URLMetadata{ MimeType: "application/pdf", }, wantErr: true, }, { name: "invalid rule in config", config: &RuleConfig{ Rules: []Rule{ &MimetypeRule{Mimetype: "", Archivers: []ArchiverConfig{{Key: "obelisk"}}}, // Invalid }, DefaultArchivers: []ArchiverConfig{{Key: "direct_download"}}, }, metadata: &URLMetadata{ MimeType: "text/html", }, wantErr: true, }, { name: "nil config", config: nil, metadata: &URLMetadata{MimeType: "text/html"}, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { engine := NewEngine(tt.config) ctx := context.Background() extractors, err := engine.Evaluate(ctx, tt.metadata) if (err != nil) != tt.wantErr { t.Errorf("Evaluate() error = %v, wantErr %v", err, tt.wantErr) return } if tt.wantErr { return } if tt.check != nil { tt.check(t, extractors) } }) } } func TestEngine_Evaluate_ComplexRules(t *testing.T) { // Test with AND rule andRule := &AndRule{ Rules: []Rule{ &MimetypeRule{Mimetype: "text/html", Archivers: []ArchiverConfig{}}, &HostnameRule{Hostname: "example.com", Archivers: []ArchiverConfig{}}, }, Archivers: []ArchiverConfig{{Key: "obelisk"}}, } config := &RuleConfig{ Rules: []Rule{andRule}, DefaultArchivers: []ArchiverConfig{{Key: "direct_download"}}, } engine := NewEngine(config) ctx := context.Background() // Should match metadata := &URLMetadata{ MimeType: "text/html", Domain: "example.com", } extractors, err := engine.Evaluate(ctx, metadata) if err != nil { t.Fatalf("Evaluate() error = %v", err) } if len(extractors) != 1 || extractors[0].Key != "obelisk" { t.Errorf("Archivers = %v, want [{key: obelisk}]", extractors) } // Should not match (hostname doesn't match) metadata2 := &URLMetadata{ MimeType: "text/html", Domain: "other.com", } extractors2, err := engine.Evaluate(ctx, metadata2) if err != nil { t.Fatalf("Evaluate() error = %v", err) } if len(extractors2) != 1 || extractors2[0].Key != "direct_download" { t.Errorf("Archivers = %v, want [{key: direct_download}]", extractors2) } }