diff options
| author | Ethan Lee <ethanalee@google.com> | 2026-03-11 16:03:34 +0000 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2026-03-18 10:11:42 -0700 |
| commit | 9b7f749dab1cca49376cabf86673e35a3faff8fb (patch) | |
| tree | 601fdec9c02fd5cd3dc15f4c72af61619d853f3a /internal/api/params_test.go | |
| parent | 1b7f032dee11d6534119541bc3e03f0fcbcc4995 (diff) | |
| download | go-x-pkgsite-9b7f749dab1cca49376cabf86673e35a3faff8fb.tar.xz | |
internal/api: implement query parameter parsing for api
- Introduce structs that will be used to parse query parameters.
- Implement parsing method and create relevant tests.
Change-Id: Ib54a57a7eb8d2dbaab0edf705a6cb9e5bc8288a9
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/754240
Auto-Submit: Ethan Lee <ethanalee@google.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
kokoro-CI: kokoro <noreply+kokoro@google.com>
Diffstat (limited to 'internal/api/params_test.go')
| -rw-r--r-- | internal/api/params_test.go | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/internal/api/params_test.go b/internal/api/params_test.go new file mode 100644 index 00000000..6d325247 --- /dev/null +++ b/internal/api/params_test.go @@ -0,0 +1,184 @@ +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package api + +import ( + "net/url" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestParseParams(t *testing.T) { + type Nested struct { + ListParams + } + type DeepNested struct { + Nested + } + type EmbeddedPtr struct { + *ListParams + } + type extraParams struct { + Int64 int64 `form:"i64"` + Slice []string `form:"slice"` + PtrInt *int `form:"ptr"` + PtrPtr **int `form:"ptrptr"` + PtrSlice []*string `form:"ptrslice"` + private int `form:"private"` // Should be ignored + } + type overflowParams struct { + Int8 int8 `form:"i8"` + } + type unsupportedParams struct { + Float float64 `form:"float"` + } + + for _, test := range []struct { + name string + values url.Values + dst any + want any + wantErr bool + }{ + { + name: "PackageParams", + values: url.Values{"module": {"m"}, "version": {"v1.0.0"}, "goos": {"linux"}, "examples": {"true"}}, + dst: &PackageParams{}, + want: &PackageParams{ + Module: "m", + Version: "v1.0.0", + GOOS: "linux", + Examples: true, + }, + }, + { + name: "Boolean presence", + values: url.Values{"examples": {"true"}, "licenses": {"1"}}, + dst: &PackageParams{}, + want: &PackageParams{ + Examples: true, + Licenses: true, + }, + }, + { + name: "Boolean presence (ModuleParams)", + values: url.Values{"licenses": {"0"}, "readme": {"false"}}, + dst: &ModuleParams{}, + want: &ModuleParams{ + Licenses: false, + Readme: false, + }, + }, + { + name: "Empty bool", + values: url.Values{"examples": {""}}, + dst: &PackageParams{}, + want: &PackageParams{ + Examples: false, + }, + }, + { + name: "Invalid bool (on)", + values: url.Values{"examples": {"on"}}, + dst: &PackageParams{}, + wantErr: true, + }, + { + name: "Deeply nested embedding", + values: url.Values{"limit": {"100"}}, + dst: &DeepNested{}, + want: &DeepNested{ + Nested: Nested{ + ListParams: ListParams{Limit: 100}, + }, + }, + }, + { + name: "Extra types (int64, slice, ptr, ptrptr, ptrslice)", + values: url.Values{ + "i64": {"9223372036854775807"}, + "slice": {"a", "b"}, + "ptr": {"42"}, + "ptrptr": {"84"}, + "ptrslice": {"one", "two"}, + "private": {"1"}, + }, + dst: &extraParams{}, + want: &extraParams{ + Int64: 9223372036854775807, + Slice: []string{"a", "b"}, + PtrInt: intPtr(42), + PtrPtr: intPtrPtr(84), + PtrSlice: []*string{stringPtr("one"), stringPtr("two")}, + private: 0, // Ignored + }, + }, + { + name: "Malformed int", + values: url.Values{"limit": {"10.5"}}, + dst: &SymbolsParams{}, + wantErr: true, + }, + { + name: "Malformed bool", + values: url.Values{"examples": {"maybe"}}, + dst: &PackageParams{}, + wantErr: true, + }, + { + name: "Empty int", + values: url.Values{"limit": {""}}, + dst: &SymbolsParams{}, + wantErr: true, + }, + { + name: "Not a pointer", + values: url.Values{}, + dst: PackageParams{}, + wantErr: true, + }, + { + name: "Int8 overflow", + values: url.Values{"i8": {"128"}}, + dst: &overflowParams{}, + wantErr: true, + }, + { + name: "Unsupported type", + values: url.Values{"float": {"1.2"}}, + dst: &unsupportedParams{}, + wantErr: true, + }, + { + name: "Embedded pointer", + values: url.Values{"limit": {"50"}}, + dst: &EmbeddedPtr{}, + want: &EmbeddedPtr{ + ListParams: &ListParams{Limit: 50}, + }, + }, + } { + t.Run(test.name, func(t *testing.T) { + err := ParseParams(test.values, test.dst) + if (err != nil) != test.wantErr { + t.Fatalf("ParseParams() error = %v, wantErr %v", err, test.wantErr) + } + if test.wantErr { + return + } + if diff := cmp.Diff(test.want, test.dst, cmp.AllowUnexported(extraParams{})); diff != "" { + t.Errorf("ParseParams() mismatch (-want +got):\n%s", diff) + } + }) + } +} + +func intPtr(i int) *int { return &i } +func intPtrPtr(i int) **int { + p := intPtr(i) + return &p +} +func stringPtr(s string) *string { return &s } |
