@@ -1397,3 +1397,222 @@ func TestGetFullName(t *testing.T) {
13971397 })
13981398 }
13991399}
1400+
1401+ // validatorConfig is a test config that implements Validate() for testing validation behavior
1402+ type validatorConfig struct {
1403+ Value int `json:"value"`
1404+ }
1405+
1406+ func (v * validatorConfig ) Validate () error {
1407+ if v .Value < 10 {
1408+ return errors .New ("value must be >= 10" )
1409+ }
1410+ return nil
1411+ }
1412+
1413+ // TestLoadValidation_WithoutEnv tests that validation is called correctly in normal loading path
1414+ func TestLoadValidation_WithoutEnv (t * testing.T ) {
1415+ tests := []struct {
1416+ name string
1417+ extension string
1418+ content string
1419+ wantErr bool
1420+ errMsg string
1421+ }{
1422+ {
1423+ name : "json valid value" ,
1424+ extension : ".json" ,
1425+ content : `{"value": 15}` ,
1426+ wantErr : false ,
1427+ },
1428+ {
1429+ name : "json invalid value" ,
1430+ extension : ".json" ,
1431+ content : `{"value": 5}` ,
1432+ wantErr : true ,
1433+ errMsg : "value must be >= 10" ,
1434+ },
1435+ {
1436+ name : "yaml valid value" ,
1437+ extension : ".yaml" ,
1438+ content : "value: 20\n " ,
1439+ wantErr : false ,
1440+ },
1441+ {
1442+ name : "yaml invalid value" ,
1443+ extension : ".yaml" ,
1444+ content : "value: 3\n " ,
1445+ wantErr : true ,
1446+ errMsg : "value must be >= 10" ,
1447+ },
1448+ {
1449+ name : "toml valid value" ,
1450+ extension : ".toml" ,
1451+ content : "value = 100\n " ,
1452+ wantErr : false ,
1453+ },
1454+ {
1455+ name : "toml invalid value" ,
1456+ extension : ".toml" ,
1457+ content : "value = 1\n " ,
1458+ wantErr : true ,
1459+ errMsg : "value must be >= 10" ,
1460+ },
1461+ }
1462+
1463+ for _ , tt := range tests {
1464+ t .Run (tt .name , func (t * testing.T ) {
1465+ tmpfile , err := createTempFile (t , tt .extension , tt .content )
1466+ assert .Nil (t , err )
1467+
1468+ var cfg validatorConfig
1469+ err = Load (tmpfile , & cfg )
1470+
1471+ if tt .wantErr {
1472+ assert .Error (t , err )
1473+ assert .Contains (t , err .Error (), tt .errMsg )
1474+ } else {
1475+ assert .NoError (t , err )
1476+ }
1477+ })
1478+ }
1479+ }
1480+
1481+ // TestLoadValidation_WithEnv tests that validation is called correctly with UseEnv() option
1482+ func TestLoadValidation_WithEnv (t * testing.T ) {
1483+ tests := []struct {
1484+ name string
1485+ extension string
1486+ content string
1487+ envValue string
1488+ wantErr bool
1489+ errMsg string
1490+ }{
1491+ {
1492+ name : "json valid value with env" ,
1493+ extension : ".json" ,
1494+ content : `{"value": ${TEST_VALUE}}` ,
1495+ envValue : "25" ,
1496+ wantErr : false ,
1497+ },
1498+ {
1499+ name : "json invalid value with env" ,
1500+ extension : ".json" ,
1501+ content : `{"value": ${TEST_VALUE}}` ,
1502+ envValue : "7" ,
1503+ wantErr : true ,
1504+ errMsg : "value must be >= 10" ,
1505+ },
1506+ {
1507+ name : "yaml valid value with env" ,
1508+ extension : ".yaml" ,
1509+ content : "value: ${TEST_VALUE}\n " ,
1510+ envValue : "50" ,
1511+ wantErr : false ,
1512+ },
1513+ {
1514+ name : "yaml invalid value with env" ,
1515+ extension : ".yaml" ,
1516+ content : "value: ${TEST_VALUE}\n " ,
1517+ envValue : "2" ,
1518+ wantErr : true ,
1519+ errMsg : "value must be >= 10" ,
1520+ },
1521+ {
1522+ name : "toml valid value with env" ,
1523+ extension : ".toml" ,
1524+ content : "value = ${TEST_VALUE}\n " ,
1525+ envValue : "99" ,
1526+ wantErr : false ,
1527+ },
1528+ {
1529+ name : "toml invalid value with env" ,
1530+ extension : ".toml" ,
1531+ content : "value = ${TEST_VALUE}\n " ,
1532+ envValue : "8" ,
1533+ wantErr : true ,
1534+ errMsg : "value must be >= 10" ,
1535+ },
1536+ }
1537+
1538+ for _ , tt := range tests {
1539+ t .Run (tt .name , func (t * testing.T ) {
1540+ t .Setenv ("TEST_VALUE" , tt .envValue )
1541+
1542+ tmpfile , err := createTempFile (t , tt .extension , tt .content )
1543+ assert .Nil (t , err )
1544+
1545+ var cfg validatorConfig
1546+ err = Load (tmpfile , & cfg , UseEnv ())
1547+
1548+ if tt .wantErr {
1549+ assert .Error (t , err )
1550+ assert .Contains (t , err .Error (), tt .errMsg )
1551+ } else {
1552+ assert .NoError (t , err )
1553+ }
1554+ })
1555+ }
1556+ }
1557+
1558+ // TestLoadValidation_Consistency verifies validation behavior is consistent between paths
1559+ func TestLoadValidation_Consistency (t * testing.T ) {
1560+ // Test that both paths (with and without UseEnv) produce the same validation results
1561+ const validValue = 15
1562+
1563+ formats := []struct {
1564+ ext string
1565+ invalid string
1566+ valid string
1567+ }{
1568+ {".json" , `{"value": 5}` , `{"value": 15}` },
1569+ {".yaml" , "value: 5\n " , "value: 15\n " },
1570+ {".toml" , "value = 5\n " , "value = 15\n " },
1571+ }
1572+
1573+ for _ , format := range formats {
1574+ t .Run ("invalid_" + format .ext , func (t * testing.T ) {
1575+ // Test without UseEnv()
1576+ tmpfile1 , err := createTempFile (t , format .ext , format .invalid )
1577+ assert .Nil (t , err )
1578+
1579+ var cfg1 validatorConfig
1580+ err1 := Load (tmpfile1 , & cfg1 )
1581+
1582+ // Test with UseEnv()
1583+ tmpfile2 , err := createTempFile (t , format .ext , format .invalid )
1584+ assert .Nil (t , err )
1585+
1586+ var cfg2 validatorConfig
1587+ err2 := Load (tmpfile2 , & cfg2 , UseEnv ())
1588+
1589+ // Both should fail validation
1590+ assert .Error (t , err1 , "validation should fail without UseEnv()" )
1591+ assert .Error (t , err2 , "validation should fail with UseEnv()" )
1592+ assert .Contains (t , err1 .Error (), "value must be >= 10" )
1593+ assert .Contains (t , err2 .Error (), "value must be >= 10" )
1594+ })
1595+
1596+ t .Run ("valid_" + format .ext , func (t * testing.T ) {
1597+ // Test without UseEnv()
1598+ tmpfile1 , err := createTempFile (t , format .ext , format .valid )
1599+ assert .Nil (t , err )
1600+
1601+ var cfg1 validatorConfig
1602+ err1 := Load (tmpfile1 , & cfg1 )
1603+
1604+ // Test with UseEnv()
1605+ tmpfile2 , err := createTempFile (t , format .ext , format .valid )
1606+ assert .Nil (t , err )
1607+
1608+ var cfg2 validatorConfig
1609+ err2 := Load (tmpfile2 , & cfg2 , UseEnv ())
1610+
1611+ // Both should pass validation
1612+ assert .NoError (t , err1 , "validation should pass without UseEnv()" )
1613+ assert .NoError (t , err2 , "validation should pass with UseEnv()" )
1614+ assert .Equal (t , validValue , cfg1 .Value )
1615+ assert .Equal (t , validValue , cfg2 .Value )
1616+ })
1617+ }
1618+ }
0 commit comments