mirror of
https://github.com/denoland/std.git
synced 2024-11-21 20:50:22 +00:00
43102325b7
* test: use `Deno.errors.NotCapable` where appropriate * copyright headers * fixes * fixes * fixes
236 lines
6.3 KiB
TypeScript
236 lines
6.3 KiB
TypeScript
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
|
|
|
import {
|
|
assert,
|
|
assertEquals,
|
|
assertStrictEquals,
|
|
assertThrows,
|
|
} from "@std/assert";
|
|
import { load, type LoadOptions, loadSync } from "./mod.ts";
|
|
import * as path from "@std/path";
|
|
import { IS_DENO_2 } from "../internal/_is_deno_2.ts";
|
|
|
|
const moduleDir = path.dirname(path.fromFileUrl(import.meta.url));
|
|
const testdataDir = path.resolve(moduleDir, "testdata");
|
|
|
|
const testOptions = Object.freeze({
|
|
envPath: path.join(testdataDir, ".env"),
|
|
});
|
|
|
|
Deno.test("load() handles non-existent .env files", async () => {
|
|
// .env doesn't exist in the current directory
|
|
assertEquals({}, await load());
|
|
assertEquals({}, loadSync());
|
|
|
|
const loadOptions = {
|
|
envPath: "some.nonexistent.env",
|
|
};
|
|
assertEquals({}, await load(loadOptions));
|
|
assertEquals({}, loadSync(loadOptions));
|
|
});
|
|
|
|
Deno.test("load() handles comprised .env and .env.defaults", async () => {
|
|
const conf = loadSync(testOptions);
|
|
assertEquals(conf.GREETING, "hello world", "loaded from .env");
|
|
|
|
const asyncConf = await load(testOptions);
|
|
assertEquals(asyncConf.GREETING, "hello world", "loaded from .env");
|
|
});
|
|
|
|
Deno.test("load() handles exported entries accessibility in Deno.env", async () => {
|
|
assert(Deno.env.get("GREETING") === undefined, "GREETING is not set");
|
|
assert(Deno.env.get("DEFAULT1") === undefined, "DEFAULT1 is not set");
|
|
|
|
loadSync({ ...testOptions, export: true });
|
|
validateExport();
|
|
|
|
await load({ ...testOptions, export: true });
|
|
validateExport();
|
|
});
|
|
|
|
function validateExport(): void {
|
|
try {
|
|
assertEquals(
|
|
Deno.env.get("GREETING"),
|
|
"hello world",
|
|
"exported from .env -> Deno.env",
|
|
);
|
|
} finally {
|
|
Deno.env.delete("GREETING");
|
|
}
|
|
}
|
|
|
|
Deno.test("load() process does not overridde env vars by .env values", async () => {
|
|
Deno.env.set("GREETING", "Do not override!");
|
|
assert(Deno.env.get("DEFAULT1") === undefined, "DEFAULT1 is not set");
|
|
|
|
validateNotOverridden(loadSync({ ...testOptions, export: true }));
|
|
validateNotOverridden(await load({ ...testOptions, export: true }));
|
|
});
|
|
|
|
function validateNotOverridden(conf: Record<string, string>): void {
|
|
try {
|
|
assertEquals(conf.GREETING, "hello world", "value from .env");
|
|
assertEquals(
|
|
Deno.env.get("GREETING"),
|
|
"Do not override!",
|
|
"not exported from .env -> Deno.env",
|
|
);
|
|
} finally {
|
|
Deno.env.delete("DEFAULT1");
|
|
}
|
|
}
|
|
|
|
Deno.test("load() loads .env successfully from default file names/paths", async () => {
|
|
const command = new Deno.Command(Deno.execPath(), {
|
|
args: [
|
|
"run",
|
|
"--no-lock",
|
|
"--allow-read",
|
|
"--allow-env",
|
|
path.join(testdataDir, "./app_defaults.ts"),
|
|
],
|
|
cwd: testdataDir,
|
|
});
|
|
const { stdout } = await command.output();
|
|
|
|
const decoder = new TextDecoder();
|
|
const conf = JSON.parse(decoder.decode(stdout).trim());
|
|
|
|
assertEquals(conf.GREETING, "hello world", "fetches .env by default");
|
|
});
|
|
|
|
Deno.test("load() expands empty values from process env expand as empty value", async () => {
|
|
try {
|
|
Deno.env.set("EMPTY", "");
|
|
|
|
// .env.single.expand contains one key which expands to the "EMPTY" process env var
|
|
const loadOptions = {
|
|
envPath: path.join(testdataDir, "./.env.single.expand"),
|
|
};
|
|
|
|
const conf = loadSync(loadOptions);
|
|
assertEquals(
|
|
conf.EXPECT_EMPTY,
|
|
"",
|
|
"empty value expanded from process env",
|
|
);
|
|
|
|
const asyncConf = await load(loadOptions);
|
|
assertEquals(
|
|
asyncConf.EXPECT_EMPTY,
|
|
"",
|
|
"empty value expanded from process env",
|
|
);
|
|
} finally {
|
|
Deno.env.delete("EMPTY");
|
|
}
|
|
});
|
|
|
|
Deno.test(
|
|
"loadSync() checks that --allow-env is not required if no process env vars are expanded upon",
|
|
{
|
|
permissions: {
|
|
read: true,
|
|
},
|
|
},
|
|
() => {
|
|
// note lack of --allow-env permission
|
|
const conf = loadSync(testOptions);
|
|
assertEquals(conf.GREETING, "hello world");
|
|
},
|
|
);
|
|
|
|
Deno.test(
|
|
"loadSync() checks that --allow-env is required when process env vars are expanded upon",
|
|
{
|
|
permissions: {
|
|
read: true,
|
|
},
|
|
},
|
|
() => {
|
|
// ./app_permission_test.ts loads a .env with one key which expands a process env var
|
|
// note lack of --allow-env permission
|
|
const loadOptions = {
|
|
envPath: path.join(testdataDir, "./.env.single.expand"),
|
|
};
|
|
assertThrows(
|
|
() => loadSync(loadOptions),
|
|
IS_DENO_2
|
|
// TODO(iuioiua): Just use `Deno.errors.NotCapable` once Deno 2 is released.
|
|
// deno-lint-ignore no-explicit-any
|
|
? (Deno as any).errors.NotCapable
|
|
: Deno.errors.PermissionDenied,
|
|
`Requires env access to "EMPTY", run again with the --allow-env flag`,
|
|
);
|
|
},
|
|
);
|
|
|
|
Deno.test(
|
|
"loadSync() checks that --allow-env restricted access works when process env vars are expanded upon",
|
|
{
|
|
permissions: {
|
|
read: true,
|
|
env: ["EMPTY"],
|
|
},
|
|
},
|
|
() => {
|
|
try {
|
|
Deno.env.set("EMPTY", "");
|
|
|
|
const loadOptions = {
|
|
envPath: path.join(testdataDir, "./.env.single.expand"),
|
|
};
|
|
const conf = loadSync(loadOptions);
|
|
assertEquals(
|
|
conf.EXPECT_EMPTY,
|
|
"",
|
|
"empty value expanded from process env",
|
|
);
|
|
} finally {
|
|
Deno.env.delete("EMPTY");
|
|
}
|
|
},
|
|
);
|
|
|
|
//TODO test permissions
|
|
|
|
Deno.test(
|
|
"loadSync() prevents file system reads of default path parameter values by using explicit null",
|
|
{
|
|
permissions: {
|
|
env: ["GREETING", "DO_NOT_OVERRIDE"],
|
|
read: [path.join(testdataDir, "./.env.multiple")],
|
|
},
|
|
},
|
|
async (t) => {
|
|
const optsNoPaths = {
|
|
envPath: null,
|
|
} satisfies LoadOptions;
|
|
|
|
const optsEnvPath = {
|
|
envPath: path.join(testdataDir, "./.env.multiple"),
|
|
} satisfies LoadOptions;
|
|
|
|
const optsOnlyEnvPath = {
|
|
...optsEnvPath,
|
|
} satisfies LoadOptions;
|
|
|
|
const assertEnv = (env: Record<string, string>): void => {
|
|
assertStrictEquals(Object.keys(env).length, 2);
|
|
assertStrictEquals(env["GREETING"], "hello world");
|
|
assertStrictEquals(env["DO_NOT_OVERRIDE"], "overridden");
|
|
};
|
|
|
|
await t.step("load", async () => {
|
|
assertStrictEquals(Object.keys(await load(optsNoPaths)).length, 0);
|
|
assertEnv(await load(optsOnlyEnvPath));
|
|
});
|
|
|
|
await t.step("loadSync", () => {
|
|
assertStrictEquals(Object.keys(loadSync(optsNoPaths)).length, 0);
|
|
assertEnv(loadSync(optsOnlyEnvPath));
|
|
});
|
|
},
|
|
);
|