From e18c74e4418710a25cd66b25233f9a5aeb4f3eba Mon Sep 17 00:00:00 2001 From: Shabicha Sureshkumar Date: Sat, 19 Sep 2026 12:24:02 -0400 Subject: [PATCH 1/3] Add tests for language validator functions --- api/validators/language_validator_test.go | 168 ++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 api/validators/language_validator_test.go diff --git a/api/validators/language_validator_test.go b/api/validators/language_validator_test.go new file mode 100644 index 0000000..3b8a61a --- /dev/null +++ b/api/validators/language_validator_test.go @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package validators + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +// setSupportedLanguages configures the package-level language map for a test + restores an empty map so tests stay independent +func setSupportedLanguages(t *testing.T, langs []string) { + t.Helper() + + InitLanguageValidator(langs) + t.Cleanup(func() { InitLanguageValidator(nil) }) +} + +func TestInitLanguageValidator(t *testing.T) { + t.Cleanup(func() { InitLanguageValidator(nil) }) + + t.Run("supports the given languages", func(t *testing.T) { + InitLanguageValidator([]string{"en", "de"}) + + assert.True(t, IsValidLanguageCode("en")) + assert.True(t, IsValidLanguageCode("de")) + assert.False(t, IsValidLanguageCode("fr")) + }) + + t.Run("replaces previous languages", func(t *testing.T) { + InitLanguageValidator([]string{"en", "de"}) + InitLanguageValidator([]string{"fr"}) + + assert.True(t, IsValidLanguageCode("fr")) + assert.False(t, IsValidLanguageCode("en")) + assert.False(t, IsValidLanguageCode("de")) + }) + + t.Run("nil list clears all languages", func(t *testing.T) { + InitLanguageValidator([]string{"en"}) + InitLanguageValidator(nil) + + assert.False(t, IsValidLanguageCode("en")) + }) + + t.Run("empty list clears all languages", func(t *testing.T) { + InitLanguageValidator([]string{"en"}) + InitLanguageValidator([]string{}) + + assert.False(t, IsValidLanguageCode("en")) + }) + + t.Run("duplicate entries are accepted", func(t *testing.T) { + InitLanguageValidator([]string{"en", "en"}) + + assert.True(t, IsValidLanguageCode("en")) + }) +} + +func TestIsValidLanguageCode(t *testing.T) { + setSupportedLanguages(t, []string{"en", "de", "fr"}) + + tests := []struct { + name string + code string + want bool + }{ + {name: "supported code", code: "en", want: true}, + {name: "another supported code", code: "de", want: true}, + {name: "valid format but unsupported", code: "es", want: false}, + {name: "uppercase code", code: "EN", want: false}, + {name: "mixed case code", code: "En", want: false}, + {name: "empty code", code: "", want: false}, + {name: "single character", code: "e", want: false}, + {name: "three characters", code: "eng", want: false}, + {name: "leading whitespace", code: " e", want: false}, + {name: "trailing whitespace", code: "en ", want: false}, + {name: "digits", code: "12", want: false}, + {name: "SQL injection attempt", code: "en; DROP TABLE", want: false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, IsValidLanguageCode(tt.code)) + }) + } +} + +func TestIsValidLanguageCode_NoLanguagesConfigured(t *testing.T) { + setSupportedLanguages(t, nil) + + assert.False(t, IsValidLanguageCode("en")) +} + +func TestSanitizeLanguageCode(t *testing.T) { + setSupportedLanguages(t, []string{"en", "de"}) + + tests := []struct { + name string + code string + want string + }{ + {name: "supported code is uppercased", code: "en", want: "EN"}, + {name: "another supported code", code: "de", want: "DE"}, + {name: "unsupported code", code: "fr", want: ""}, + {name: "uppercase input is rejected", code: "EN", want: ""}, + {name: "empty code", code: "", want: ""}, + {name: "too long", code: "eng", want: ""}, + {name: "injection attempt", code: "en; DROP TABLE", want: ""}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, SanitizeLanguageCode(tt.code)) + }) + } +} + +func TestIsLanguageSupported(t *testing.T) { + tests := []struct { + name string + lang string + available []string + want bool + }{ + {name: "language in list", lang: "en", available: []string{"en", "de"}, want: true}, + {name: "language not in list", lang: "fr", available: []string{"en", "de"}, want: false}, + {name: "case sensitive", lang: "EN", available: []string{"en", "de"}, want: false}, + {name: "empty list", lang: "en", available: []string{}, want: false}, + {name: "nil list", lang: "en", available: nil, want: false}, + {name: "empty language not in list", lang: "", available: []string{"en"}, want: false}, + {name: "empty language in list", lang: "", available: []string{""}, want: true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, IsLanguageSupported(tt.lang, tt.available)) + }) + } +} + +func TestIsValidTranslationLangCode(t *testing.T) { + tests := []struct { + name string + code string + want bool + }{ + {name: "two-letter code", code: "de", want: true}, + {name: "three-letter code", code: "pnb", want: true}, + {name: "four-letter code", code: "abcd", want: true}, + {name: "uppercase code", code: "DE", want: false}, + {name: "mixed case code", code: "dE", want: false}, + {name: "empty code", code: "", want: false}, + {name: "single letter", code: "d", want: false}, + {name: "five letters", code: "abcde", want: false}, + {name: "digits", code: "d1", want: false}, + {name: "hyphen", code: "de-", want: false}, + {name: "leading whitespace", code: " de", want: false}, + {name: "trailing newline", code: "de\n", want: false}, + {name: "non-ASCII letters", code: "dé", want: false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, IsValidTranslationLangCode(tt.code)) + }) + } +} From e33e410dc455b8503c685114cdb020408fda5259 Mon Sep 17 00:00:00 2001 From: Shabicha Sureshkumar Date: Sat, 19 Sep 2026 12:45:07 -0400 Subject: [PATCH 2/3] changelog update --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9832457..fdb08c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ Emojis for the following are chosen based on [gitmoji](https://gitmoji.dev/). - Basic health and CORS test scaffolding was added for the API ([#29](https://github.com/scribe-org/Scribe-Server/pull/29)). - The CI workflow was updated to select the Go version via `go-version-file` ([#8](https://github.com/scribe-org/Scribe-Server/issues/8)) and later improved further ([#30](https://github.com/scribe-org/Scribe-Server/issues/30)). +- - Unit tests were added for the language validator functions ([#78](https://github.com/scribe-org/Scribe-Server/issues/78)). ### ♻️ Code Refactoring From 988d720d122ea9ced9a0f8a82a71dbeab146644b Mon Sep 17 00:00:00 2001 From: Shabicha Sureshkumar Date: Sat, 19 Sep 2026 22:59:07 -0400 Subject: [PATCH 3/3] removed - --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fdb08c6..bd184d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,7 +58,7 @@ Emojis for the following are chosen based on [gitmoji](https://gitmoji.dev/). - Basic health and CORS test scaffolding was added for the API ([#29](https://github.com/scribe-org/Scribe-Server/pull/29)). - The CI workflow was updated to select the Go version via `go-version-file` ([#8](https://github.com/scribe-org/Scribe-Server/issues/8)) and later improved further ([#30](https://github.com/scribe-org/Scribe-Server/issues/30)). -- - Unit tests were added for the language validator functions ([#78](https://github.com/scribe-org/Scribe-Server/issues/78)). +- Unit tests were added for the language validator functions ([#78](https://github.com/scribe-org/Scribe-Server/issues/78)). ### ♻️ Code Refactoring