diff options
Diffstat (limited to 'internal/validate')
-rw-r--r-- | internal/validate/formvalidation.go | 17 | ||||
-rw-r--r-- | internal/validate/formvalidation_test.go | 87 |
2 files changed, 44 insertions, 60 deletions
diff --git a/internal/validate/formvalidation.go b/internal/validate/formvalidation.go index 76ce6a8de..1b5996b4b 100644 --- a/internal/validate/formvalidation.go +++ b/internal/validate/formvalidation.go @@ -99,14 +99,19 @@ func Email(email string) error { return err } -// Language checks that the given language string is a 2- or 3-letter ISO 639 code. -// Returns an error if the language cannot be parsed. See: https://pkg.go.dev/golang.org/x/text/language -func Language(lang string) error { +// Language checks that the given language string is a valid, if not necessarily canonical, BCP 47 language tag. +// Returns a canonicalized version of the tag if the language can be parsed. +// Returns an error if the language cannot be parsed. +// See: https://pkg.go.dev/golang.org/x/text/language +func Language(lang string) (string, error) { if lang == "" { - return errors.New("no language provided") + return "", errors.New("no language provided") } - _, err := language.ParseBase(lang) - return err + parsed, err := language.Parse(lang) + if err != nil { + return "", err + } + return parsed.String(), err } // SignUpReason checks that a sufficient reason is given for a server signup request diff --git a/internal/validate/formvalidation_test.go b/internal/validate/formvalidation_test.go index 534e5b849..40830407c 100644 --- a/internal/validate/formvalidation_test.go +++ b/internal/validate/formvalidation_test.go @@ -159,60 +159,39 @@ func (suite *ValidationTestSuite) TestValidateEmail() { } func (suite *ValidationTestSuite) TestValidateLanguage() { - empty := "" - notALanguage := "this isn't a language at all!" - english := "en" - capitalEnglish := "EN" - arabic3Letters := "ara" - mixedCapsEnglish := "eN" - englishUS := "en-us" - dutch := "nl" - german := "de" - var err error - - err = validate.Language(empty) - if suite.Error(err) { - suite.Equal(errors.New("no language provided"), err) - } - - err = validate.Language(notALanguage) - if suite.Error(err) { - suite.Equal(errors.New("language: tag is not well-formed"), err) - } - - err = validate.Language(english) - if suite.NoError(err) { - suite.Equal(nil, err) - } - - err = validate.Language(capitalEnglish) - if suite.NoError(err) { - suite.Equal(nil, err) - } - - err = validate.Language(arabic3Letters) - if suite.NoError(err) { - suite.Equal(nil, err) - } - - err = validate.Language(mixedCapsEnglish) - if suite.NoError(err) { - suite.Equal(nil, err) - } - - err = validate.Language(englishUS) - if suite.Error(err) { - suite.Equal(errors.New("language: tag is not well-formed"), err) - } - - err = validate.Language(dutch) - if suite.NoError(err) { - suite.Equal(nil, err) - } - - err = validate.Language(german) - if suite.NoError(err) { - suite.Equal(nil, err) + testCases := []struct { + name, input, expected, err string + }{ + {name: "empty", err: "no language provided"}, + {name: "notALanguage", input: "this isn't a language at all!", err: "language: tag is not well-formed"}, + {name: "english", input: "en", expected: "en"}, + // Should be all lowercase + {name: "capitalEnglish", input: "EN", expected: "en"}, + // Overlong, should be in ISO 639-1 format + {name: "arabic3Letters", input: "ara", expected: "ar"}, + // Should be all lowercase + {name: "mixedCapsEnglish", input: "eN", expected: "en"}, + // Region should be capitalized + {name: "englishUS", input: "en-us", expected: "en-US"}, + {name: "dutch", input: "nl", expected: "nl"}, + {name: "german", input: "de", expected: "de"}, + {name: "chinese", input: "zh", expected: "zh"}, + {name: "chineseSimplified", input: "zh-Hans", expected: "zh-Hans"}, + {name: "chineseTraditional", input: "zh-Hant", expected: "zh-Hant"}, + } + + for _, testCase := range testCases { + testCase := testCase + suite.Run(testCase.name, func() { + actual, actualErr := validate.Language(testCase.input) + if testCase.err == "" { + suite.Equal(testCase.expected, actual) + suite.NoError(actualErr) + } else { + suite.Empty(actual) + suite.EqualError(actualErr, testCase.err) + } + }) } } |