From da812eed45cba1ce4c978e746039483064b8f92d Mon Sep 17 00:00:00 2001 From: JINMEI Tatuya Date: Mon, 17 Aug 2020 00:08:03 -0700 Subject: [PATCH] fix and enhance stringToCm to parse LOC RR optional fields (#1148) Automatically submitted. --- parse_test.go | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++ scan.go | 23 +++++++++++++++---- 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/parse_test.go b/parse_test.go index 25574d6b..74c6279d 100644 --- a/parse_test.go +++ b/parse_test.go @@ -415,6 +415,67 @@ func TestParseLOC(t *testing.T) { } } +// this tests a subroutine for the LOC RR parser. It's complicated enough to test separately. +func TestStringToCm(t *testing.T) { + tests := []struct { + // Test description: the input token and the expected return values from stringToCm. + token string + e uint8 + m uint8 + ok bool + }{ + {"100", 4, 1, true}, + {"0100", 4, 1, true}, // leading 0 (allowed) + {"100.99", 4, 1, true}, + {"90000000", 9, 9, true}, + {"90000000.00", 9, 9, true}, + {"0", 0, 0, true}, + {"0.00", 0, 0, true}, + {"0.01", 0, 1, true}, + {".01", 0, 1, true}, // empty 'meter' part (allowed) + {"0.1", 1, 1, true}, + + // out of range (too large) + {"90000001", 0, 0, false}, + {"90000000.01", 0, 0, false}, + + // more than 2 digits in 'cmeter' part + {"0.000", 0, 0, false}, + {"0.001", 0, 0, false}, + {"0.999", 0, 0, false}, + // with plus or minus sign (disallowed) + {"-100", 0, 0, false}, + {"+100", 0, 0, false}, + {"0.-10", 0, 0, false}, + {"0.+10", 0, 0, false}, + {"0a.00", 0, 0, false}, // invalid string for 'meter' part + {".1x", 0, 0, false}, // invalid string for 'cmeter' part + {".", 0, 0, false}, // empty 'cmeter' part (disallowed) + {"1.", 0, 0, false}, // ditto + {"m", 0, 0, false}, // only the "m" suffix + } + for _, tc := range tests { + tc := tc + t.Run(tc.token, func(t *testing.T) { + // In all cases the expected result is the same with or without the 'm' suffix. + // So we test both cases using the same test code. + for _, sfx := range []string{"", "m"} { + token := tc.token + sfx + e, m, ok := stringToCm(token) + if ok != tc.ok { + t.Fatal("unexpected validation result") + } + if m != tc.m { + t.Fatalf("Expected %d, got %d", tc.m, m) + } + if e != tc.e { + t.Fatalf("Expected %d, got %d", tc.e, e) + } + } + }) + } +} + func TestParseDS(t *testing.T) { dt := map[string]string{ "example.net. 3600 IN DS 40692 12 3 22261A8B0E0D799183E35E24E2AD6BB58533CBA7E3B14D659E9CA09B 2071398F": "example.net.\t3600\tIN\tDS\t40692 12 3 22261A8B0E0D799183E35E24E2AD6BB58533CBA7E3B14D659E9CA09B2071398F", diff --git a/scan.go b/scan.go index 2e5ec270..aa2840ef 100644 --- a/scan.go +++ b/scan.go @@ -1210,11 +1210,29 @@ func stringToCm(token string) (e, m uint8, ok bool) { if cmeters, err = strconv.Atoi(s[1]); err != nil { return } + // There's no point in having more than 2 digits in this part, and would rather make the implementation complicated ('123' should be treated as '12'). + // So we simply reject it. + // We also make sure the first character is a digit to reject '+-' signs. + if len(s[1]) > 2 || s[1][0] < '0' || s[1][0] > '9' { + return + } + if len(s[1]) == 1 { + // 'nn.1' must be treated as 'nn-meters and 10cm, not 1cm. + cmeters *= 10 + } + if len(s[0]) == 0 { + // This will allow omitting the 'meter' part, like .01 (meaning 0.01m = 1cm). + break + } fallthrough case 1: if meters, err = strconv.Atoi(s[0]); err != nil { return } + // RFC1876 states the max value is 90000000.00. The latter two conditions enforce it. + if s[0][0] < '0' || s[0][0] > '9' || meters > 90000000 || (meters == 90000000 && cmeters != 0) { + return + } case 0: // huh? return 0, 0, false @@ -1227,13 +1245,10 @@ func stringToCm(token string) (e, m uint8, ok bool) { e = 0 val = cmeters } - for val > 10 { + for val >= 10 { e++ val /= 10 } - if e > 9 { - ok = false - } m = uint8(val) return }