master
cpp 213 lines 6.93 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 WSLCCLIEnvVarParserUnitTests.cpp
8
9 Abstract:
10
11 This file contains unit tests for WSLC CLI environment variable parsing and validation.
12
13 --*/
14
15 #include "precomp.h"
16 #include "windows/Common.h"
17 #include "WSLCCLITestHelpers.h"
18 #include "ContainerModel.h"
19
20 #include <filesystem>
21 #include <fstream>
22
23 using namespace wsl::windows::wslc;
24
25 namespace WSLCCLIEnvVarParserUnitTests {
26
27 class WSLCCLIEnvVarParserUnitTests
28 {
29 WSLC_TEST_CLASS(WSLCCLIEnvVarParserUnitTests)
30
31 TEST_METHOD_SETUP(TestMethodSetup)
32 {
33 EnvTestFile = wsl::windows::common::filesystem::GetTempFilename();
34 return true;
35 }
36
37 TEST_METHOD_CLEANUP(TestMethodCleanup)
38 {
39 DeleteFileW(EnvTestFile.c_str());
40 return true;
41 }
42
43 TEST_METHOD(WSLCCLIEnvVarParser_ValidEnvVars)
44 {
45 const auto parsed = models::EnvironmentVariable::Parse(L"FOO=bar");
46 VERIFY_IS_TRUE(parsed.has_value());
47 VERIFY_ARE_EQUAL(L"FOO=bar", parsed.value());
48 }
49
50 TEST_METHOD(WSLCCLIEnvVarParser_UsesProcessEnvWhenValueMissing)
51 {
52 constexpr const auto key = L"WSLC_TEST_ENV_FROM_PROCESS";
53 ScopedEnvVariable env(key, L"process_value");
54
55 const auto parsed = models::EnvironmentVariable::Parse(key);
56 VERIFY_IS_TRUE(parsed.has_value());
57 VERIFY_ARE_EQUAL(L"WSLC_TEST_ENV_FROM_PROCESS=process_value", parsed.value());
58 }
59
60 TEST_METHOD(WSLCCLIEnvVarParser_NulloptForWhitespaceOrUnsetVar)
61 {
62 const auto whitespaceOnly = models::EnvironmentVariable::Parse(L" \t ");
63 VERIFY_IS_FALSE(whitespaceOnly.has_value());
64
65 ScopedEnvVariable env(L"WSLC_TEST_ENV_UNSET");
66 const auto missingFromProcess = models::EnvironmentVariable::Parse(L"WSLC_TEST_ENV_UNSET");
67 VERIFY_IS_FALSE(missingFromProcess.has_value());
68 }
69
70 TEST_METHOD(WSLCCLIEnvVarParser_InvalidKeysThrow)
71 {
72 auto verifyThrowsWithMessage = [](const std::wstring& input, const std::wstring& expectedSubstring) {
73 try
74 {
75 (void)models::EnvironmentVariable::Parse(input);
76 VERIFY_FAIL(L"Expected exception");
77 }
78 catch (const wil::ResultException& ex)
79 {
80 VERIFY_ARE_EQUAL(E_INVALIDARG, ex.GetErrorCode());
81
82 const auto raw = ex.GetFailureInfo().pszMessage;
83 std::wstring message = raw ? raw : L"";
84 VERIFY_ARE_EQUAL(expectedSubstring, message);
85 }
86 };
87
88 verifyThrowsWithMessage(L"=value", L"Environment variable key cannot be empty");
89 verifyThrowsWithMessage(L"BAD KEY=value", L"Environment variable key 'BAD KEY' cannot contain whitespace");
90 verifyThrowsWithMessage(L"BAD\tKEY=value", L"Environment variable key 'BAD\tKEY' cannot contain whitespace");
91 verifyThrowsWithMessage(L"BAD\nKEY=value", L"Environment variable key 'BAD\nKEY' cannot contain whitespace");
92 }
93
94 TEST_METHOD(WSLCCLIEnvVarParser_ParseFileParsesAndSkipsExpectedLines)
95 {
96 constexpr const auto key = L"WSLC_TEST_ENV_FROM_FILE";
97 ScopedEnvVariable env(key, L"file_process_value");
98
99 std::ofstream file(EnvTestFile);
100 VERIFY_IS_TRUE(file.is_open());
101 file << "# comment\n";
102 file << "\n";
103 file << "KEY1=VALUE1\n";
104 file << " KEY2=VALUE2\n";
105 file << "WSLC_TEST_ENV_FROM_FILE\n";
106 file << "WSLC_TEST_ENV_DOES_NOT_EXIST\n";
107 file.close();
108
109 const auto parsed = models::EnvironmentVariable::ParseFile(EnvTestFile.wstring());
110
111 VERIFY_ARE_EQUAL(3U, parsed.size());
112 VERIFY_ARE_EQUAL(L"KEY1=VALUE1", parsed[0]);
113 VERIFY_ARE_EQUAL(L"KEY2=VALUE2", parsed[1]);
114 VERIFY_ARE_EQUAL(L"WSLC_TEST_ENV_FROM_FILE=file_process_value", parsed[2]);
115 }
116
117 TEST_METHOD(WSLCCLIEnvVarParser_ParseFileThrowsWhenMissing)
118 {
119 try
120 {
121 (void)models::EnvironmentVariable::ParseFile(L"ENV_FILE_NOT_FOUND");
122 VERIFY_FAIL(L"Expected exception");
123 }
124 catch (const wil::ResultException& ex)
125 {
126 VERIFY_ARE_EQUAL(E_INVALIDARG, ex.GetErrorCode());
127
128 const auto raw = ex.GetFailureInfo().pszMessage;
129 std::wstring message = raw ? raw : L"";
130 VERIFY_ARE_EQUAL(L"Environment file 'ENV_FILE_NOT_FOUND' cannot be opened for reading", message);
131 }
132 }
133
134 TEST_METHOD(WSLCCLIEnvVarParser_ExplicitEmptyValueIsValid)
135 {
136 const auto parsed = models::EnvironmentVariable::Parse(L"FOO=");
137 VERIFY_IS_TRUE(parsed.has_value());
138 VERIFY_ARE_EQUAL(L"FOO=", parsed.value());
139 }
140
141 TEST_METHOD(WSLCCLIEnvVarParser_MultipleEqualsPreservedInValue)
142 {
143 const auto parsed = models::EnvironmentVariable::Parse(L"FOO=a=b=c");
144 VERIFY_IS_TRUE(parsed.has_value());
145 VERIFY_ARE_EQUAL(L"FOO=a=b=c", parsed.value());
146 }
147
148 TEST_METHOD(WSLCCLIEnvVarParser_EmptyInputReturnsNullopt)
149 {
150 const auto parsed = models::EnvironmentVariable::Parse(L"");
151 VERIFY_IS_FALSE(parsed.has_value());
152 }
153
154 TEST_METHOD(WSLCCLIEnvVarParser_UsesProcessEnvWhenValueIsExplicitlyEmpty)
155 {
156 constexpr const auto key = L"WSLC_TEST_ENV_EMPTY_VALUE";
157 ScopedEnvVariable env(key, L"");
158
159 const auto parsed = models::EnvironmentVariable::Parse(key);
160 VERIFY_IS_TRUE(parsed.has_value());
161 VERIFY_ARE_EQUAL(L"WSLC_TEST_ENV_EMPTY_VALUE=", parsed.value());
162 }
163
164 TEST_METHOD(WSLCCLIEnvVarParser_ParseFilePreservesTrailingWhitespaceInValue)
165 {
166 std::ofstream file(EnvTestFile);
167 VERIFY_IS_TRUE(file.is_open());
168 file << "KEY=value \n";
169 file.close();
170
171 const auto parsed = models::EnvironmentVariable::ParseFile(EnvTestFile.wstring());
172
173 VERIFY_ARE_EQUAL(1U, parsed.size());
174 VERIFY_ARE_EQUAL(L"KEY=value ", parsed[0]);
175 }
176
177 TEST_METHOD(WSLCCLIEnvVarParser_ParseFileThrowsOnInvalidLine)
178 {
179 try
180 {
181 std::ofstream file(EnvTestFile);
182 VERIFY_IS_TRUE(file.is_open());
183 file << "BAD KEY=value\n";
184 file.close();
185
186 (void)models::EnvironmentVariable::ParseFile(EnvTestFile.wstring());
187 VERIFY_FAIL(L"Expected exception");
188 }
189 catch (const wil::ResultException& ex)
190 {
191 VERIFY_ARE_EQUAL(E_INVALIDARG, ex.GetErrorCode());
192
193 const auto raw = ex.GetFailureInfo().pszMessage;
194 std::wstring message = raw ? raw : L"";
195 VERIFY_ARE_EQUAL(L"Environment variable key 'BAD KEY' cannot contain whitespace", message);
196 }
197 }
198
199 TEST_METHOD(WSLCCLIEnvVarParser_ParseFileEmptyFileReturnsEmpty)
200 {
201 std::ofstream file(EnvTestFile);
202 VERIFY_IS_TRUE(file.is_open());
203 file.close();
204
205 const auto parsed = models::EnvironmentVariable::ParseFile(EnvTestFile.wstring());
206 VERIFY_ARE_EQUAL(0U, parsed.size());
207 }
208
209 private:
210 std::filesystem::path EnvTestFile;
211 };
212
213 } // namespace WSLCCLIEnvVarParserUnitTests