Something went wrong. Try again.
Approval-based snapshot testing library for Go (mirror)
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522package transform
import ( "regexp" "strings" "testing")
// Mock implementations for testing
type mockScrubber struct { fn func(string) string}
func (m *mockScrubber) Scrub(content string) string { return m.fn(content)}
type mockIgnorePattern struct { fn func(string, string) bool}
func (m *mockIgnorePattern) ShouldIgnore(key, value string) bool { return m.fn(key, value)}
// Tests for ApplyScrubbers
func TestApplyScrubbers_NoScrubbers(t *testing.T) { input := "hello world" result := ApplyScrubbers(input, nil)
if result != input { t.Errorf("expected %q, got %q", input, result) }}
func TestApplyScrubbers_SingleScrubber(t *testing.T) { scrubber := &mockScrubber{ fn: func(s string) string { return strings.ReplaceAll(s, "secret", "<REDACTED>") }, }
input := "my secret password" expected := "my <REDACTED> password" result := ApplyScrubbers(input, []Scrubber{scrubber})
if result != expected { t.Errorf("expected %q, got %q", expected, result) }}
func TestApplyScrubbers_MultipleScrubbers(t *testing.T) { scrubber1 := &mockScrubber{ fn: func(s string) string { return strings.ReplaceAll(s, "foo", "FOO") }, } scrubber2 := &mockScrubber{ fn: func(s string) string { return strings.ReplaceAll(s, "bar", "BAR") }, }
input := "foo and bar" expected := "FOO and BAR" result := ApplyScrubbers(input, []Scrubber{scrubber1, scrubber2})
if result != expected { t.Errorf("expected %q, got %q", expected, result) }}
func TestApplyScrubbers_OrderMatters(t *testing.T) { // Test that scrubbers are applied in order scrubber1 := &mockScrubber{ fn: func(s string) string { return strings.ReplaceAll(s, "test", "TEST") }, } scrubber2 := &mockScrubber{ fn: func(s string) string { return strings.ReplaceAll(s, "TEST", "FINAL") }, }
input := "test value" expected := "FINAL value" result := ApplyScrubbers(input, []Scrubber{scrubber1, scrubber2})
if result != expected { t.Errorf("expected %q, got %q", expected, result) }}
// Tests for TransformJSON
func TestTransformJSON_InvalidJSON(t *testing.T) { config := &Config{} _, err := TransformJSON("not valid json", config)
if err == nil { t.Error("expected error for invalid JSON") } if err != nil && !strings.Contains(err.Error(), "failed to unmarshal JSON") { t.Errorf("unexpected error message: %v", err) }}
func TestTransformJSON_EmptyConfig(t *testing.T) { config := &Config{} input := `{"name":"John","age":30}`
result, err := TransformJSON(input, config) if err != nil { t.Fatalf("unexpected error: %v", err) }
// Should return pretty-printed JSON expected := "{\n \"age\": 30,\n \"name\": \"John\"\n}" if result != expected { t.Errorf("expected:\n%s\ngot:\n%s", expected, result) }}
func TestTransformJSON_WithScrubbers(t *testing.T) { scrubber := &mockScrubber{ fn: func(s string) string { return strings.ReplaceAll(s, "John", "<NAME>") }, }
config := &Config{ Scrubbers: []Scrubber{scrubber}, }
input := `{"name":"John","age":30}` result, err := TransformJSON(input, config) if err != nil { t.Fatalf("unexpected error: %v", err) }
if !strings.Contains(result, "<NAME>") { t.Errorf("expected scrubber to be applied, got: %s", result) } if strings.Contains(result, "John") { t.Errorf("scrubber failed to replace 'John', got: %s", result) }}
func TestTransformJSON_WithIgnorePatterns(t *testing.T) { ignorePattern := &mockIgnorePattern{ fn: func(key, value string) bool { return key == "password" }, }
config := &Config{ Ignore: []IgnorePattern{ignorePattern}, }
input := `{"username":"john","password":"secret"}` result, err := TransformJSON(input, config) if err != nil { t.Fatalf("unexpected error: %v", err) }
if strings.Contains(result, "password") { t.Errorf("expected 'password' to be ignored, got: %s", result) } if !strings.Contains(result, "username") { t.Errorf("expected 'username' to be present, got: %s", result) }}
func TestTransformJSON_ComplexNested(t *testing.T) { ignorePattern := &mockIgnorePattern{ fn: func(key, value string) bool { return key == "secret" }, }
config := &Config{ Ignore: []IgnorePattern{ignorePattern}, }
input := `{ "user": { "name": "John", "secret": "hidden", "nested": { "secret": "also_hidden", "public": "visible" } } }`
result, err := TransformJSON(input, config) if err != nil { t.Fatalf("unexpected error: %v", err) }
if strings.Contains(result, "hidden") || strings.Contains(result, "also_hidden") { t.Errorf("expected nested secrets to be ignored, got: %s", result) } if !strings.Contains(result, "visible") { t.Errorf("expected 'visible' to be present, got: %s", result) }}
func TestTransformJSON_WithArrays(t *testing.T) { ignorePattern := &mockIgnorePattern{ fn: func(key, value string) bool { return key == "id" }, }
config := &Config{ Ignore: []IgnorePattern{ignorePattern}, }
input := `{ "users": [ {"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"} ] }`
result, err := TransformJSON(input, config) if err != nil { t.Fatalf("unexpected error: %v", err) }
// Should remove id fields from all array elements if strings.Contains(result, "\"id\"") { t.Errorf("expected 'id' fields to be ignored in arrays, got: %s", result) } if !strings.Contains(result, "Alice") || !strings.Contains(result, "Bob") { t.Errorf("expected names to be present, got: %s", result) }}
func TestTransformJSON_ScrubbersAndIgnoreCombined(t *testing.T) { scrubber := &mockScrubber{ fn: func(s string) string { re := regexp.MustCompile(`\d{3}-\d{3}-\d{4}`) return re.ReplaceAllString(s, "<PHONE>") }, }
ignorePattern := &mockIgnorePattern{ fn: func(key, value string) bool { return key == "ssn" }, }
config := &Config{ Scrubbers: []Scrubber{scrubber}, Ignore: []IgnorePattern{ignorePattern}, }
input := `{"name":"John","phone":"555-123-4567","ssn":"123-45-6789"}` result, err := TransformJSON(input, config) if err != nil { t.Fatalf("unexpected error: %v", err) }
// SSN field should be completely removed if strings.Contains(result, "ssn") { t.Errorf("expected 'ssn' field to be ignored, got: %s", result) }
// Phone should be scrubbed if !strings.Contains(result, "<PHONE>") { t.Errorf("expected phone to be scrubbed, got: %s", result) } if strings.Contains(result, "555-123-4567") { t.Errorf("expected phone number to be replaced, got: %s", result) }}
// Tests for helper functions
func TestValueToString_String(t *testing.T) { result := valueToString("hello") if result != "hello" { t.Errorf("expected 'hello', got %q", result) }}
func TestValueToString_Nil(t *testing.T) { result := valueToString(nil) if result != "null" { t.Errorf("expected 'null', got %q", result) }}
func TestValueToString_BoolTrue(t *testing.T) { result := valueToString(true) if result != "true" { t.Errorf("expected 'true', got %q", result) }}
func TestValueToString_BoolFalse(t *testing.T) { result := valueToString(false) if result != "false" { t.Errorf("expected 'false', got %q", result) }}
func TestValueToString_Float64(t *testing.T) { result := valueToString(42.5) if result != "42.5" { t.Errorf("expected '42.5', got %q", result) }}
func TestValueToString_Int(t *testing.T) { result := valueToString(42) if result != "42" { t.Errorf("expected '42', got %q", result) }}
func TestValueToString_ComplexType(t *testing.T) { // Map should be marshalled to JSON m := map[string]any{"key": "value"} result := valueToString(m) if result != `{"key":"value"}` { t.Errorf("expected JSON string, got %q", result) }}
func TestFilterMap_RemovesMatchingKeys(t *testing.T) { ignorePattern := &mockIgnorePattern{ fn: func(key, value string) bool { return key == "remove_me" }, }
input := map[string]any{ "keep": "value1", "remove_me": "value2", "also_keep": "value3", }
result := filterMap(input, []IgnorePattern{ignorePattern})
if _, exists := result["remove_me"]; exists { t.Error("expected 'remove_me' to be filtered out") } if result["keep"] != "value1" { t.Error("expected 'keep' to remain") } if result["also_keep"] != "value3" { t.Error("expected 'also_keep' to remain") }}
func TestFilterMap_NestedStructures(t *testing.T) { ignorePattern := &mockIgnorePattern{ fn: func(key, value string) bool { return key == "secret" }, }
input := map[string]any{ "public": "data", "nested": map[string]any{ "secret": "hidden", "public": "visible", }, }
result := filterMap(input, []IgnorePattern{ignorePattern})
nested, ok := result["nested"].(map[string]any) if !ok { t.Fatal("expected nested map") }
if _, exists := nested["secret"]; exists { t.Error("expected nested 'secret' to be filtered out") } if nested["public"] != "visible" { t.Error("expected nested 'public' to remain") }}
func TestFilterSlice_ProcessesAllElements(t *testing.T) { ignorePattern := &mockIgnorePattern{ fn: func(key, value string) bool { return key == "id" }, }
input := []any{ map[string]any{"id": "1", "name": "Alice"}, map[string]any{"id": "2", "name": "Bob"}, }
result := filterSlice(input, []IgnorePattern{ignorePattern})
if len(result) != 2 { t.Fatalf("expected 2 elements, got %d", len(result)) }
for i, item := range result { m, ok := item.(map[string]any) if !ok { t.Fatalf("expected map at index %d", i) } if _, exists := m["id"]; exists { t.Errorf("expected 'id' to be filtered at index %d", i) } if m["name"] == "" { t.Errorf("expected 'name' to remain at index %d", i) } }}
func TestWalkAndFilter_HandlesAllTypes(t *testing.T) { ignorePattern := &mockIgnorePattern{ fn: func(key, value string) bool { return false // Don't ignore anything }, }
tests := []struct { name string input any expected any }{ { name: "string passthrough", input: "hello", expected: "hello", }, { name: "number passthrough", input: 42, expected: 42, }, { name: "bool passthrough", input: true, expected: true, }, { name: "nil passthrough", input: nil, expected: nil, }, }
for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := walkAndFilter(tt.input, []IgnorePattern{ignorePattern}) if result != tt.expected { t.Errorf("expected %v, got %v", tt.expected, result) } }) }}
func TestTransformJSON_EmptyObject(t *testing.T) { config := &Config{} input := `{}`
result, err := TransformJSON(input, config) if err != nil { t.Fatalf("unexpected error: %v", err) }
expected := "{}" if result != expected { t.Errorf("expected %q, got %q", expected, result) }}
func TestTransformJSON_EmptyArray(t *testing.T) { config := &Config{} input := `[]`
result, err := TransformJSON(input, config) if err != nil { t.Fatalf("unexpected error: %v", err) }
expected := "[]" if result != expected { t.Errorf("expected %q, got %q", expected, result) }}
func TestTransformJSON_IgnoreByValue(t *testing.T) { ignorePattern := &mockIgnorePattern{ fn: func(key, value string) bool { return value == "ignore_this" }, }
config := &Config{ Ignore: []IgnorePattern{ignorePattern}, }
input := `{"field1":"keep","field2":"ignore_this","field3":"also_keep"}` result, err := TransformJSON(input, config) if err != nil { t.Fatalf("unexpected error: %v", err) }
if strings.Contains(result, "field2") { t.Errorf("expected field with ignored value to be removed, got: %s", result) } if !strings.Contains(result, "field1") || !strings.Contains(result, "field3") { t.Errorf("expected other fields to remain, got: %s", result) }}