@@ -1401,3 +1401,127 @@ func TestConstraintCheck(t *testing.T) {
14011401 })
14021402 }
14031403}
1404+
1405+ // TestStartsWithArityRegression: startswith with wrong arity must return WrongNumberOfParamsError, not panic.
1406+ func TestStartsWithArityRegression (t * testing.T ) {
1407+ t .Parallel ()
1408+
1409+ testCases := []struct {
1410+ name string
1411+ args []string
1412+ }{
1413+ {name : "no args" , args : []string {}},
1414+ {name : "one arg (the bug trigger)" , args : []string {"foo" }},
1415+ {name : "three args" , args : []string {"foo" , "bar" , "baz" }},
1416+ }
1417+
1418+ for _ , tc := range testCases {
1419+ t .Run (tc .name , func (t * testing.T ) {
1420+ t .Parallel ()
1421+
1422+ ctx , pctx := newTestParsingContext (t , "" )
1423+
1424+ require .NotPanics (t , func () {
1425+ _ , err := config .StartsWith (ctx , pctx , tc .args )
1426+ require .Error (t , err , "must return error for wrong arity (%d args)" , len (tc .args ))
1427+ require .True (t , assertErrorType (t , config.WrongNumberOfParamsError {}, err ),
1428+ "expected WrongNumberOfParamsError, got %T: %v" , err , err )
1429+ }, "startswith with %d args must not panic" , len (tc .args ))
1430+ })
1431+ }
1432+ }
1433+
1434+ // TestEndsWithArityRegression: endswith with wrong arity must return WrongNumberOfParamsError, not panic.
1435+ func TestEndsWithArityRegression (t * testing.T ) {
1436+ t .Parallel ()
1437+
1438+ testCases := []struct {
1439+ name string
1440+ args []string
1441+ }{
1442+ {name : "no args" , args : []string {}},
1443+ {name : "one arg (the bug trigger)" , args : []string {"foo" }},
1444+ {name : "three args" , args : []string {"foo" , "bar" , "baz" }},
1445+ }
1446+
1447+ for _ , tc := range testCases {
1448+ t .Run (tc .name , func (t * testing.T ) {
1449+ t .Parallel ()
1450+
1451+ ctx , pctx := newTestParsingContext (t , "" )
1452+
1453+ require .NotPanics (t , func () {
1454+ _ , err := config .EndsWith (ctx , pctx , tc .args )
1455+ require .Error (t , err , "must return error for wrong arity (%d args)" , len (tc .args ))
1456+ require .True (t , assertErrorType (t , config.WrongNumberOfParamsError {}, err ),
1457+ "expected WrongNumberOfParamsError, got %T: %v" , err , err )
1458+ }, "endswith with %d args must not panic" , len (tc .args ))
1459+ })
1460+ }
1461+ }
1462+
1463+ // TestStrContainsArityRegression: strcontains with wrong arity must return WrongNumberOfParamsError, not panic.
1464+ func TestStrContainsArityRegression (t * testing.T ) {
1465+ t .Parallel ()
1466+
1467+ testCases := []struct {
1468+ name string
1469+ args []string
1470+ }{
1471+ {name : "no args" , args : []string {}},
1472+ {name : "one arg (the bug trigger)" , args : []string {"hello" }},
1473+ {name : "three args" , args : []string {"hello" , "world" , "extra" }},
1474+ }
1475+
1476+ for _ , tc := range testCases {
1477+ t .Run (tc .name , func (t * testing.T ) {
1478+ t .Parallel ()
1479+
1480+ ctx , pctx := newTestParsingContext (t , "" )
1481+
1482+ require .NotPanics (t , func () {
1483+ _ , err := config .StrContains (ctx , pctx , tc .args )
1484+ require .Error (t , err , "must return error for wrong arity (%d args)" , len (tc .args ))
1485+ require .True (t , assertErrorType (t , config.WrongNumberOfParamsError {}, err ),
1486+ "expected WrongNumberOfParamsError, got %T: %v" , err , err )
1487+ }, "strcontains with %d args must not panic" , len (tc .args ))
1488+ })
1489+ }
1490+ }
1491+
1492+ // TestRunCommandOptionsOnlyArityRegression: run_cmd with only option flags must return EmptyStringNotAllowedError, not panic.
1493+ func TestRunCommandOptionsOnlyArityRegression (t * testing.T ) {
1494+ t .Parallel ()
1495+
1496+ if runtime .GOOS == "windows" {
1497+ t .Skip ("Skipping test on Windows because it doesn't support bash" )
1498+ }
1499+
1500+ testCases := []struct {
1501+ name string
1502+ params []string
1503+ }{
1504+ {name : "single quiet flag" , params : []string {"--terragrunt-quiet" }},
1505+ {name : "single no-cache flag" , params : []string {"--terragrunt-no-cache" }},
1506+ {name : "single global-cache flag" , params : []string {"--terragrunt-global-cache" }},
1507+ {name : "two compatible flags" , params : []string {"--terragrunt-quiet" , "--terragrunt-no-cache" }},
1508+ {name : "two compatible flags reversed" , params : []string {"--terragrunt-no-cache" , "--terragrunt-quiet" }},
1509+ {name : "duplicate quiet" , params : []string {"--terragrunt-quiet" , "--terragrunt-quiet" }},
1510+ }
1511+
1512+ for _ , tc := range testCases {
1513+ t .Run (tc .name , func (t * testing.T ) {
1514+ t .Parallel ()
1515+
1516+ l := logger .CreateLogger ()
1517+ ctx , pctx := newTestParsingContext (t , "" )
1518+
1519+ require .NotPanics (t , func () {
1520+ _ , err := config .RunCommand (ctx , pctx , l , tc .params )
1521+ require .Error (t , err , "must return error when only option flags are supplied (%v)" , tc .params )
1522+ require .True (t , assertErrorType (t , config .EmptyStringNotAllowedError ("" ), err ),
1523+ "expected EmptyStringNotAllowedError, got %T: %v" , err , err )
1524+ }, "run_cmd with options-only %v must not panic" , tc .params )
1525+ })
1526+ }
1527+ }
0 commit comments