Skip to content

Commit f59f391

Browse files
authored
fix(goelements): handle Hex default int/uint values (#827)
* fix(goelements): handle Hex default int/uint values * fix(goelements): handle Hex default int/uint values * fix(gogen): fix hex/octal default value handling for int/uint .. and add test cases for hex/octal default int/uint values. The Go standard library already handles base inference for hexadecimal, octal, binary, and base-10, with sign prefix support. There's no need to reimplement the parsing and conversion of these integer values. According to https://datatracker.ietf.org/doc/html/rfc7950#section-9.2.1 one remaining question is, should the `yangDefaultValueToGo` function return an error if the default value for an integer is in binary format? * fix(gogen): make sure that base 2 default int/uint values are disallowed * fix(gogen): make sure that underscores are disallowed in default values * fix(gogen): handle default int/uint negative case with a sign prefix * fix(gogen): correct a typo on trimming the default value string The tests didn't catch this typo because `ParseUint` returned an error on the sign prefix. But this should be fixed and the expected error should be `binary format is disallowed`. * fix(gogen): fix typos in the default value parsing test cases
1 parent 97fb230 commit f59f391

File tree

2 files changed

+318
-2
lines changed

2 files changed

+318
-2
lines changed

gogen/goelements.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -642,16 +642,40 @@ func (s *GoLangMapper) yangDefaultValueToGo(value string, args resolveTypeArgs,
642642
if err != nil {
643643
return "", yang.Ynone, err
644644
}
645+
646+
// Check if the value is an empty string.
647+
signStripedValue := strings.TrimLeft(strings.TrimLeft(value, "-"), "+")
648+
if len(signStripedValue) == 0 {
649+
return "", yang.Ynone, fmt.Errorf("default value conversion: empty value")
650+
}
651+
652+
// When the default value of int/uint is not base-10, check if the base should be supported according to
653+
// https://datatracker.ietf.org/doc/html/rfc7950#section-9.2.1
654+
//
655+
// When the first character in the value is `0`, the value could be hexadecimal, octal or binary. While hexadecimal
656+
// and octal values are supported (with an optional sign prefix), binary is not allowed by the RFC. The format support
657+
// of `strconv.ParseInt/ParseUint` functions should be further constrained.
658+
if signStripedValue[0] == '0' {
659+
if len(signStripedValue) > 1 && (signStripedValue[1] == 'b' || signStripedValue[1] == 'B') {
660+
return "", yang.Ynone, fmt.Errorf("default value conversion: base 2 value `%s` is not allowed", value)
661+
}
662+
}
663+
664+
// Underscores are not allowed in the value, although `strconv` allows them in certain formats.
665+
if strings.Contains(value, "_") {
666+
return "", yang.Ynone, fmt.Errorf("default value conversion: `_` is not allowed in the value %s", value)
667+
}
668+
645669
if signed {
646-
val, err := strconv.ParseInt(value, 10, bits)
670+
val, err := strconv.ParseInt(value, 0, bits)
647671
if err != nil {
648672
return "", yang.Ynone, fmt.Errorf("default value conversion: unable to convert default value %q to %v: %v", value, ykind, err)
649673
}
650674
if err := ytypes.ValidateIntRestrictions(args.yangType, val); err != nil {
651675
return "", yang.Ynone, fmt.Errorf("default value conversion: %q doesn't match int restrictions: %v", value, err)
652676
}
653677
} else {
654-
val, err := strconv.ParseUint(value, 10, bits)
678+
val, err := strconv.ParseUint(value, 0, bits)
655679
if err != nil {
656680
return "", yang.Ynone, fmt.Errorf("default value conversion: unable to convert default value %q to %v: %v", value, ykind, err)
657681
}

gogen/goelements_test.go

Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,13 +1577,33 @@ func TestYangDefaultValueToGo(t *testing.T) {
15771577
inType: &yang.YangType{Kind: yang.Yint8},
15781578
inValue: "-129",
15791579
wantErr: true,
1580+
}, {
1581+
name: "int8 (empty value)",
1582+
inType: &yang.YangType{Kind: yang.Yuint8},
1583+
inValue: "",
1584+
wantErr: true,
1585+
}, {
1586+
name: "empty value (only a `+` sign)",
1587+
inType: &yang.YangType{Kind: yang.Yuint8},
1588+
inValue: "+",
1589+
wantErr: true,
1590+
}, {
1591+
name: "empty value (only a `-` sign)",
1592+
inType: &yang.YangType{Kind: yang.Yuint8},
1593+
inValue: "+",
1594+
wantErr: true,
15801595
}, {
15811596
name: "int16",
15821597
inType: &yang.YangType{Kind: yang.Yint16},
15831598
inValue: "-129",
15841599
want: "-129",
15851600
wantKind: yang.Yint16,
15861601
wantUnionName: "UnionInt16(-129)",
1602+
}, {
1603+
name: "int16 (integer literal -- disallowed)",
1604+
inType: &yang.YangType{Kind: yang.Yint16},
1605+
inValue: "10_000",
1606+
wantErr: true,
15871607
}, {
15881608
name: "int32",
15891609
inType: &yang.YangType{Kind: yang.Yint32},
@@ -1633,6 +1653,278 @@ func TestYangDefaultValueToGo(t *testing.T) {
16331653
want: "3.14",
16341654
wantKind: yang.Ydecimal64,
16351655
wantUnionName: "UnionFloat64(3.14)",
1656+
}, {
1657+
name: "int8 (hexadecimal without an optional `+/-` sign)",
1658+
inType: &yang.YangType{Kind: yang.Yint8},
1659+
inValue: "0x42",
1660+
want: "0x42",
1661+
wantKind: yang.Yint8,
1662+
wantUnionName: "UnionInt8(0x42)",
1663+
}, {
1664+
name: "int8 (hexadecimal out of range)",
1665+
inType: &yang.YangType{Kind: yang.Yint8},
1666+
inValue: "0x4242",
1667+
wantErr: true,
1668+
}, {
1669+
name: "int8 (invalid hexadecimal value)",
1670+
inType: &yang.YangType{Kind: yang.Yint8},
1671+
inValue: "0x",
1672+
wantErr: true,
1673+
}, {
1674+
name: "int16 (hexadecimal without an optional `+/-` sign)",
1675+
inType: &yang.YangType{Kind: yang.Yint16},
1676+
inValue: "0x4242",
1677+
want: "0x4242",
1678+
wantKind: yang.Yint16,
1679+
wantUnionName: "UnionInt16(0x4242)",
1680+
}, {
1681+
name: "int32 (hexadecimal without an optional `+/-` sign)",
1682+
inType: &yang.YangType{Kind: yang.Yint32},
1683+
inValue: "0x4242",
1684+
want: "0x4242",
1685+
wantKind: yang.Yint32,
1686+
wantUnionName: "UnionInt32(0x4242)",
1687+
}, {
1688+
name: "int64 (hexadecimal without an optional `+/-` sign)",
1689+
inType: &yang.YangType{Kind: yang.Yint64},
1690+
inValue: "0x4242",
1691+
want: "0x4242",
1692+
wantKind: yang.Yint64,
1693+
wantUnionName: "UnionInt64(0x4242)",
1694+
}, {
1695+
name: "uint8 (hexadecimal without an optional `+/-` sign)",
1696+
inType: &yang.YangType{Kind: yang.Yuint8},
1697+
inValue: "0x42",
1698+
want: "0x42",
1699+
wantKind: yang.Yuint8,
1700+
wantUnionName: "UnionUint8(0x42)",
1701+
}, {
1702+
name: "uint16 (hexadecimal without an optional `+/-` sign)",
1703+
inType: &yang.YangType{Kind: yang.Yuint16},
1704+
inValue: "0x42",
1705+
want: "0x42",
1706+
wantKind: yang.Yuint16,
1707+
wantUnionName: "UnionUint16(0x42)",
1708+
}, {
1709+
name: "uint32 (hexadecimal without an optional `+/-` sign)",
1710+
inType: &yang.YangType{Kind: yang.Yuint32},
1711+
inValue: "0x42",
1712+
want: "0x42",
1713+
wantKind: yang.Yuint32,
1714+
wantUnionName: "UnionUint32(0x42)",
1715+
}, {
1716+
name: "uint64 (hexadecimal without an optional `+/-` sign)",
1717+
inType: &yang.YangType{Kind: yang.Yuint64},
1718+
inValue: "0x42",
1719+
want: "0x42",
1720+
wantKind: yang.Yuint64,
1721+
wantUnionName: "UnionUint64(0x42)",
1722+
}, {
1723+
name: "int8 (hexadecimal with a `+` sign)",
1724+
inType: &yang.YangType{Kind: yang.Yint8},
1725+
inValue: "+0x42",
1726+
want: "+0x42",
1727+
wantKind: yang.Yint8,
1728+
wantUnionName: "UnionInt8(+0x42)",
1729+
}, {
1730+
name: "int8 (hexadecimal with a `-` sign)",
1731+
inType: &yang.YangType{Kind: yang.Yint8},
1732+
inValue: "-0x42",
1733+
want: "-0x42",
1734+
wantKind: yang.Yint8,
1735+
wantUnionName: "UnionInt8(-0x42)",
1736+
}, {
1737+
name: "int16 (hexadecimal with a `+` sign)",
1738+
inType: &yang.YangType{Kind: yang.Yint16},
1739+
inValue: "+0x4242",
1740+
want: "+0x4242",
1741+
wantKind: yang.Yint16,
1742+
wantUnionName: "UnionInt16(+0x4242)",
1743+
}, {
1744+
name: "int16 (hexadecimal with a `-` sign)",
1745+
inType: &yang.YangType{Kind: yang.Yint16},
1746+
inValue: "-0x4242",
1747+
want: "-0x4242",
1748+
wantKind: yang.Yint16,
1749+
wantUnionName: "UnionInt16(-0x4242)",
1750+
}, {
1751+
name: "int32 (hexadecimal with a `+` sign)",
1752+
inType: &yang.YangType{Kind: yang.Yint32},
1753+
inValue: "+0x4242",
1754+
want: "+0x4242",
1755+
wantKind: yang.Yint32,
1756+
wantUnionName: "UnionInt32(+0x4242)",
1757+
}, {
1758+
name: "int32 (hexadecimal with a `-` sign)",
1759+
inType: &yang.YangType{Kind: yang.Yint32},
1760+
inValue: "-0x4242",
1761+
want: "-0x4242",
1762+
wantKind: yang.Yint32,
1763+
wantUnionName: "UnionInt32(-0x4242)",
1764+
}, {
1765+
name: "int64 (hexadecimal with a `+` sign)",
1766+
inType: &yang.YangType{Kind: yang.Yint64},
1767+
inValue: "+0x4242",
1768+
want: "+0x4242",
1769+
wantKind: yang.Yint64,
1770+
wantUnionName: "UnionInt64(+0x4242)",
1771+
}, {
1772+
name: "int64 (hexadecimal with a `-` sign)",
1773+
inType: &yang.YangType{Kind: yang.Yint64},
1774+
inValue: "-0x4242",
1775+
want: "-0x4242",
1776+
wantKind: yang.Yint64,
1777+
wantUnionName: "UnionInt64(-0x4242)",
1778+
}, {
1779+
name: "uint8 (hexadecimal with a `+` sign -- invalid syntax)",
1780+
inType: &yang.YangType{Kind: yang.Yuint8},
1781+
inValue: "+0x42",
1782+
wantErr: true,
1783+
}, {
1784+
name: "uint8 (hexadecimal with a `-` sign -- invalid syntax)",
1785+
inType: &yang.YangType{Kind: yang.Yuint8},
1786+
inValue: "-0x42",
1787+
wantErr: true,
1788+
}, {
1789+
name: "int8 (octal out of range)",
1790+
inType: &yang.YangType{Kind: yang.Yint8},
1791+
inValue: "04242",
1792+
wantErr: true,
1793+
}, {
1794+
name: "int8 (invalid octal value)",
1795+
inType: &yang.YangType{Kind: yang.Yint8},
1796+
inValue: "08",
1797+
wantErr: true,
1798+
}, {
1799+
name: "int16 (octal without an optional `+/-` sign)",
1800+
inType: &yang.YangType{Kind: yang.Yint16},
1801+
inValue: "04242",
1802+
want: "04242",
1803+
wantKind: yang.Yint16,
1804+
wantUnionName: "UnionInt16(04242)",
1805+
}, {
1806+
name: "int32 (octal without an optional `+/-` sign)",
1807+
inType: &yang.YangType{Kind: yang.Yint32},
1808+
inValue: "04242",
1809+
want: "04242",
1810+
wantKind: yang.Yint32,
1811+
wantUnionName: "UnionInt32(04242)",
1812+
}, {
1813+
name: "int64 (octal without an optional `+/-` sign)",
1814+
inType: &yang.YangType{Kind: yang.Yint64},
1815+
inValue: "04242",
1816+
want: "04242",
1817+
wantKind: yang.Yint64,
1818+
wantUnionName: "UnionInt64(04242)",
1819+
}, {
1820+
name: "uint8 (octal without an optional `+/-` sign)",
1821+
inType: &yang.YangType{Kind: yang.Yuint8},
1822+
inValue: "042",
1823+
want: "042",
1824+
wantKind: yang.Yuint8,
1825+
wantUnionName: "UnionUint8(042)",
1826+
}, {
1827+
name: "uint16 (octal without an optional `+/-` sign)",
1828+
inType: &yang.YangType{Kind: yang.Yuint16},
1829+
inValue: "042",
1830+
want: "042",
1831+
wantKind: yang.Yuint16,
1832+
wantUnionName: "UnionUint16(042)",
1833+
}, {
1834+
name: "uint32 (octal without an optional `+/-` sign)",
1835+
inType: &yang.YangType{Kind: yang.Yuint32},
1836+
inValue: "042",
1837+
want: "042",
1838+
wantKind: yang.Yuint32,
1839+
wantUnionName: "UnionUint32(042)",
1840+
}, {
1841+
name: "uint64 (octal without an optional `+/-` sign)",
1842+
inType: &yang.YangType{Kind: yang.Yuint64},
1843+
inValue: "042",
1844+
want: "042",
1845+
wantKind: yang.Yuint64,
1846+
wantUnionName: "UnionUint64(042)",
1847+
}, {
1848+
name: "int8 (octal with a `+` sign)",
1849+
inType: &yang.YangType{Kind: yang.Yint8},
1850+
inValue: "+042",
1851+
want: "+042",
1852+
wantKind: yang.Yint8,
1853+
wantUnionName: "UnionInt8(+042)",
1854+
}, {
1855+
name: "int8 (octal with a `-` sign)",
1856+
inType: &yang.YangType{Kind: yang.Yint8},
1857+
inValue: "-042",
1858+
want: "-042",
1859+
wantKind: yang.Yint8,
1860+
wantUnionName: "UnionInt8(-042)",
1861+
}, {
1862+
name: "int16 (octal with a `+` sign)",
1863+
inType: &yang.YangType{Kind: yang.Yint16},
1864+
inValue: "+04242",
1865+
want: "+04242",
1866+
wantKind: yang.Yint16,
1867+
wantUnionName: "UnionInt16(+04242)",
1868+
}, {
1869+
name: "int16 (octal with a `-` sign)",
1870+
inType: &yang.YangType{Kind: yang.Yint16},
1871+
inValue: "-04242",
1872+
want: "-04242",
1873+
wantKind: yang.Yint16,
1874+
wantUnionName: "UnionInt16(-04242)",
1875+
}, {
1876+
name: "int32 (octal with a `+` sign)",
1877+
inType: &yang.YangType{Kind: yang.Yint32},
1878+
inValue: "+04242",
1879+
want: "+04242",
1880+
wantKind: yang.Yint32,
1881+
wantUnionName: "UnionInt32(+04242)",
1882+
}, {
1883+
name: "int32 (octal with a `-` sign)",
1884+
inType: &yang.YangType{Kind: yang.Yint32},
1885+
inValue: "-04242",
1886+
want: "-04242",
1887+
wantKind: yang.Yint32,
1888+
wantUnionName: "UnionInt32(-04242)",
1889+
}, {
1890+
name: "int64 (octal with a `+` sign)",
1891+
inType: &yang.YangType{Kind: yang.Yint64},
1892+
inValue: "+04242",
1893+
want: "+04242",
1894+
wantKind: yang.Yint64,
1895+
wantUnionName: "UnionInt64(+04242)",
1896+
}, {
1897+
name: "int64 (octal with a `-` sign)",
1898+
inType: &yang.YangType{Kind: yang.Yint64},
1899+
inValue: "-04242",
1900+
want: "-04242",
1901+
wantKind: yang.Yint64,
1902+
wantUnionName: "UnionInt64(-04242)",
1903+
}, {
1904+
name: "uint8 (octal with a `+` sign -- invalid syntax)",
1905+
inType: &yang.YangType{Kind: yang.Yuint8},
1906+
inValue: "+042",
1907+
wantErr: true,
1908+
}, {
1909+
name: "uint8 (octal with a `-` sign -- invalid syntax)",
1910+
inType: &yang.YangType{Kind: yang.Yuint8},
1911+
inValue: "-042",
1912+
wantErr: true,
1913+
}, {
1914+
name: "int8 (binary format -- disallowed)",
1915+
inType: &yang.YangType{Kind: yang.Yint8},
1916+
inValue: "0b01",
1917+
wantErr: true,
1918+
}, {
1919+
name: "int8 (binary format with a `+` sign prefix -- disallowed)",
1920+
inType: &yang.YangType{Kind: yang.Yint8},
1921+
inValue: "+0b01",
1922+
wantErr: true,
1923+
}, {
1924+
name: "int8 (binary format with a `-` sign prefix -- disallowed)",
1925+
inType: &yang.YangType{Kind: yang.Yint8},
1926+
inValue: "-0b01",
1927+
wantErr: true,
16361928
}, {
16371929
name: "decimal64",
16381930
inType: &yang.YangType{Kind: yang.Ydecimal64},

0 commit comments

Comments
 (0)