package backend import ( "strings" "testing" ) func TestParseEnvFile(t *testing.T) { tests := []struct { name string in string want map[string]string wantErr string }{ { name: "simple lines", in: "A=1\nB=two words\n", want: map[string]string{"A": "1", "B": "two words"}, }, { name: "comments and blanks", in: "# header\n\nA=1\n # indented comment\nB=2\n", want: map[string]string{"A": "1", "B": "2"}, }, { name: "export prefix", in: "export A=1\nexport\tB=2\n", want: map[string]string{"A": "1", "B": "2"}, }, { name: "quoted values stripped", in: "A=\"1 2\"\nB='3 4'\n", want: map[string]string{"A": "1 2", "B": "3 4"}, }, { name: "spaces around key and value trimmed", in: " A = 1 \n", want: map[string]string{"A": "1"}, }, { name: "inline comment after value", in: "A=1 # trailing\nB=\"2 # kept\"\n", want: map[string]string{"A": "1", "B": "2 # kept"}, }, { name: "equals inside value", in: "A=b=c\n", want: map[string]string{"A": "b=c"}, }, { name: "crlf line endings", in: "A=1\r\nB=2\r\n", want: map[string]string{"A": "1", "B": "2"}, }, { name: "later duplicate wins", in: "A=first\nA=second\n", want: map[string]string{"A": "second"}, }, { name: "line without equals", in: "SECRET_MATERIAL_NO_EQUALS\n", wantErr: "line 1: malformed", }, { name: "illegal key character", in: "A-B=supersecret\n", wantErr: "line 1: malformed", }, { name: "key starting with digit", in: "1KEY=supersecret\n", wantErr: "line 1: malformed", }, { name: "empty key", in: "=value\n", wantErr: "line 1: malformed", }, { name: "line number reported", in: "A=1\nB=2\nbroken line here\n", wantErr: "line 3: malformed", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := parseEnvFile([]byte(tt.in)) if tt.wantErr != "" { if err == nil { t.Fatalf("want error %q, got nil (parsed %v)", tt.wantErr, got) } if !strings.Contains(err.Error(), tt.wantErr) { t.Fatalf("error %q does not contain %q", err, tt.wantErr) } // Parse errors carry line numbers only — never line // contents (contents may be material). if strings.Contains(err.Error(), "supersecret") || strings.Contains(err.Error(), "SECRET_MATERIAL") { t.Fatalf("parse error leaks line contents: %q", err) } return } if err != nil { t.Fatalf("unexpected error: %v", err) } if len(got) != len(tt.want) { t.Fatalf("got %v, want %v", got, tt.want) } for k, v := range tt.want { if got[k] != v { t.Fatalf("key %s: got %q, want %q", k, got[k], v) } } }) } }