tmp . '/env', $content); $code = 'require ' . var_export(XXX_ROOT . '/config.lib.php', TRUE) . ";\n\$out = array();\n"; foreach ($calls as $i => $call) { if ($i === 1) $code .= $between; $code .= '$out[] = config(' . var_export($call[0], TRUE) . ', ' . var_export($call[1] ?? NULL, TRUE) . ");\n"; } $code .= 'echo json_encode($out);'; $result = PhpProcess::runPlain($code, $env + array('XXX_ENV_FILE' => $this->tmp . '/env')); $this->assertSame('', $result['stderr']); return json_decode($result['stdout'], TRUE); } public function testReadsNameValueLines(): void { $this->assertSame(array('example.org', 'stories'), $this->config("DB_HOST=example.org\nDB_NAME=stories\n", array(array('DB_HOST'), array('DB_NAME')))); } public function testSkipsCommentsBlankLinesAndLinesWithoutEquals(): void { $this->assertSame(array(NULL, NULL, 'real'), $this->config("# DB_HOST=commented\n\n \nnot a setting\nDB_USER=real\n", array(array('DB_HOST'), array('not a setting'), array('DB_USER')))); } public function testRemovesMatchingQuotesAndSpaces(): void { $this->assertSame(array('double quoted', 'single quoted', "\"unbalanced'", '', '"x'), $this->config("A = \"double quoted\" \nB='single quoted'\nC=\"unbalanced'\nD=\"\"\nE=\"x\n", array(array('A'), array('B'), array('C'), array('D'), array('E')))); } public function testKeepsEqualsSignsInValues(): void { $this->assertSame(array('a=b==c'), $this->config("DB_PASS=a=b==c\n", array(array('DB_PASS')))); } public function testAcceptsExportPrefix(): void { $this->assertSame(array('exported'), $this->config("export DB_HOST=exported\n", array(array('DB_HOST')))); } public function testTheLastOfTwoLinesWins(): void { $this->assertSame(array('second'), $this->config("KEY=first\nKEY=second\n", array(array('KEY')))); } public function testEnvironmentBeatsTheFile(): void { $this->assertSame(array('from-environment'), $this->config("DB_HOST=from-file\n", array(array('DB_HOST')), array('DB_HOST' => 'from-environment'))); } public function testDefaultWhenMissing(): void { $this->assertSame(array(NULL, 'fallback'), $this->config("OTHER=1\n", array(array('MISSING'), array('MISSING', 'fallback')))); } public function testEmptyValueIsNotTheDefault(): void { $this->assertSame(array(''), $this->config("EMPTY=\n", array(array('EMPTY', 'fallback')))); } public function testMissingFileGivesDefaults(): void { $result = PhpProcess::runPlain('require ' . var_export(XXX_ROOT . '/config.lib.php', TRUE) . '; echo config("DB_HOST", "fallback");', array('XXX_ENV_FILE' => $this->tmp . '/does-not-exist')); $this->assertSame('fallback', $result['stdout']); } public function testFileIsReadOnlyOnce(): void { $this->assertSame(array('before', 'before'), $this->config("KEY=before\n", array(array('KEY'), array('KEY')), array(), 'file_put_contents(getenv("XXX_ENV_FILE"), "KEY=after\n");')); } public function testDisplayErrorsIsOffUnlessConfigured(): void { $code = 'require ' . var_export(XXX_ROOT . '/config.lib.php', TRUE) . '; echo ini_get("display_errors"), "|", ini_get("log_errors");'; file_put_contents($this->tmp . '/env', "DISPLAY_ERRORS=\n"); $this->assertSame('|1', PhpProcess::runPlain($code, array('XXX_ENV_FILE' => $this->tmp . '/env'))['stdout']); file_put_contents($this->tmp . '/env', "DISPLAY_ERRORS=stderr\n"); $this->assertSame('stderr|1', PhpProcess::runPlain($code, array('XXX_ENV_FILE' => $this->tmp . '/env'))['stdout']); file_put_contents($this->tmp . '/env', "OTHER=1\n"); $this->assertSame('0|1', PhpProcess::runPlain($code, array('XXX_ENV_FILE' => $this->tmp . '/env'))['stdout']); } public function testTheTestsUseTheTestFile(): void { $this->assertSame('test-site-key', config('RECAPTCHA_SITE_KEY')); } public function testExampleFileListsEverySettingTheCodeReads(): void { $code = implode('', array_map('file_get_contents', array_merge( glob(XXX_ROOT . '/*.php'), glob(XXX_ROOT . '/lib/*.php'), glob(XXX_ROOT . '/publish/*.php')))); preg_match_all("/config\\('([A-Z_]+)'/", $code, $used); $example = file_get_contents(XXX_ROOT . '/.env.example'); $this->assertNotEmpty($used[1]); foreach (array_unique($used[1]) as $name) $this->assertMatchesRegularExpression("/^$name=/m", $example, "$name is missing from .env.example"); } }