@@ -285,279 +285,3 @@ def test_lint_invalid_template(self):
285285
286286 self .assertIn (warning_message , output )
287287 self .assertEqual (command_result .process .returncode , 1 )
288-
289- def test_validate_language_extensions_valid_foreach (self ):
290- """
291- Test that sam validate passes for valid Fn::ForEach syntax.
292-
293- Validates: Requirements 7.1, 12.3
294- - 7.1: WHEN `sam validate` processes a template with valid `Fn::ForEach` syntax,
295- THE Validate_Command SHALL report the template as valid
296- - 12.3: THE Integration_Tests SHALL verify `sam validate` correctly validates
297- templates with language extensions
298- """
299- test_data_path = (
300- Path (__file__ ).resolve ().parents [2 ] / "integration" / "testdata" / "validate" / "language-extensions"
301- )
302- template_file = "valid-foreach.yaml"
303- template_path = test_data_path / template_file
304-
305- command_result = run_command (self .command_list (template_file = template_path ))
306- output = command_result .stdout .decode ("utf-8" )
307-
308- # Verify the command succeeds (exit code 0)
309- self .assertEqual (
310- command_result .process .returncode ,
311- 0 ,
312- f"Expected exit code 0 but got { command_result .process .returncode } . Output: { output } " ,
313- )
314-
315- # Verify the output indicates the template is valid
316- # The output should contain a message indicating the template is valid
317- valid_pattern = re .compile (
318- r"valid-foreach\.yaml is a valid SAM Template\. This is according to basic SAM Validation, "
319- 'for additional validation, please run with "--lint" option(\r \n )?$'
320- )
321- self .assertRegex (
322- output ,
323- valid_pattern ,
324- f"Expected output to indicate template is valid. Actual output: { output } " ,
325- )
326-
327- def test_validate_language_extensions_invalid_foreach (self ):
328- """
329- Test that sam validate fails with clear error message for invalid Fn::ForEach syntax.
330-
331- Validates: Requirements 7.2, 12.4
332- - 7.2: WHEN `sam validate` processes a template with invalid `Fn::ForEach` syntax
333- (e.g., wrong number of arguments), THE Validate_Command SHALL report a
334- clear error message
335- - 12.4: THE Integration_Tests SHALL verify `sam validate` reports errors for
336- invalid language extension syntax
337- """
338- test_data_path = (
339- Path (__file__ ).resolve ().parents [2 ] / "integration" / "testdata" / "validate" / "language-extensions"
340- )
341- template_file = "invalid-foreach.yaml"
342- template_path = test_data_path / template_file
343-
344- command_result = run_command (self .command_list (template_file = template_path ))
345- # Combine stdout and stderr for error message checking
346- stdout_output = command_result .stdout .decode ("utf-8" )
347- stderr_output = command_result .stderr .decode ("utf-8" )
348- combined_output = stdout_output + stderr_output
349-
350- # Verify the command fails (non-zero exit code)
351- self .assertNotEqual (
352- command_result .process .returncode ,
353- 0 ,
354- f"Expected non-zero exit code but got { command_result .process .returncode } . Output: { combined_output } " ,
355- )
356-
357- # Verify the output contains the specific error about invalid ForEach layout
358- self .assertIn (
359- "layout is incorrect" ,
360- combined_output ,
361- f"Expected 'layout is incorrect' error for invalid Fn::ForEach syntax. Actual output: { combined_output } " ,
362- )
363-
364- def test_validate_language_extensions_valid_dynamic_codeuri (self ):
365- """
366- Test that sam validate passes for valid Fn::ForEach with dynamic CodeUri.
367-
368- Validates: Requirements 4.1, 10.1
369- - 4.1: Dynamic artifact properties (e.g., CodeUri: ./${Name}) are supported
370- - 10.1: sam validate should pass for valid templates with dynamic CodeUri
371- """
372- test_data_path = (
373- Path (__file__ ).resolve ().parents [2 ] / "integration" / "testdata" / "validate" / "language-extensions"
374- )
375- template_file = "valid-dynamic-codeuri.yaml"
376- template_path = test_data_path / template_file
377-
378- command_result = run_command (self .command_list (template_file = template_path ))
379- output = command_result .stdout .decode ("utf-8" )
380-
381- # Verify the command succeeds (exit code 0)
382- self .assertEqual (
383- command_result .process .returncode ,
384- 0 ,
385- f"Expected exit code 0 but got { command_result .process .returncode } . Output: { output } " ,
386- )
387-
388- # Verify the output indicates the template is valid
389- valid_pattern = re .compile (
390- r"valid-dynamic-codeuri\.yaml is a valid SAM Template\. This is according to basic SAM Validation, "
391- 'for additional validation, please run with "--lint" option(\r \n )?$'
392- )
393- self .assertRegex (
394- output ,
395- valid_pattern ,
396- f"Expected output to indicate template is valid. Actual output: { output } " ,
397- )
398-
399- def test_validate_language_extensions_cloud_dependent_collection (self ):
400- """
401- Test that sam validate fails with clear error for cloud-dependent collection.
402-
403- Validates: Requirements 5.1, 5.4, 5.5
404- - 5.1: Fn::GetAtt in collection should raise error with clear message
405- - 5.4: Error message should include which Fn::ForEach block has the issue
406- - 5.5: Error message should suggest using parameter with --parameter-overrides
407- """
408- test_data_path = (
409- Path (__file__ ).resolve ().parents [2 ] / "integration" / "testdata" / "validate" / "language-extensions"
410- )
411- template_file = "cloud-dependent-collection.yaml"
412- template_path = test_data_path / template_file
413-
414- command_result = run_command (self .command_list (template_file = template_path ))
415- # Combine stdout and stderr for error message checking
416- stdout_output = command_result .stdout .decode ("utf-8" )
417- stderr_output = command_result .stderr .decode ("utf-8" )
418- combined_output = stdout_output + stderr_output
419-
420- # Verify the command fails (non-zero exit code)
421- self .assertNotEqual (
422- command_result .process .returncode ,
423- 0 ,
424- f"Expected non-zero exit code but got { command_result .process .returncode } . Output: { combined_output } " ,
425- )
426-
427- # Verify the output contains the specific error about unresolvable collection
428- self .assertIn (
429- "Unable to resolve Fn::ForEach collection locally" ,
430- combined_output ,
431- f"Expected 'Unable to resolve Fn::ForEach collection locally' error. Actual output: { combined_output } " ,
432- )
433-
434- def test_validate_language_extensions_missing_dynamic_artifact_dir (self ):
435- """
436- Test that sam validate handles templates with dynamic CodeUri pointing to non-existent directories.
437-
438- Validates: Requirements 4.1
439- - 4.1: Dynamic artifact properties should be validated
440-
441- Note: sam validate performs basic SAM validation which may not check if directories exist.
442- This test verifies the behavior when dynamic CodeUri points to non-existent directories.
443- """
444- test_data_path = (
445- Path (__file__ ).resolve ().parents [2 ] / "integration" / "testdata" / "validate" / "language-extensions"
446- )
447- template_file = "missing-dynamic-artifact-dir.yaml"
448- template_path = test_data_path / template_file
449-
450- command_result = run_command (self .command_list (template_file = template_path ))
451- stdout_output = command_result .stdout .decode ("utf-8" )
452- stderr_output = command_result .stderr .decode ("utf-8" )
453- combined_output = stdout_output + stderr_output
454-
455- # sam validate performs basic SAM template validation only — it does not check
456- # whether artifact directories exist on disk. Directory validation happens at
457- # build time. The template is syntactically valid, so validate should pass.
458- self .assertEqual (
459- command_result .process .returncode ,
460- 0 ,
461- f"sam validate should pass for syntactically valid template (directory checks happen at build time). "
462- f"Output: { combined_output } " ,
463- )
464-
465- def test_validate_language_extensions_nested_foreach_valid_depth_5 (self ):
466- """
467- Test that sam validate passes for templates with 5 levels of nested Fn::ForEach.
468-
469- Validates: Requirements 18.2, 18.6
470- - 18.2: WHEN a template contains 5 or fewer levels of nested Fn::ForEach loops,
471- THE SAM_CLI SHALL process the template successfully
472- - 18.6: WHEN `sam validate` processes a template exceeding the nested loop limit,
473- THE Validate_Command SHALL report the nesting depth error
474- """
475- test_data_path = (
476- Path (__file__ ).resolve ().parents [2 ]
477- / "integration"
478- / "testdata"
479- / "buildcmd"
480- / "language-extensions-nested-foreach-valid"
481- )
482- template_file = "template.yaml"
483- template_path = test_data_path / template_file
484-
485- command_result = run_command (self .command_list (template_file = template_path ))
486- output = command_result .stdout .decode ("utf-8" )
487-
488- # Verify the command succeeds (exit code 0)
489- self .assertEqual (
490- command_result .process .returncode ,
491- 0 ,
492- f"Expected exit code 0 but got { command_result .process .returncode } . Output: { output } " ,
493- )
494-
495- # Verify the output indicates the template is valid
496- valid_pattern = re .compile (
497- r"template\.yaml is a valid SAM Template\. This is according to basic SAM Validation, "
498- 'for additional validation, please run with "--lint" option(\r \n )?$'
499- )
500- self .assertRegex (
501- output ,
502- valid_pattern ,
503- f"Expected output to indicate template is valid. Actual output: { output } " ,
504- )
505-
506- def test_validate_language_extensions_nested_foreach_invalid_depth_6 (self ):
507- """
508- Test that sam validate fails for templates with 6 levels of nested Fn::ForEach.
509-
510- Validates: Requirements 18.3, 18.4, 18.5, 18.6
511- - 18.3: WHEN a template contains more than 5 levels of nested Fn::ForEach loops,
512- THE SAM_CLI SHALL raise an error before processing
513- - 18.4: WHEN the nested loop limit is exceeded, THE error message SHALL clearly
514- indicate that the maximum nesting depth of 5 has been exceeded
515- - 18.5: WHEN the nested loop limit is exceeded, THE error message SHALL indicate
516- the actual nesting depth found in the template
517- - 18.6: WHEN `sam validate` processes a template exceeding the nested loop limit,
518- THE Validate_Command SHALL report the nesting depth error
519- """
520- test_data_path = (
521- Path (__file__ ).resolve ().parents [2 ]
522- / "integration"
523- / "testdata"
524- / "buildcmd"
525- / "language-extensions-nested-foreach-invalid"
526- )
527- template_file = "template.yaml"
528- template_path = test_data_path / template_file
529-
530- command_result = run_command (self .command_list (template_file = template_path ))
531- # Combine stdout and stderr for error message checking
532- stdout_output = command_result .stdout .decode ("utf-8" )
533- stderr_output = command_result .stderr .decode ("utf-8" )
534- combined_output = stdout_output + stderr_output
535-
536- # Verify the command fails (non-zero exit code)
537- self .assertNotEqual (
538- command_result .process .returncode ,
539- 0 ,
540- f"Expected non-zero exit code but got { command_result .process .returncode } . Output: { combined_output } " ,
541- )
542-
543- # Requirement 18.4: Error message indicates maximum nesting depth of 5
544- self .assertIn (
545- "5" ,
546- combined_output ,
547- f"Expected error message to mention maximum depth of 5. Actual output: { combined_output } " ,
548- )
549-
550- # Requirement 18.5: Error message indicates actual nesting depth found (6)
551- self .assertIn (
552- "6" ,
553- combined_output ,
554- f"Expected error message to mention actual depth of 6. Actual output: { combined_output } " ,
555- )
556-
557- # Verify the error message mentions nesting or depth
558- nesting_indicators = ["nesting" , "depth" , "exceeds" , "maximum" , "nested" ]
559- has_nesting_indicator = any (indicator .lower () in combined_output .lower () for indicator in nesting_indicators )
560- self .assertTrue (
561- has_nesting_indicator ,
562- f"Expected error message about nesting depth. Actual output: { combined_output } " ,
563- )
0 commit comments