package config import ( "bytes" "io" "os" "path/filepath" "strings" "testing" "time" ) func TestConfigFilePreservesDefaultsWithoutSharingMutableData(t *testing.T) { type cfg struct { Writer io.Writer `json:"-"` Secret string `json:"-"` Values map[string]int64 `json:"values"` Timers map[string]time.Duration `json:"timers"` ID int64 `json:"id"` } var writer bytes.Buffer base := cfg{Writer: &writer, Secret: "borrowedSecret", Values: map[string]int64{"old": 7}, ID: 9007199254740993} file := filepath.Join(t.TempDir(), "config.json") if err := os.WriteFile(file, []byte(`{"values":{"new":2},"timers":{"retry":"2s"}}`), 0600); err != nil { t.Fatal(err) } next, err := DecodeFile(file, base) if err != nil { t.Fatal(err) } if next.Writer != &writer || next.Secret != base.Secret || next.ID != base.ID || next.Timers["retry"] != 2*time.Second || len(base.Values) != 1 { t.Fatal("defaults lost or mutated") } next.Values["old"] = 9 if base.Values["old"] != 7 { t.Fatal("defaults shared map") } if err = os.WriteFile(file, []byte(`{"values":{"secretValue":"credential-super-secret"}}`), 0600); err != nil { t.Fatal(err) } if _, err = DecodeFile(file, base); err == nil || strings.Contains(err.Error(), "credential-super-secret") { t.Fatal("decode error leaked contents", err) } }