package httputils import ( "math" "net/http" "net/url" "strconv" "testing" cerrdefs "github.com/containerd/errdefs" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" ) func TestBoolValue(t *testing.T) { cases := map[string]bool{ "": false, "0": false, "no": false, "false": false, "none": false, "1": true, "yes": true, "true": true, "one": true, "100": true, } for c, e := range cases { v := url.Values{} v.Set("test", c) r, _ := http.NewRequest(http.MethodPost, "", http.NoBody) r.Form = v a := BoolValue(r, "test") if a != e { t.Fatalf("Value: %s, expected: %v, actual: %v", c, e, a) } } } func TestBoolValueOrDefault(t *testing.T) { r, _ := http.NewRequest(http.MethodGet, "", http.NoBody) if !BoolValueOrDefault(r, "queryparam", true) { t.Fatal("Expected to get true default value, got false") } v := url.Values{} v.Set("param", "") r, _ = http.NewRequest(http.MethodGet, "", http.NoBody) r.Form = v if BoolValueOrDefault(r, "param", true) { t.Fatal("Expected not to get true") } } func TestInt64ValueOrZero(t *testing.T) { cases := map[string]int64{ "": 0, "asdf": 0, "0": 0, "1": 1, } for c, e := range cases { v := url.Values{} v.Set("test", c) r, _ := http.NewRequest(http.MethodPost, "", http.NoBody) r.Form = v a := Int64ValueOrZero(r, "test") if a != e { t.Fatalf("Value: %s, expected: %v, actual: %v", c, e, a) } } } func TestInt64ValueOrDefault(t *testing.T) { cases := map[string]int64{ "": -1, "-1": -1, "42": 42, } for c, e := range cases { v := url.Values{} v.Set("test", c) r, _ := http.NewRequest(http.MethodPost, "", http.NoBody) r.Form = v a, err := Int64ValueOrDefault(r, "test", -1) if a != e { t.Fatalf("Value: %s, expected: %v, actual: %v", c, e, a) } if err != nil { t.Fatalf("Error should be nil, but received: %s", err) } } } func TestInt64ValueOrDefaultWithError(t *testing.T) { v := url.Values{} v.Set("test", "invalid") r, _ := http.NewRequest(http.MethodPost, "", http.NoBody) r.Form = v _, err := Int64ValueOrDefault(r, "test", -1) if err == nil { t.Fatal("Expected an error.") } } func TestUint32Value(t *testing.T) { const valueNotSet = "unset" tests := []struct { value string expected uint32 expectedErr error }{ { value: "0", expected: 0, }, { value: strconv.FormatUint(math.MaxUint32, 10), expected: math.MaxUint32, }, { value: valueNotSet, expectedErr: strconv.ErrSyntax, }, { value: "", expectedErr: strconv.ErrSyntax, }, { value: "-1", expectedErr: strconv.ErrRange, }, { value: "4294967296", // MaxUint32+1 expectedErr: strconv.ErrRange, }, { value: "not-a-number", expectedErr: strconv.ErrSyntax, }, } for _, tc := range tests { t.Run(tc.value, func(t *testing.T) { r, _ := http.NewRequest(http.MethodPost, "", http.NoBody) r.Form = url.Values{} if tc.value != valueNotSet { r.Form.Set("field", tc.value) } out, err := Uint32Value(r, "field") assert.Check(t, is.Equal(tc.expected, out)) assert.Check(t, is.ErrorIs(err, tc.expectedErr)) }) } } func TestDecodePlatform(t *testing.T) { tests := []struct { doc string platformJSON string expected *ocispec.Platform expectedErr string }{ { doc: "empty platform", expectedErr: `failed to parse platform: unexpected end of JSON input`, }, { doc: "not JSON", platformJSON: `linux/ams64`, expectedErr: `failed to parse platform: invalid character 'l' looking for beginning of value`, }, { doc: "malformed JSON", platformJSON: `{"architecture"`, expectedErr: `failed to parse platform: unexpected end of JSON input`, }, { doc: "missing os", platformJSON: `{"architecture":"amd64","os":""}`, expectedErr: `both OS and Architecture must be provided`, }, { doc: "variant without architecture", platformJSON: `{"architecture":"","os":"","variant":"v7"}`, expectedErr: `optional platform fields provided, but OS and Architecture are missing`, }, { doc: "missing architecture", platformJSON: `{"architecture":"","os":"linux"}`, expectedErr: `both OS and Architecture must be provided`, }, { doc: "os.version without os and architecture", platformJSON: `{"architecture":"","os":"","os.version":"12.0"}`, expectedErr: `optional platform fields provided, but OS and Architecture are missing`, }, { doc: "os.features without os and architecture", platformJSON: `{"architecture":"","os":"","os.features":["a","b"]}`, expectedErr: `optional platform fields provided, but OS and Architecture are missing`, }, { doc: "valid platform", platformJSON: `{"architecture":"arm64","os":"linux","os.version":"12.0", "os.features":["a","b"], "variant": "v7"}`, expected: &ocispec.Platform{ Architecture: "arm64", OS: "linux", OSVersion: "12.0", OSFeatures: []string{"a", "b"}, Variant: "v7", }, }, } for _, tc := range tests { t.Run(tc.doc, func(t *testing.T) { p, err := DecodePlatform(tc.platformJSON) assert.Check(t, is.DeepEqual(p, tc.expected)) if tc.expectedErr != "" { assert.Check(t, cerrdefs.IsInvalidArgument(err)) assert.Check(t, is.Error(err, tc.expectedErr)) } else { assert.Check(t, err) } }) } }