From 90fb3927713a608030bcfb56dec2274ce1802025 Mon Sep 17 00:00:00 2001 From: favonia Date: Sun, 12 Mar 2023 09:30:32 -0500 Subject: [PATCH] style: change parsing errors --- internal/config/config.go | 2 +- internal/config/config_test.go | 7 ++- internal/config/env.go | 2 +- internal/config/env_test.go | 22 +++---- internal/domainexp/lexer.go | 4 +- internal/domainexp/parser.go | 95 ++++++++++++++++--------------- internal/domainexp/parser_test.go | 42 +++++++------- internal/droproot/checker.go | 4 +- test/fuzzer/fuzzer_test.go | 36 ++++++------ 9 files changed, 111 insertions(+), 103 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index cef44289..a0ad9051 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -347,7 +347,7 @@ func (c *Config) NormalizeConfig(ppfmt pp.PP) bool { } // fill in proxyMap - proxiedPred, ok := domainexp.ParseExpression(ppfmt, c.ProxiedTemplate) + proxiedPred, ok := domainexp.ParseExpression(ppfmt, "PROXIED", c.ProxiedTemplate) if !ok { return false } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 7d226437..405390ea 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -530,6 +530,7 @@ func TestReadEnvEmpty(t *testing.T) { func TestNormalizeConfig(t *testing.T) { t.Parallel() + keyProxied := "PROXIED" var empty config.Config for name, tc := range map[string]struct { @@ -719,7 +720,7 @@ func TestNormalizeConfig(t *testing.T) { m.EXPECT().IsEnabledFor(pp.Info).Return(true), m.EXPECT().Infof(pp.EmojiEnvVars, "Checking settings . . ."), m.EXPECT().IncIndent().Return(m), - m.EXPECT().Errorf(pp.EmojiUserError, "Failed to parse %q: wanted a boolean expression; got %q", `range`, `range`), + m.EXPECT().Errorf(pp.EmojiUserError, "%s (%q) is not a boolean expression: got unexpected token %q", keyProxied, `range`, `range`), //nolint:lll ) }, }, @@ -740,7 +741,7 @@ func TestNormalizeConfig(t *testing.T) { m.EXPECT().IsEnabledFor(pp.Info).Return(true), m.EXPECT().Infof(pp.EmojiEnvVars, "Checking settings . . ."), m.EXPECT().IncIndent().Return(m), - m.EXPECT().Errorf(pp.EmojiUserError, "Failed to parse %q: wanted a boolean expression; got %q", "999", "999"), + m.EXPECT().Errorf(pp.EmojiUserError, "%s (%q) is not a boolean expression: got unexpected token %q", keyProxied, `999`, `999`), //nolint:lll ) }, }, @@ -761,7 +762,7 @@ func TestNormalizeConfig(t *testing.T) { m.EXPECT().IsEnabledFor(pp.Info).Return(true), m.EXPECT().Infof(pp.EmojiEnvVars, "Checking settings . . ."), m.EXPECT().IncIndent().Return(m), - m.EXPECT().Errorf(pp.EmojiUserError, `Failed to parse %q: wanted %q; reached end of string`, `is(12345`, ")"), + m.EXPECT().Errorf(pp.EmojiUserError, `%s (%q) is missing %q at the end`, keyProxied, `is(12345`, ")"), ) }, }, diff --git a/internal/config/env.go b/internal/config/env.go index 116ce653..ed5c3f18 100644 --- a/internal/config/env.go +++ b/internal/config/env.go @@ -175,7 +175,7 @@ func ReadTTL(ppfmt pp.PP, key string, field *api.TTL) bool { // ReadDomains reads an environment variable as a comma-separated list of domains. func ReadDomains(ppfmt pp.PP, key string, field *[]domain.Domain) bool { - if list, ok := domainexp.ParseList(ppfmt, Getenv(key)); ok { + if list, ok := domainexp.ParseList(ppfmt, key, Getenv(key)); ok { *field = list return true } diff --git a/internal/config/env_test.go b/internal/config/env_test.go index 57ad19f6..8092c679 100644 --- a/internal/config/env_test.go +++ b/internal/config/env_test.go @@ -418,21 +418,21 @@ func TestReadDomains(t *testing.T) { "test1": {true, "書.org , Bücher.org ", ds{f("random.org")}, ds{f("xn--rov.org"), f("xn--bcher-kva.org")}, true, nil}, //nolint:lll "test2": {true, " \txn--rov.org , xn--Bcher-kva.org ", ds{f("random.org")}, ds{f("xn--rov.org"), f("xn--bcher-kva.org")}, true, nil}, //nolint:lll "illformed1": { - true, "xn--:D.org", + true, "xn--:D.org,a.org", ds{f("random.org")}, - ds{f("xn--:d.org")}, - true, + ds{f("random.org")}, + false, func(m *mocks.MockPP) { - m.EXPECT().Warningf(pp.EmojiUserError, "Domain %q was added but it is ill-formed: %v", "xn--:d.org", gomock.Any()) //nolint:lll + m.EXPECT().Errorf(pp.EmojiUserError, "%s (%q) contains an ill-formed domain %q: %v", key, "xn--:D.org,a.org", "xn--:d.org", gomock.Any()) //nolint:lll }, }, "illformed2": { - true, "*.xn--:D.org", + true, "*.xn--:D.org,a.org", ds{f("random.org")}, - ds{w("xn--:d.org")}, - true, + ds{f("random.org")}, + false, func(m *mocks.MockPP) { - m.EXPECT().Warningf(pp.EmojiUserError, "Domain %q was added but it is ill-formed: %v", "*.xn--:d.org", gomock.Any()) //nolint:lll + m.EXPECT().Errorf(pp.EmojiUserError, "%s (%q) contains an ill-formed domain %q: %v", key, "*.xn--:D.org,a.org", "*.xn--:d.org", gomock.Any()) //nolint:lll }, }, "illformed3": { @@ -441,7 +441,7 @@ func TestReadDomains(t *testing.T) { ds{}, false, func(m *mocks.MockPP) { - m.EXPECT().Errorf(pp.EmojiUserError, "Failed to parse %q: unexpected token %q", "hi.org,(", "(") + m.EXPECT().Errorf(pp.EmojiUserError, "%s (%q) has unexpected token %q", key, "hi.org,(", "(") }, }, "illformed4": { @@ -450,7 +450,7 @@ func TestReadDomains(t *testing.T) { ds{}, false, func(m *mocks.MockPP) { - m.EXPECT().Errorf(pp.EmojiUserError, "Failed to parse %q: unexpected token %q", ")", ")") + m.EXPECT().Errorf(pp.EmojiUserError, "%s (%q) has unexpected token %q", key, ")", ")") }, }, } { @@ -511,7 +511,7 @@ func TestReadProvider(t *testing.T) { func(m *mocks.MockPP) { m.EXPECT().Warningf( pp.EmojiUserWarning, - `%s=cloudflare is deprecated; use %s=cloudflare.trace or %s=cloudflare.doh`, //nolint:lll + `%s=cloudflare is deprecated; use %s=cloudflare.trace or %s=cloudflare.doh`, keyDeprecated, key, key, ) }, diff --git a/internal/domainexp/lexer.go b/internal/domainexp/lexer.go index c4bcf4a5..f7435209 100644 --- a/internal/domainexp/lexer.go +++ b/internal/domainexp/lexer.go @@ -99,7 +99,7 @@ func splitter(data []byte, atEOF bool) (int, []byte, error) { } } -func tokenize(ppfmt pp.PP, input string) ([]string, bool) { +func tokenize(ppfmt pp.PP, key string, input string) ([]string, bool) { scanner := bufio.NewScanner(strings.NewReader(input)) scanner.Split(splitter) @@ -110,7 +110,7 @@ func tokenize(ppfmt pp.PP, input string) ([]string, bool) { } if err := scanner.Err(); err != nil { - ppfmt.Errorf(pp.EmojiUserError, "Failed to parse %q: %v", input, err) + ppfmt.Errorf(pp.EmojiUserError, "%s (%q) is ill-formed: %v", key, input, err) return nil, false } return tokens, true diff --git a/internal/domainexp/parser.go b/internal/domainexp/parser.go index dd90ea5d..a3046f36 100644 --- a/internal/domainexp/parser.go +++ b/internal/domainexp/parser.go @@ -8,7 +8,7 @@ import ( "github.com/favonia/cloudflare-ddns/internal/pp" ) -func scanList(ppfmt pp.PP, input string, tokens []string) ([]string, []string) { +func scanList(ppfmt pp.PP, key string, input string, tokens []string) ([]string, []string) { var list []string readyForNext := true for len(tokens) > 0 { @@ -18,11 +18,11 @@ func scanList(ppfmt pp.PP, input string, tokens []string) ([]string, []string) { case ")": return list, tokens case "(", "&&", "||", "!": - ppfmt.Errorf(pp.EmojiUserError, `Failed to parse %q: unexpected token %q`, input, tokens[0]) + ppfmt.Errorf(pp.EmojiUserError, `%s (%q) has unexpected token %q`, key, input, tokens[0]) return nil, nil default: if !readyForNext { - ppfmt.Warningf(pp.EmojiUserError, `Please insert a comma "," before %q`, tokens[0]) + ppfmt.Warningf(pp.EmojiUserError, `%s (%q) is missing a comma "," before %q`, key, input, tokens[0]) } list = append(list, tokens[0]) readyForNext = false @@ -33,8 +33,8 @@ func scanList(ppfmt pp.PP, input string, tokens []string) ([]string, []string) { return list, tokens } -func scanASCIIDomainList(ppfmt pp.PP, input string, tokens []string) ([]string, []string) { - list, tokens := scanList(ppfmt, input, tokens) +func scanASCIIDomainList(ppfmt pp.PP, key string, input string, tokens []string) ([]string, []string) { + list, tokens := scanList(ppfmt, key, input, tokens) domains := make([]string, 0, len(list)) for _, raw := range list { domains = append(domains, domain.StringToASCII(raw)) @@ -42,42 +42,43 @@ func scanASCIIDomainList(ppfmt pp.PP, input string, tokens []string) ([]string, return domains, tokens } -func scanDomainList(ppfmt pp.PP, input string, tokens []string) ([]domain.Domain, []string) { - list, tokens := scanList(ppfmt, input, tokens) +func scanDomainList(ppfmt pp.PP, key string, input string, tokens []string) ([]domain.Domain, []string) { + list, tokens := scanList(ppfmt, key, input, tokens) domains := make([]domain.Domain, 0, len(list)) for _, raw := range list { domain, err := domain.New(raw) if err != nil { - ppfmt.Warningf(pp.EmojiUserError, - "Domain %q was added but it is ill-formed: %v", - domain.Describe(), err) + ppfmt.Errorf(pp.EmojiUserError, + "%s (%q) contains an ill-formed domain %q: %v", + key, input, domain.Describe(), err) + return nil, nil } domains = append(domains, domain) } return domains, tokens } -func scanConstants(_ppfmt pp.PP, _input string, tokens []string, wanted []string) (string, []string) { +func scanConstants(_ppfmt pp.PP, _key string, _input string, tokens []string, expected []string) (string, []string) { if len(tokens) == 0 { return "", nil } - for _, wanted := range wanted { - if wanted == tokens[0] { + for _, expected := range expected { + if expected == tokens[0] { return tokens[0], tokens[1:] } } return "", nil } -func scanMustConstant(ppfmt pp.PP, input string, tokens []string, wanted string) []string { +func scanMustConstant(ppfmt pp.PP, key string, input string, tokens []string, expected string) []string { if len(tokens) == 0 { - ppfmt.Errorf(pp.EmojiUserError, `Failed to parse %q: wanted %q; reached end of string`, input, wanted) + ppfmt.Errorf(pp.EmojiUserError, `%s (%q) is missing %q at the end`, key, input, expected) return nil } - if wanted == tokens[0] { + if expected == tokens[0] { return tokens[1:] } - ppfmt.Errorf(pp.EmojiUserError, `Failed to parse %q: wanted %q; got %q`, input, wanted, tokens[0]) + ppfmt.Errorf(pp.EmojiUserError, `%s (%q) has unexpected token %q when %q is expected`, key, input, tokens[0], expected) return nil } @@ -92,31 +93,31 @@ func hasStrictSuffix(s, suffix string) bool { // --> true | false | | ! | ( ) // //nolint:funlen -func scanFactor(ppfmt pp.PP, input string, tokens []string) (predicate, []string) { +func scanFactor(ppfmt pp.PP, key string, input string, tokens []string) (predicate, []string) { // fmt.Printf("scanFactor(tokens = %#v)\n", tokens) - if _, newTokens := scanConstants(ppfmt, input, tokens, + if _, newTokens := scanConstants(ppfmt, key, input, tokens, []string{"1", "t", "T", "TRUE", "true", "True"}); newTokens != nil { return func(_ domain.Domain) bool { return true }, newTokens } - if _, newTokens := scanConstants(ppfmt, input, tokens, + if _, newTokens := scanConstants(ppfmt, key, input, tokens, []string{"0", "f", "F", "FALSE", "false", "False"}); newTokens != nil { return func(_ domain.Domain) bool { return false }, newTokens } { //nolint:nestif - if funName, newTokens := scanConstants(ppfmt, input, tokens, []string{"is", "sub"}); newTokens != nil { - newTokens = scanMustConstant(ppfmt, input, newTokens, "(") + if funName, newTokens := scanConstants(ppfmt, key, input, tokens, []string{"is", "sub"}); newTokens != nil { + newTokens = scanMustConstant(ppfmt, key, input, newTokens, "(") if newTokens == nil { return nil, nil } - ASCIIDomains, newTokens := scanASCIIDomainList(ppfmt, input, newTokens) + ASCIIDomains, newTokens := scanASCIIDomainList(ppfmt, key, input, newTokens) if newTokens == nil { return nil, nil } - newTokens = scanMustConstant(ppfmt, input, newTokens, ")") + newTokens = scanMustConstant(ppfmt, key, input, newTokens, ")") if newTokens == nil { return nil, nil } @@ -145,9 +146,9 @@ func scanFactor(ppfmt pp.PP, input string, tokens []string) (predicate, []string } { - _, newTokens := scanConstants(ppfmt, input, tokens, []string{"!"}) + _, newTokens := scanConstants(ppfmt, key, input, tokens, []string{"!"}) if newTokens != nil { - if pred, newTokens := scanFactor(ppfmt, input, newTokens); newTokens != nil { + if pred, newTokens := scanFactor(ppfmt, key, input, newTokens); newTokens != nil { return func(d domain.Domain) bool { return !(pred(d)) }, newTokens } return nil, nil @@ -155,13 +156,13 @@ func scanFactor(ppfmt pp.PP, input string, tokens []string) (predicate, []string } { - _, newTokens := scanConstants(ppfmt, input, tokens, []string{"("}) + _, newTokens := scanConstants(ppfmt, key, input, tokens, []string{"("}) if newTokens != nil { - pred, newTokens := scanExpression(ppfmt, input, newTokens) + pred, newTokens := scanExpression(ppfmt, key, input, newTokens) if newTokens == nil { return nil, nil } - newTokens = scanMustConstant(ppfmt, input, newTokens, ")") + newTokens = scanMustConstant(ppfmt, key, input, newTokens, ")") if newTokens == nil { return nil, nil } @@ -170,9 +171,9 @@ func scanFactor(ppfmt pp.PP, input string, tokens []string) (predicate, []string } if len(tokens) == 0 { - ppfmt.Errorf(pp.EmojiUserError, "Failed to parse %q: wanted a boolean expression; reached end of string", input) + ppfmt.Errorf(pp.EmojiUserError, "%s (%q) is not a boolean expression", key, input) } else { - ppfmt.Errorf(pp.EmojiUserError, "Failed to parse %q: wanted a boolean expression; got %q", input, tokens[0]) + ppfmt.Errorf(pp.EmojiUserError, "%s (%q) is not a boolean expression: got unexpected token %q", key, input, tokens[0]) } return nil, nil } @@ -180,20 +181,20 @@ func scanFactor(ppfmt pp.PP, input string, tokens []string) (predicate, []string // scanTerm scans a term with this grammar: // // --> "&&" | -func scanTerm(ppfmt pp.PP, input string, tokens []string) (predicate, []string) { +func scanTerm(ppfmt pp.PP, key string, input string, tokens []string) (predicate, []string) { // fmt.Printf("scanTerm(tokens = %#v)\n", tokens) - pred1, tokens := scanFactor(ppfmt, input, tokens) + pred1, tokens := scanFactor(ppfmt, key, input, tokens) if tokens == nil { return nil, nil } - _, newTokens := scanConstants(ppfmt, input, tokens, []string{"&&"}) + _, newTokens := scanConstants(ppfmt, key, input, tokens, []string{"&&"}) if newTokens == nil { return pred1, tokens } - pred2, newTokens := scanTerm(ppfmt, input, newTokens) + pred2, newTokens := scanTerm(ppfmt, key, input, newTokens) if newTokens != nil { return func(d domain.Domain) bool { return pred1(d) && pred2(d) }, newTokens } @@ -204,18 +205,18 @@ func scanTerm(ppfmt pp.PP, input string, tokens []string) (predicate, []string) // scanExpression scans an expression with this grammar: // // --> "||" | -func scanExpression(ppfmt pp.PP, input string, tokens []string) (predicate, []string) { - pred1, tokens := scanTerm(ppfmt, input, tokens) +func scanExpression(ppfmt pp.PP, key string, input string, tokens []string) (predicate, []string) { + pred1, tokens := scanTerm(ppfmt, key, input, tokens) if tokens == nil { return nil, nil } - _, newTokens := scanConstants(ppfmt, input, tokens, []string{"||"}) + _, newTokens := scanConstants(ppfmt, key, input, tokens, []string{"||"}) if newTokens == nil { return pred1, tokens } - pred2, newTokens := scanExpression(ppfmt, input, newTokens) + pred2, newTokens := scanExpression(ppfmt, key, input, newTokens) if newTokens != nil { return func(d domain.Domain) bool { return pred1(d) || pred2(d) }, newTokens } @@ -224,17 +225,17 @@ func scanExpression(ppfmt pp.PP, input string, tokens []string) (predicate, []st } // ParseList parses a list of comma-separated domains. Internationalized domain names are fully supported. -func ParseList(ppfmt pp.PP, input string) ([]domain.Domain, bool) { - tokens, ok := tokenize(ppfmt, input) +func ParseList(ppfmt pp.PP, key string, input string) ([]domain.Domain, bool) { + tokens, ok := tokenize(ppfmt, key, input) if !ok { return nil, false } - list, tokens := scanDomainList(ppfmt, input, tokens) + list, tokens := scanDomainList(ppfmt, key, input, tokens) if tokens == nil { return nil, false } else if len(tokens) > 0 { - ppfmt.Errorf(pp.EmojiUserError, `Failed to parse %q: unexpected token %q`, input, tokens[0]) + ppfmt.Errorf(pp.EmojiUserError, `%s (%q) has unexpected token %q`, key, input, tokens[0]) return nil, false } @@ -255,17 +256,17 @@ func ParseList(ppfmt pp.PP, input string) ([]domain.Domain, bool) { // - exp1 && exp2, where exp1 and exp2 are boolean expressions, representing logical conjunction of exp1 and exp2. // // One can use parentheses to group expressions, such as !(is(hello.org) && (is(hello.io) || is(hello.me))). -func ParseExpression(ppfmt pp.PP, input string) (predicate, bool) { - tokens, ok := tokenize(ppfmt, input) +func ParseExpression(ppfmt pp.PP, key string, input string) (predicate, bool) { + tokens, ok := tokenize(ppfmt, key, input) if !ok { return nil, false } - pred, tokens := scanExpression(ppfmt, input, tokens) + pred, tokens := scanExpression(ppfmt, key, input, tokens) if tokens == nil { return nil, false } else if len(tokens) > 0 { - ppfmt.Errorf(pp.EmojiUserError, "Failed to parse %q: unexpected token %q", input, tokens[0]) + ppfmt.Errorf(pp.EmojiUserError, "%s (%q) has unexpected token %q", key, input, tokens[0]) return nil, false } diff --git a/internal/domainexp/parser_test.go b/internal/domainexp/parser_test.go index 3e880b85..b5be183f 100644 --- a/internal/domainexp/parser_test.go +++ b/internal/domainexp/parser_test.go @@ -14,6 +14,7 @@ import ( func TestParseList(t *testing.T) { t.Parallel() + key := "key" type f = domain.FQDN type w = domain.Wildcard type ds = []domain.Domain @@ -32,16 +33,16 @@ func TestParseList(t *testing.T) { ds{f("a"), f("b"), f("c"), f("d")}, func(m *mocks.MockPP) { gomock.InOrder( - m.EXPECT().Warningf(pp.EmojiUserError, `Please insert a comma "," before %q`, "b"), - m.EXPECT().Warningf(pp.EmojiUserError, `Please insert a comma "," before %q`, "c"), - m.EXPECT().Warningf(pp.EmojiUserError, `Please insert a comma "," before %q`, "d"), + m.EXPECT().Warningf(pp.EmojiUserError, `%s (%q) is missing a comma "," before %q`, key, " a b c d ", "b"), + m.EXPECT().Warningf(pp.EmojiUserError, `%s (%q) is missing a comma "," before %q`, key, " a b c d ", "c"), + m.EXPECT().Warningf(pp.EmojiUserError, `%s (%q) is missing a comma "," before %q`, key, " a b c d ", "d"), ) }, }, "illformed/1": { "&", false, nil, func(m *mocks.MockPP) { - m.EXPECT().Errorf(pp.EmojiUserError, "Failed to parse %q: %v", "&", domainexp.ErrSingleAnd) + m.EXPECT().Errorf(pp.EmojiUserError, "%s (%q) is ill-formed: %v", key, "&", domainexp.ErrSingleAnd) }, }, } { @@ -55,7 +56,7 @@ func TestParseList(t *testing.T) { tc.prepareMockPP(mockPP) } - list, ok := domainexp.ParseList(mockPP, tc.input) + list, ok := domainexp.ParseList(mockPP, key, tc.input) require.Equal(t, tc.ok, ok) require.Equal(t, tc.expected, list) }) @@ -65,6 +66,7 @@ func TestParseList(t *testing.T) { //nolint:funlen func TestParseExpression(t *testing.T) { t.Parallel() + key := "key" type f = domain.FQDN type w = domain.Wildcard for name, tc := range map[string]struct { @@ -77,7 +79,7 @@ func TestParseExpression(t *testing.T) { "empty": { "", false, nil, true, func(m *mocks.MockPP) { - m.EXPECT().Errorf(pp.EmojiUserError, `Failed to parse %q: wanted a boolean expression; reached end of string`, "") + m.EXPECT().Errorf(pp.EmojiUserError, `%s (%q) is not a boolean expression`, key, "") }, }, "const/1": {"true", true, nil, true, nil}, @@ -86,38 +88,38 @@ func TestParseExpression(t *testing.T) { "&&/2": { "t &&", false, nil, false, func(m *mocks.MockPP) { - m.EXPECT().Errorf(pp.EmojiUserError, `Failed to parse %q: wanted a boolean expression; reached end of string`, "t &&") //nolint:lll + m.EXPECT().Errorf(pp.EmojiUserError, `%s (%q) is not a boolean expression`, key, "t &&") }, }, "&&/&/1": { "true & true", false, nil, false, func(m *mocks.MockPP) { - m.EXPECT().Errorf(pp.EmojiUserError, "Failed to parse %q: %v", "true & true", domainexp.ErrSingleAnd) + m.EXPECT().Errorf(pp.EmojiUserError, "%s (%q) is ill-formed: %v", key, "true & true", domainexp.ErrSingleAnd) }, }, "&&/&/2": { "true &", false, nil, false, func(m *mocks.MockPP) { - m.EXPECT().Errorf(pp.EmojiUserError, "Failed to parse %q: %v", "true &", domainexp.ErrSingleAnd) + m.EXPECT().Errorf(pp.EmojiUserError, "%s (%q) is ill-formed: %v", key, "true &", domainexp.ErrSingleAnd) }, }, "||/1": {"F || 1", true, nil, true, nil}, "||/2": { "F ||", false, nil, false, func(m *mocks.MockPP) { - m.EXPECT().Errorf(pp.EmojiUserError, `Failed to parse %q: wanted a boolean expression; reached end of string`, "F ||") //nolint:lll + m.EXPECT().Errorf(pp.EmojiUserError, `%s (%q) is not a boolean expression`, key, "F ||") }, }, "||/|/1": { "false | false", false, nil, false, func(m *mocks.MockPP) { - m.EXPECT().Errorf(pp.EmojiUserError, "Failed to parse %q: %v", "false | false", domainexp.ErrSingleOr) + m.EXPECT().Errorf(pp.EmojiUserError, "%s (%q) is ill-formed: %v", key, "false | false", domainexp.ErrSingleOr) }, }, "||/|/2": { "false |", false, nil, false, func(m *mocks.MockPP) { - m.EXPECT().Errorf(pp.EmojiUserError, "Failed to parse %q: %v", "false |", domainexp.ErrSingleOr) + m.EXPECT().Errorf(pp.EmojiUserError, "%s (%q) is ill-formed: %v", key, "false |", domainexp.ErrSingleOr) }, }, "is/1": {"is(example.com)", true, f("example.com"), true, nil}, @@ -132,19 +134,19 @@ func TestParseExpression(t *testing.T) { "is/error/1": { "is)", false, nil, false, func(m *mocks.MockPP) { - m.EXPECT().Errorf(pp.EmojiUserError, `Failed to parse %q: wanted %q; got %q`, "is)", "(", ")") + m.EXPECT().Errorf(pp.EmojiUserError, `%s (%q) has unexpected token %q when %q is expected`, key, "is)", ")", "(") }, }, "is/error/2": { "is(&&", false, nil, false, func(m *mocks.MockPP) { - m.EXPECT().Errorf(pp.EmojiUserError, `Failed to parse %q: unexpected token %q`, "is(&&", "&&") + m.EXPECT().Errorf(pp.EmojiUserError, `%s (%q) has unexpected token %q`, key, "is(&&", "&&") }, }, "is/error/3": { "is", false, nil, false, func(m *mocks.MockPP) { - m.EXPECT().Errorf(pp.EmojiUserError, `Failed to parse %q: wanted %q; reached end of string`, "is", "(") + m.EXPECT().Errorf(pp.EmojiUserError, `%s (%q) is missing %q at the end`, key, "is", "(") }, }, "sub/1": {"sub(example.com)", true, f("example.com"), false, nil}, @@ -159,26 +161,26 @@ func TestParseExpression(t *testing.T) { "not/3": { "!(", false, nil, true, func(m *mocks.MockPP) { - m.EXPECT().Errorf(pp.EmojiUserError, "Failed to parse %q: wanted a boolean expression; reached end of string", "!(") + m.EXPECT().Errorf(pp.EmojiUserError, "%s (%q) is not a boolean expression", key, "!(") }, }, "nested/1": {"((true)||(false))&&((false)||(true))", true, nil, true, nil}, "nested/2": { "((", false, nil, true, func(m *mocks.MockPP) { - m.EXPECT().Errorf(pp.EmojiUserError, "Failed to parse %q: wanted a boolean expression; reached end of string", "((") + m.EXPECT().Errorf(pp.EmojiUserError, "%s (%q) is not a boolean expression", key, "((") }, }, "nested/3": { "(true", false, nil, true, func(m *mocks.MockPP) { - m.EXPECT().Errorf(pp.EmojiUserError, "Failed to parse %q: wanted %q; reached end of string", "(true", ")") + m.EXPECT().Errorf(pp.EmojiUserError, "%s (%q) is missing %q at the end", key, "(true", ")") }, }, "error/extra": { "0 1", false, nil, false, func(m *mocks.MockPP) { - m.EXPECT().Errorf(pp.EmojiUserError, "Failed to parse %q: unexpected token %q", "0 1", "1") + m.EXPECT().Errorf(pp.EmojiUserError, "%s (%q) has unexpected token %q", key, "0 1", "1") }, }, } { @@ -192,7 +194,7 @@ func TestParseExpression(t *testing.T) { tc.prepareMockPP(mockPP) } - pred, ok := domainexp.ParseExpression(mockPP, tc.input) + pred, ok := domainexp.ParseExpression(mockPP, "key", tc.input) require.Equal(t, tc.ok, ok) if ok { require.Equal(t, tc.expected, pred(tc.domain)) diff --git a/internal/droproot/checker.go b/internal/droproot/checker.go index 7895a2b2..f2092ef5 100644 --- a/internal/droproot/checker.go +++ b/internal/droproot/checker.go @@ -37,7 +37,9 @@ func checkGroupIDs(ppfmt pp.PP, gid int) bool { descriptions = append(descriptions, strconv.Itoa(g)) } } - ppfmt.Warningf(pp.EmojiUserWarning, "Failed to reset group IDs to only %d; current ones: %s", gid, strings.Join(descriptions, ", ")) + ppfmt.Warningf(pp.EmojiUserWarning, + "Failed to reset group IDs to only %d; current ones: %s", + gid, strings.Join(descriptions, ", ")) } return ok diff --git a/test/fuzzer/fuzzer_test.go b/test/fuzzer/fuzzer_test.go index e0e486d1..8d1d9ebc 100644 --- a/test/fuzzer/fuzzer_test.go +++ b/test/fuzzer/fuzzer_test.go @@ -11,18 +11,20 @@ import ( "github.com/favonia/cloudflare-ddns/internal/pp" ) +const key string = "KEY" + // FuzzParseList fuzz test [domainexp.ParseList]. func FuzzParseList(f *testing.F) { f.Fuzz(func(t *testing.T, input string) { mockCtrl := gomock.NewController(t) mockPP := mocks.NewMockPP(mockCtrl) - mockPP.EXPECT().Errorf(pp.EmojiUserError, `Failed to parse %q: %v`, gomock.Any(), domainexp.ErrSingleAnd).AnyTimes() - mockPP.EXPECT().Errorf(pp.EmojiUserError, `Failed to parse %q: %v`, gomock.Any(), domainexp.ErrSingleOr).AnyTimes() - mockPP.EXPECT().Errorf(pp.EmojiUserError, `Failed to parse %q: unexpected token %q`, gomock.Any(), gomock.Any()).AnyTimes() //nolint:lll - mockPP.EXPECT().Warningf(pp.EmojiUserError, `Domain %q was added but it is ill-formed: %v`, gomock.Any(), gomock.Any()).AnyTimes() //nolint:lll - mockPP.EXPECT().Warningf(pp.EmojiUserError, `Please insert a comma "," before %q`, gomock.Any()).AnyTimes() + mockPP.EXPECT().Errorf(pp.EmojiUserError, `%s (%q) is ill-formed: %v`, key, input, domainexp.ErrSingleAnd).AnyTimes() + mockPP.EXPECT().Errorf(pp.EmojiUserError, `%s (%q) is ill-formed: %v`, key, input, domainexp.ErrSingleOr).AnyTimes() + mockPP.EXPECT().Errorf(pp.EmojiUserError, `%s (%q) has unexpected token %q`, key, input, gomock.Any()).AnyTimes() + mockPP.EXPECT().Errorf(pp.EmojiUserError, `%s (%q) contains an ill-formed domain %q: %v`, key, input, gomock.Any(), gomock.Any()).AnyTimes() //nolint:lll + mockPP.EXPECT().Warningf(pp.EmojiUserError, `%s (%q) is missing a comma "," before %q`, key, input, gomock.Any()).AnyTimes() //nolint:lll - _, _ = domainexp.ParseList(mockPP, input) + _, _ = domainexp.ParseList(mockPP, key, input) }) } @@ -31,16 +33,16 @@ func FuzzParseExpression(f *testing.F) { f.Fuzz(func(t *testing.T, input string) { mockCtrl := gomock.NewController(t) mockPP := mocks.NewMockPP(mockCtrl) - mockPP.EXPECT().Errorf(pp.EmojiUserError, `Failed to parse %q: %v`, gomock.Any(), domainexp.ErrSingleAnd).AnyTimes() - mockPP.EXPECT().Errorf(pp.EmojiUserError, `Failed to parse %q: %v`, gomock.Any(), domainexp.ErrSingleOr).AnyTimes() - mockPP.EXPECT().Errorf(pp.EmojiUserError, `Failed to parse %q: unexpected token %q`, gomock.Any(), gomock.Any()).AnyTimes() //nolint:lll - mockPP.EXPECT().Errorf(pp.EmojiUserError, `Failed to parse %q: wanted %q; got %q`, gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() //nolint:lll - mockPP.EXPECT().Errorf(pp.EmojiUserError, `Failed to parse %q: wanted %q; reached end of string`, gomock.Any(), gomock.Any()).AnyTimes() //nolint:lll - mockPP.EXPECT().Errorf(pp.EmojiUserError, `Failed to parse %q: wanted a boolean expression; got %q`, gomock.Any(), gomock.Any()).AnyTimes() //nolint:lll - mockPP.EXPECT().Errorf(pp.EmojiUserError, `Failed to parse %q: wanted a boolean expression; reached end of string`, gomock.Any()).AnyTimes() //nolint:lll - mockPP.EXPECT().Warningf(pp.EmojiUserError, "Domain %q was added but it is ill-formed: %v", gomock.Any(), gomock.Any()).AnyTimes() //nolint:lll - mockPP.EXPECT().Warningf(pp.EmojiUserError, `Please insert a comma "," before %q`, gomock.Any()).AnyTimes() - - _, _ = domainexp.ParseExpression(mockPP, input) + mockPP.EXPECT().Errorf(pp.EmojiUserError, `%s (%q) is ill-formed: %v`, key, input, domainexp.ErrSingleAnd).AnyTimes() + mockPP.EXPECT().Errorf(pp.EmojiUserError, `%s (%q) is ill-formed: %v`, key, input, domainexp.ErrSingleOr).AnyTimes() + mockPP.EXPECT().Errorf(pp.EmojiUserError, `%s (%q) has unexpected token %q`, key, input, gomock.Any()).AnyTimes() //nolint:lll + mockPP.EXPECT().Errorf(pp.EmojiUserError, `%s (%q) has unexpected token %q when %q is expected`, key, input, gomock.Any(), gomock.Any()).AnyTimes() //nolint:lll + mockPP.EXPECT().Errorf(pp.EmojiUserError, `%s (%q) is missing %q at the end`, key, input, gomock.Any()).AnyTimes() + mockPP.EXPECT().Errorf(pp.EmojiUserError, `%s (%q) is not a boolean expression: got unexpected token %q`, key, input, gomock.Any()).AnyTimes() //nolint:lll + mockPP.EXPECT().Errorf(pp.EmojiUserError, `%s (%q) is not a boolean expression`, key, input).AnyTimes() + mockPP.EXPECT().Errorf(pp.EmojiUserError, `%s (%q) contains an ill-formed domain %q: %v`, key, input, gomock.Any(), gomock.Any()).AnyTimes() //nolint:lll + mockPP.EXPECT().Warningf(pp.EmojiUserError, `%s (%q) is missing a comma "," before %q`, key, input, gomock.Any()).AnyTimes() //nolint:lll + + _, _ = domainexp.ParseExpression(mockPP, key, input) }) }