@@ -120,32 +120,37 @@ def setUp(self):
120120 def test_sub_and_quote (self ):
121121 valid_cases = (
122122 # Empty string
123- ('' , {}, "''" ),
123+ ('' , {}, "''" , [] ),
124124 # No substitutions
125- ('a' , {}, 'a' ),
126- # Unused substitutions
127- ('a' , {'FOO' :'foo' }, 'a' ),
125+ ('a' , {}, 'a' , []),
126+ # Unused builtin substitutions are fine
127+ ('a' , {'FOO' :'foo' }, 'a' , []),
128+ # Unused user substitition (ok here but error in generate_script)
129+ ('a' , {'_FOO' :'_foo' }, 'a' , []),
128130 # Defined builtin substitution
129- ('a$FOOb' , {'FOO' :'foo' }, 'afoob' ),
130- ('a${FOO}b' , {'FOO' :'foo' }, 'afoob' ),
131+ ('a$FOOb' , {'FOO' :'foo' }, 'afoob' , [ 'FOO' ] ),
132+ ('a${FOO}b' , {'FOO' :'foo' }, 'afoob' , [ 'FOO' ] ),
131133 # Undefined builtin substitution
132- ('a$FOOb' , {}, 'ab' ),
133- ('a${FOO}b' , {}, 'ab' ),
134+ ('a$FOOb' , {}, 'ab' , [ 'FOO' ] ),
135+ ('a${FOO}b' , {}, 'ab' , [ 'FOO' ] ),
134136 # Defined user substitution
135- ('a$_FOOb' , {'_FOO' :'_foo' }, 'a_foob' ),
136- ('a${_FOO}b' , {'_FOO' :'_foo' }, 'a_foob' ),
137+ ('a$_FOOb' , {'_FOO' :'_foo' }, 'a_foob' , [ '_FOO' ] ),
138+ ('a${_FOO}b' , {'_FOO' :'_foo' }, 'a_foob' , [ '_FOO' ] ),
137139 # Multiple substitutions
138- ('$FOO${FOO}${BAR}$FOO' , {'FOO' :'foo' , 'BAR' :'bar' }, 'foofoobarfoo' ),
140+ ('$FOO${FOO}${BAR}$FOO' , {'FOO' :'foo' , 'BAR' :'bar' },
141+ 'foofoobarfoo' , ['FOO' , 'BAR' ]),
139142 # Invalid names
140- ('a $ b' , {}, "'a $ b'" ),
141- ('a$foo b' , {}, "'a$foo b'" ),
142- ('a$0FOO b' , {}, "'a$0FOO b'" ),
143+ ('a $ b' , {}, "'a $ b'" , [] ),
144+ ('a$foo b' , {}, "'a$foo b'" , [] ),
145+ ('a$0FOO b' , {}, "'a$0FOO b'" , [] ),
143146 )
144147 for valid_case in valid_cases :
145148 with self .subTest (valid_case = valid_case ):
146- s , subs , expected = valid_case
147- actual = local_cloudbuild .sub_and_quote (s , subs )
149+ s , subs , expected , expected_used = valid_case
150+ used = set ()
151+ actual = local_cloudbuild .sub_and_quote (s , subs , used )
148152 self .assertEqual (actual , expected )
153+ self .assertEqual (used , set (expected_used ))
149154
150155 invalid_cases = (
151156 # Undefined user substitution
@@ -156,7 +161,8 @@ def test_sub_and_quote(self):
156161 with self .subTest (invalid_case = invalid_case ):
157162 s , subs = invalid_case
158163 with self .assertRaises (ValueError ):
159- local_cloudbuild .sub_and_quote (s , subs )
164+ used = set ()
165+ local_cloudbuild .sub_and_quote (s , subs , used )
160166
161167 def test_get_cloudbuild (self ):
162168 args = argparse .Namespace (
@@ -237,7 +243,7 @@ def test_generate_command(self):
237243 name = 'aname' ,
238244 )
239245 subs = {'BUILTIN' :'builtin' , '_USER' :'_user' }
240- command = local_cloudbuild .generate_command (base_step , subs )
246+ command = local_cloudbuild .generate_command (base_step , subs , set () )
241247 self .assertEqual (command , [
242248 'docker' ,
243249 'run' ,
@@ -260,49 +266,49 @@ def test_generate_command(self):
260266
261267 # dir specified
262268 step = base_step ._replace (dir_ = 'adir' )
263- command = local_cloudbuild .generate_command (step , subs )
269+ command = local_cloudbuild .generate_command (step , subs , set () )
264270 self .assertIn ('--workdir' , command )
265271 self .assertIn ('/workspace/adir' , command )
266272
267273 # Shell quoting
268274 step = base_step ._replace (args = ['arg with \n newline' ])
269- command = local_cloudbuild .generate_command (step , subs )
275+ command = local_cloudbuild .generate_command (step , subs , set () )
270276 self .assertIn ("'arg with \n newline'" , command )
271277
272278 step = base_step ._replace (dir_ = 'dir/ with space/' )
273- command = local_cloudbuild .generate_command (step , subs )
279+ command = local_cloudbuild .generate_command (step , subs , set () )
274280 self .assertIn ("/workspace/'dir/ with space/'" , command )
275281
276282 step = base_step ._replace (env = ['env with space' ])
277- command = local_cloudbuild .generate_command (step , subs )
283+ command = local_cloudbuild .generate_command (step , subs , set () )
278284 self .assertIn ("'env with space'" , command )
279285
280286 step = base_step ._replace (name = 'a name' )
281- command = local_cloudbuild .generate_command (step , subs )
287+ command = local_cloudbuild .generate_command (step , subs , set () )
282288 self .assertIn ("'a name'" , command )
283289
284290 # Variable substitution
285291 step = base_step ._replace (name = 'a $BUILTIN substitution' )
286- command = local_cloudbuild .generate_command (step , subs )
292+ command = local_cloudbuild .generate_command (step , subs , set () )
287293 self .assertIn ("'a builtin substitution'" , command )
288294
289295 step = base_step ._replace (name = 'a $UNSET_BUILTIN substitution' )
290- command = local_cloudbuild .generate_command (step , subs )
296+ command = local_cloudbuild .generate_command (step , subs , set () )
291297 self .assertIn ("'a substitution'" , command )
292298
293299 step = base_step ._replace (name = 'a $_USER substitution' )
294- command = local_cloudbuild .generate_command (step , subs )
300+ command = local_cloudbuild .generate_command (step , subs , set () )
295301 self .assertIn ("'a _user substitution'" , command )
296302
297303 step = base_step ._replace (name = 'a $_UNSET_USER substitution' )
298304 with self .assertRaises (ValueError ):
299- local_cloudbuild .generate_command (step , subs )
305+ local_cloudbuild .generate_command (step , subs , set () )
300306
301307 step = base_step ._replace (name = 'a curly brace ${BUILTIN} substitution' )
302- command = local_cloudbuild .generate_command (step , subs )
308+ command = local_cloudbuild .generate_command (step , subs , set () )
303309 self .assertIn ("'a curly brace builtin substitution'" , command )
304310
305- def test_generate_script (self ):
311+ def test_generate_script_golden (self ):
306312 config_name = 'cloudbuild_ok.yaml'
307313 config = os .path .join (self .testdata_dir , config_name )
308314 expected_output_script = os .path .join (self .testdata_dir , config_name + '_golden.sh' )
@@ -331,6 +337,16 @@ def test_generate_script(self):
331337 with open (expected_output_script , 'r' , encoding = 'utf8' ) as expected :
332338 self .assertEqual (actual , expected .read ())
333339
340+ def test_generate_script_unused_user_substitution (self ):
341+ cloudbuild = local_cloudbuild .CloudBuild (
342+ output_script = '' ,
343+ run = False ,
344+ steps = [],
345+ substitutions = {'_FOO' :'_foo' },
346+ )
347+ with self .assertRaisesRegexp (ValueError , 'User substitution variables' ):
348+ actual = local_cloudbuild .generate_script (cloudbuild )
349+
334350 def test_make_executable (self ):
335351 with tempfile .TemporaryDirectory (
336352 prefix = 'local_cloudbuild_test_' ) as tempdir :
0 commit comments