+ EXPECT_EQ(value, getenv(key));
+}
+
+TEST(EnvVarSaverTest, Movable) {
+ Optional<EnvVarSaver> pSaver1;
+ pSaver1.emplace();
+ auto key = "PATH";
+ EXPECT_NE(nullptr, getenv(key));
+ auto value = std::string{getenv(key)};
+ Optional<EnvVarSaver> pSaver2;
+ pSaver2.emplace(std::move(*pSaver1));
+ pSaver1.clear();
+ PCHECK(0 == setenv(key, "blah", true));
+ EXPECT_STREQ("blah", getenv(key));
+ pSaver2.clear();
+ EXPECT_EQ(value, getenv(key));
+}
+
+TEST(EnvironmentStateTest, FailOnEmptyString) {
+ EnvVarSaver saver{};
+ char test[4] = "A=B";
+ PCHECK(0 == putenv(test));
+ auto okState = EnvironmentState::fromCurrentEnvironment();
+ test[0] = 0;
+ EXPECT_THROW(
+ EnvironmentState::fromCurrentEnvironment(), MalformedEnvironment);
+}
+
+TEST(EnvironmentStateTest, MovableAndCopyable) {
+ auto initialState = EnvironmentState::fromCurrentEnvironment();
+ auto copiedState1 = EnvironmentState::empty();
+ copiedState1.operator=(initialState);
+ EnvironmentState copiedState2{initialState};
+ EXPECT_EQ(*initialState, *copiedState1);
+ EXPECT_EQ(*initialState, *copiedState2);
+ (*initialState)["foo"] = "bar";
+ EXPECT_EQ(0, copiedState1->count("foo"));
+ EXPECT_EQ(0, copiedState2->count("foo"));
+ auto movedState1 = EnvironmentState::empty();
+ movedState1.operator=(std::move(copiedState1));
+ EnvironmentState movedState2{std::move(copiedState2)};
+ EXPECT_EQ(0, movedState1->count("foo"));
+ EXPECT_EQ(0, movedState2->count("foo"));
+ initialState->erase("foo");
+ EXPECT_EQ(*initialState, *movedState1);
+ EXPECT_EQ(*initialState, *movedState2);
+}
+
+TEST(EnvironmentStateTest, FailOnDuplicate) {
+ EnvVarSaver saver{};
+ char test[7] = "PATG=B";
+ PCHECK(0 == putenv(test));
+ auto okState = EnvironmentState::fromCurrentEnvironment();
+ test[3] = 'H';
+ EXPECT_THROW(
+ EnvironmentState::fromCurrentEnvironment(), MalformedEnvironment);
+}
+
+TEST(EnvironmentStateTest, Separation) {
+ EnvVarSaver saver{};
+ auto initialState = EnvironmentState::fromCurrentEnvironment();
+ PCHECK(0 == setenv("spork", "foon", true));
+ auto updatedState = EnvironmentState::fromCurrentEnvironment();
+ EXPECT_EQ(0, initialState->count("spork"));
+ EXPECT_EQ(1, updatedState->count("spork"));
+ EXPECT_EQ("foon", (*updatedState)["spork"]);
+ updatedState->erase("spork");
+ EXPECT_EQ(0, updatedState->count("spork"));
+ EXPECT_STREQ("foon", getenv("spork"));
+}
+
+TEST(EnvironmentStateTest, Update) {
+ EnvVarSaver saver{};
+ auto env = EnvironmentState::fromCurrentEnvironment();
+ EXPECT_EQ(nullptr, getenv("spork"));
+ (*env)["spork"] = "foon";
+ EXPECT_EQ(nullptr, getenv("spork"));
+ env.setAsCurrentEnvironment();
+ EXPECT_STREQ("foon", getenv("spork"));
+}
+
+TEST(EnvironmentStateTest, forSubprocess) {
+ auto env = EnvironmentState::empty();
+ (*env)["spork"] = "foon";
+ std::vector<std::string> expected = {"spork=foon"};
+ auto vec = env.toVector();
+ EXPECT_EQ(expected, vec);
+ Subprocess subProcess{{fLS::FLAGS_env_util_subprocess_binary},
+ {},
+ fLS::FLAGS_env_util_subprocess_binary.c_str(),
+ &vec};
+ EXPECT_EQ(0, subProcess.wait().exitStatus());
+}
+
+TEST(EnvironmentStateTest, forC) {
+ auto env = EnvironmentState::empty();
+ (*env)["spork"] = "foon";
+ EXPECT_STREQ("spork=foon", env.toPointerArray().get()[0]);
+ EXPECT_EQ(nullptr, env.toPointerArray().get()[1]);
+ char const* program = fLS::FLAGS_env_util_subprocess_binary.c_str();
+ pid_t pid;
+ PCHECK(
+ 0 == posix_spawn(
+ &pid,
+ program,
+ nullptr,
+ nullptr,
+ nullptr,
+ env.toPointerArray().get()));
+ int result;
+ PCHECK(pid == waitpid(pid, &result, 0));
+ EXPECT_EQ(0, result);