2020
2121import com .fasterxml .jackson .databind .ObjectMapper ;
2222import java .io .IOException ;
23+ import java .util .HashMap ;
2324import java .util .Map ;
25+ import java .util .Set ;
26+ import lombok .experimental .SuperBuilder ;
2427import org .junit .jupiter .api .Test ;
2528import org .junit .jupiter .params .ParameterizedTest ;
2629import org .junit .jupiter .params .provider .CsvSource ;
@@ -43,7 +46,7 @@ void givenEnvVariables_whenReplaceWithEnv_thenReplaceCorrectlyVars(
4346 Map .of (
4447 "USER" , "John" ,
4548 "PATH" , "/usr/bin" );
46- resolver = EnvVarResolver .of ( envVariables );
49+ resolver = EnvVarResolver .builder (). envVars ( envVariables ). build ( );
4750 var result = resolver .resolve (command );
4851 assertThat (result ).isEqualTo (expected );
4952 }
@@ -57,7 +60,7 @@ void givenEnvVariables_whenReplaceWithEnv_thenReplaceCorrectlyVars(
5760 })
5861 void givenMissingEnvVariables_whenResolveEnv_Vars_thenThrowException (String command ) {
5962 Map <String , String > envVariables = Map .of ();
60- resolver = EnvVarResolver .of ( envVariables ); // Empty map to simulate missing variables
63+ resolver = EnvVarResolver .builder (). envVars ( envVariables ). build ();
6164 assertThatThrownBy (() -> resolver .resolve (command ))
6265 .isInstanceOf (IllegalStateException .class )
6366 .hasMessageStartingWith (
@@ -76,7 +79,7 @@ void givenSimilarEnvVariableNames_whenResolveEnv_Vars_thenPartialMatchDoesNotOcc
7679 Map .of (
7780 "USER" , "John" ,
7881 "NAME" , "exists" );
79- resolver = EnvVarResolver .of ( envVariables );
82+ resolver = EnvVarResolver .builder (). envVars ( envVariables ). build ( );
8083 assertThatThrownBy (() -> resolver .resolve (command ))
8184 .isInstanceOf (IllegalStateException .class )
8285 .hasMessage (
@@ -105,7 +108,7 @@ void givenDefaultEnvValues_whenResolve_thenFallbackOrUseEnvValue(
105108 Map .of (
106109 "USER" , "John" ,
107110 "PATH" , "/usr/bin" );
108- resolver = EnvVarResolver .of ( envVariables );
111+ resolver = EnvVarResolver .builder (). envVars ( envVariables ). build ( );
109112 var result = resolver .resolve (command );
110113 assertThat (result ).isEqualTo (expected );
111114 }
@@ -120,7 +123,7 @@ void givenDefaultEnvValues_whenResolve_thenFallbackOrUseEnvValue(
120123 })
121124 void givenMissingEnvWithoutDefault_whenResolve_thenThrowException (String command ) {
122125 Map <String , String > envVariables = Map .of ("A" , "something" );
123- resolver = EnvVarResolver .of ( envVariables );
126+ resolver = EnvVarResolver .builder (). envVars ( envVariables ). build ( );
124127 assertThatThrownBy (() -> resolver .resolve (command ))
125128 .isInstanceOf (IllegalStateException .class )
126129 .hasMessageContaining ("referenced, but not found" );
@@ -136,22 +139,52 @@ void givenMissingEnvWithoutDefault_whenResolve_thenThrowException(String command
136139 })
137140 void givenFallbackWithColons_whenResolve_thenParseCorrectly (String command , String expected ) {
138141 Map <String , String > envVariables = Map .of (); // No TOKEN set
139- resolver = EnvVarResolver .of ( envVariables );
142+ resolver = EnvVarResolver .builder (). envVars ( envVariables ). build ( );
140143 var result = resolver .resolve (command );
141144 assertThat (result ).isEqualTo (expected );
142145 }
143146
147+ @ ParameterizedTest
148+ @ CsvSource ({
149+ "'${{SECRET}}', '${{SECRET}}'" ,
150+ "'Token=${{SECRET}}', 'Token=${{SECRET}}'" ,
151+ "'Host=${HOST}, password=${{DB_PASSWORD}}', 'Host=db.example.com, password=${{DB_PASSWORD}}'"
152+ })
153+ void givenSecretEnvTemplate_whenResolve_thenLeaveUnchanged (String command , String expected ) {
154+ resolver = EnvVarResolver .builder ().envVars (Map .of ("HOST" , "db.example.com" )).build ();
155+
156+ var result = resolver .resolve (command );
157+
158+ assertThat (result ).isEqualTo (expected );
159+ }
160+
161+ @ Test
162+ void givenExcludedEnvVariables_whenResolve_thenLeavePlaceholdersUnchanged () {
163+ resolver =
164+ EnvVarResolver .builder ()
165+ .envVars (
166+ Map .of (
167+ "USER" , "John" ,
168+ "EXCLUDED" , "ignored" ))
169+ .exclusions (Set .of ("EXCLUDED" , "MISSING_EXCLUDED" ))
170+ .build ();
171+
172+ var result = resolver .resolve ("${USER}|${EXCLUDED}|${EXCLUDED:-fallback}|${MISSING_EXCLUDED}" );
173+
174+ assertThat (result ).isEqualTo ("John|${EXCLUDED}|${EXCLUDED:-fallback}|${MISSING_EXCLUDED}" );
175+ }
176+
144177 @ Test
145178 void givenNullOrBlankSource_whenResolve_thenReturnSource () {
146- resolver = EnvVarResolver .of ( Map .of ());
179+ resolver = EnvVarResolver .builder (). envVars ( Map .of ()). build ( );
147180
148181 assertThat (resolver .resolve (null )).isNull ();
149182 assertThat (resolver .resolve (" " )).isEqualTo (" " );
150183 }
151184
152185 @ Test
153186 void givenNonStrictResolver_whenMissingEnvVariables_thenLeavesPlaceholdersUnresolved () {
154- resolver = EnvVarResolver .of ( Map .of ("USER" , "John" ), false );
187+ resolver = EnvVarResolver .builder (). envVars ( Map .of ("USER" , "John" )). strict ( false ). build ( );
155188
156189 var result = resolver .resolve ("Hello ${USER}, ${MISSING}!" );
157190
@@ -161,10 +194,13 @@ void givenNonStrictResolver_whenMissingEnvVariables_thenLeavesPlaceholdersUnreso
161194 @ Test
162195 void givenDeploymentDefaults_whenResolve_thenUseDefaultsAndSuppliedValues () {
163196 resolver =
164- EnvVarResolver .withDeploymentDefaults (
165- Map .of (
166- "DEPLOYMENT_ID" , "deployment-1" ,
167- "USER" , "John" ));
197+ EnvVarResolver .builder ()
198+ .envVars (
199+ withDeploymentDefaults (
200+ Map .of (
201+ "DEPLOYMENT_ID" , "deployment-1" ,
202+ "USER" , "John" )))
203+ .build ();
168204
169205 var result = resolver .resolve ("${DEPLOYMENT_ID}|${DEPLOYMENT_TIMESTAMP}|${USER}" );
170206 var parts = result .split ("\\ |" );
@@ -178,7 +214,10 @@ void givenDeploymentDefaults_whenResolve_thenUseDefaultsAndSuppliedValues() {
178214 @ Test
179215 void givenNonStrictDeploymentDefaults_whenMissingNonDefaultEnvVariable_thenLeavesPlaceholder () {
180216 resolver =
181- EnvVarResolver .withDeploymentDefaults (Map .of ("DEPLOYMENT_ID" , "deployment-1" ), false );
217+ EnvVarResolver .builder ()
218+ .envVars (withDeploymentDefaults (Map .of ("DEPLOYMENT_ID" , "deployment-1" )))
219+ .strict (false )
220+ .build ();
182221
183222 var result = resolver .resolve ("${DEPLOYMENT_ID}|${MISSING}" );
184223
@@ -187,7 +226,7 @@ void givenNonStrictDeploymentDefaults_whenMissingNonDefaultEnvVariable_thenLeave
187226
188227 @ Test
189228 void givenJsonSource_whenResolveInJson_thenResolveStringLeafNodes () throws IOException {
190- resolver = EnvVarResolver .of ( Map .of ("USER" , "John" ));
229+ resolver = EnvVarResolver .builder (). envVars ( Map .of ("USER" , "John" )). build ( );
191230
192231 var result =
193232 resolver .resolveInJson (
@@ -198,4 +237,36 @@ void givenJsonSource_whenResolveInJson_thenResolveStringLeafNodes() throws IOExc
198237 assertThat (json .get ("count" ).asInt ()).isEqualTo (1 );
199238 assertThat (json .get ("nested" ).get ("path" ).asText ()).isEqualTo ("/tmp" );
200239 }
240+
241+ @ Test
242+ void givenSubclass_whenBuild_thenInheritedBuilderFieldsAreApplied () {
243+ resolver =
244+ TestEnvVarResolver .builder ()
245+ .envVars (Map .of ("USER" , "John" ))
246+ .strict (false )
247+ .prefix ("resolved=" )
248+ .build ();
249+
250+ var result = resolver .resolve ("${USER}:${MISSING}" );
251+
252+ assertThat (result ).isEqualTo ("resolved=John:${MISSING}" );
253+ }
254+
255+ private Map <String , String > withDeploymentDefaults (Map <String , String > envVars ) {
256+ var modifiedEnvVars = new HashMap <>(envVars );
257+ EnvUtils .getDeploymentDefaults ().forEach (modifiedEnvVars ::putIfAbsent );
258+
259+ return Map .copyOf (modifiedEnvVars );
260+ }
261+
262+ @ SuperBuilder
263+ private static class TestEnvVarResolver extends EnvVarResolver {
264+
265+ private final String prefix ;
266+
267+ @ Override
268+ public String resolve (String src ) {
269+ return prefix + super .resolve (src );
270+ }
271+ }
201272}
0 commit comments