unmarshal: validate date (#622)
This commit is contained in:
@@ -43,6 +43,10 @@ func parseLocalDate(b []byte) (LocalDate, error) {
|
|||||||
|
|
||||||
date.Day = parseDecimalDigits(b[8:10])
|
date.Day = parseDecimalDigits(b[8:10])
|
||||||
|
|
||||||
|
if !isValidDate(date.Year, date.Month, date.Day) {
|
||||||
|
return LocalDate{}, newDecodeError(b, "impossible date")
|
||||||
|
}
|
||||||
|
|
||||||
return date, nil
|
return date, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,3 +334,38 @@ func checkAndRemoveUnderscores(b []byte) ([]byte, error) {
|
|||||||
|
|
||||||
return cleaned, nil
|
return cleaned, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isValidDate checks if a provided date is a date that exists.
|
||||||
|
func isValidDate(year int, month int, day int) bool {
|
||||||
|
return day <= daysIn(month, year)
|
||||||
|
}
|
||||||
|
|
||||||
|
// daysBefore[m] counts the number of days in a non-leap year
|
||||||
|
// before month m begins. There is an entry for m=12, counting
|
||||||
|
// the number of days before January of next year (365).
|
||||||
|
var daysBefore = [...]int32{
|
||||||
|
0,
|
||||||
|
31,
|
||||||
|
31 + 28,
|
||||||
|
31 + 28 + 31,
|
||||||
|
31 + 28 + 31 + 30,
|
||||||
|
31 + 28 + 31 + 30 + 31,
|
||||||
|
31 + 28 + 31 + 30 + 31 + 30,
|
||||||
|
31 + 28 + 31 + 30 + 31 + 30 + 31,
|
||||||
|
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
|
||||||
|
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
|
||||||
|
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
|
||||||
|
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
|
||||||
|
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
|
||||||
|
}
|
||||||
|
|
||||||
|
func daysIn(m int, year int) int {
|
||||||
|
if m == 2 && isLeap(year) {
|
||||||
|
return 29
|
||||||
|
}
|
||||||
|
return int(daysBefore[m] - daysBefore[m-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
func isLeap(year int) bool {
|
||||||
|
return year%4 == 0 && (year%100 != 0 || year%400 == 0)
|
||||||
|
}
|
||||||
|
|||||||
@@ -176,7 +176,6 @@ func TestTOMLTest_Invalid_Control_StringUs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTOMLTest_Invalid_Datetime_ImpossibleDate(t *testing.T) {
|
func TestTOMLTest_Invalid_Datetime_ImpossibleDate(t *testing.T) {
|
||||||
t.Skip("FIXME")
|
|
||||||
input := "d = 2006-01-50T00:00:00Z\n"
|
input := "d = 2006-01-50T00:00:00Z\n"
|
||||||
testgenInvalid(t, input)
|
testgenInvalid(t, input)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -353,6 +353,22 @@ func TestUnmarshal(t *testing.T) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "local leap-day date into interface",
|
||||||
|
input: `a = 2020-02-29`,
|
||||||
|
gen: func() test {
|
||||||
|
type doc struct {
|
||||||
|
A interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return test{
|
||||||
|
target: &doc{},
|
||||||
|
expected: &doc{
|
||||||
|
A: toml.LocalDate{2020, 2, 29},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "local-time with nano second",
|
desc: "local-time with nano second",
|
||||||
input: `a = 12:08:05.666666666`,
|
input: `a = 12:08:05.666666666`,
|
||||||
@@ -2091,6 +2107,16 @@ world'`,
|
|||||||
desc: "multiline basic string with unfinished escape sequence after the first escape code",
|
desc: "multiline basic string with unfinished escape sequence after the first escape code",
|
||||||
data: "a = \"\"\"\\t\\",
|
data: "a = \"\"\"\\t\\",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: `impossible date-day`,
|
||||||
|
data: `A = 2021-03-40T23:59:00`,
|
||||||
|
msg: `impossible date`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: `leap day in non-leap year`,
|
||||||
|
data: `A = 2021-02-29T23:59:00`,
|
||||||
|
msg: `impossible date`,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, e := range examples {
|
for _, e := range examples {
|
||||||
|
|||||||
Reference in New Issue
Block a user