package main import ( "os" "path/filepath" "reflect" "strings" "testing" ) // dotenv_test.go pins the .env parsing rules that used to live only in comments: // парные кавычки (регресс «упростили в strings.Trim» портил бы API-ключи и // всплывал бы 401-ми посреди прогона) и «выставленное окружение не перекрывать». func TestParseDotEnvPairedQuotes(t *testing.T) { in := strings.Join([]string{ `A="v1"`, // парные двойные — снять `B='v2'`, // парные одинарные — снять `C="v3'`, // РАЗНЫЕ кавычки — не трогать `D=v4"`, // хвостовая кавычка без парной — оставить (главный регресс-кейс) `E="`, // одиночная кавычка (n<2) — оставить `F=""`, // пустые парные — пустая строка ` G = v7 `, // трим ключа и значения `# comment`, // комментарий — пропустить ``, // пустая — пропустить `no-equals-line`, // без «=» — пропустить }, "\n") got := parseDotEnv(strings.NewReader(in)) want := []dotenvPair{ {"A", "v1"}, {"B", "v2"}, {"C", `"v3'`}, {"D", `v4"`}, {"E", `"`}, {"F", ""}, {"G", "v7"}, } if !reflect.DeepEqual(got, want) { t.Fatalf("parseDotEnv:\n got %+v\n want %+v", got, want) } } func TestLoadDotEnvDoesNotOverride(t *testing.T) { path := filepath.Join(t.TempDir(), ".env") if err := os.WriteFile(path, []byte("TM_TEST_SET=from_file\nTM_TEST_UNSET=filled\n"), 0o600); err != nil { t.Fatal(err) } t.Setenv("TM_TEST_SET", "from_env") t.Setenv("TM_TEST_UNSET", "") // выставленная В ПУСТОТУ считается невыставленной (заморожено) loadDotEnv(path) if got := os.Getenv("TM_TEST_SET"); got != "from_env" { t.Fatalf("an already-set variable must win over .env, got %q", got) } if got := os.Getenv("TM_TEST_UNSET"); got != "filled" { t.Fatalf("an empty variable is treated as unset (frozen behaviour), got %q", got) } }