// Copyright 2011 Google Inc. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package googleapi import ( "encoding/json" "io/ioutil" "net/http" "net/url" "reflect" "strings" "testing" ) type ExpandTest struct { in string expansions map[string]string want string } var expandTests = []ExpandTest{ // no expansions { "http://www.golang.org/", map[string]string{}, "http://www.golang.org/", }, // one expansion, no escaping { "http://www.golang.org/{bucket}/delete", map[string]string{ "bucket": "red", }, "http://www.golang.org/red/delete", }, // one expansion, with hex escapes { "http://www.golang.org/{bucket}/delete", map[string]string{ "bucket": "red/blue", }, "http://www.golang.org/red%2Fblue/delete", }, // one expansion, with space { "http://www.golang.org/{bucket}/delete", map[string]string{ "bucket": "red or blue", }, "http://www.golang.org/red%20or%20blue/delete", }, // expansion not found { "http://www.golang.org/{object}/delete", map[string]string{ "bucket": "red or blue", }, "http://www.golang.org//delete", }, // multiple expansions { "http://www.golang.org/{one}/{two}/{three}/get", map[string]string{ "one": "ONE", "two": "TWO", "three": "THREE", }, "http://www.golang.org/ONE/TWO/THREE/get", }, // utf-8 characters { "http://www.golang.org/{bucket}/get", map[string]string{ "bucket": "£100", }, "http://www.golang.org/%C2%A3100/get", }, // punctuations { "http://www.golang.org/{bucket}/get", map[string]string{ "bucket": `/\@:,.`, }, "http://www.golang.org/%2F%5C%40%3A%2C./get", }, // mis-matched brackets { "http://www.golang.org/{bucket/get", map[string]string{ "bucket": "red", }, "http://www.golang.org/%7Bbucket/get", }, // "+" prefix for suppressing escape // See also: http://tools.ietf.org/html/rfc6570#section-3.2.3 { "http://www.golang.org/{+topic}", map[string]string{ "topic": "/topics/myproject/mytopic", }, // The double slashes here look weird, but it's intentional "http://www.golang.org//topics/myproject/mytopic", }, } func TestExpand(t *testing.T) { for i, test := range expandTests { u := url.URL{ Path: test.in, } Expand(&u, test.expansions) got := u.EscapedPath() if got != test.want { t.Errorf("got %q expected %q in test %d", got, test.want, i+1) } } } func TestResolveRelative(t *testing.T) { resolveRelativeTests := []struct { basestr string relstr string want string }{ { "http://www.golang.org/", "topics/myproject/mytopic", "http://www.golang.org/topics/myproject/mytopic", }, { "http://www.golang.org/", "topics/{+myproject}/{release}:build:test:deploy", "http://www.golang.org/topics/{+myproject}/{release}:build:test:deploy", }, { "https://www.googleapis.com/admin/reports/v1/", "/admin/reports_v1/channels/stop", "https://www.googleapis.com/admin/reports_v1/channels/stop", }, { "https://www.googleapis.com/admin/directory/v1/", "customer/{customerId}/orgunits{/orgUnitPath*}", "https://www.googleapis.com/admin/directory/v1/customer/{customerId}/orgunits{/orgUnitPath*}", }, { "https://www.googleapis.com/tagmanager/v2/", "accounts", "https://www.googleapis.com/tagmanager/v2/accounts", }, { "https://www.googleapis.com/tagmanager/v2/", "{+parent}/workspaces", "https://www.googleapis.com/tagmanager/v2/{+parent}/workspaces", }, { "https://www.googleapis.com/tagmanager/v2/", "{+path}:create_version", "https://www.googleapis.com/tagmanager/v2/{+path}:create_version", }, } for i, test := range resolveRelativeTests { got := ResolveRelative(test.basestr, test.relstr) if got != test.want { t.Errorf("got %q expected %q in test %d", got, test.want, i+1) } } } type CheckResponseTest struct { in *http.Response bodyText string want error errText string } var checkResponseTests = []CheckResponseTest{ { &http.Response{ StatusCode: http.StatusOK, }, "", nil, "", }, { &http.Response{ StatusCode: http.StatusInternalServerError, }, `{"error":{}}`, &Error{ Code: http.StatusInternalServerError, Body: `{"error":{}}`, }, `googleapi: got HTTP response code 500 with body: {"error":{}}`, }, { &http.Response{ StatusCode: http.StatusNotFound, }, `{"error":{"message":"Error message for StatusNotFound."}}`, &Error{ Code: http.StatusNotFound, Message: "Error message for StatusNotFound.", Body: `{"error":{"message":"Error message for StatusNotFound."}}`, }, "googleapi: Error 404: Error message for StatusNotFound.", }, { &http.Response{ StatusCode: http.StatusBadRequest, }, `{"error":"invalid_token","error_description":"Invalid Value"}`, &Error{ Code: http.StatusBadRequest, Body: `{"error":"invalid_token","error_description":"Invalid Value"}`, }, `googleapi: got HTTP response code 400 with body: {"error":"invalid_token","error_description":"Invalid Value"}`, }, { &http.Response{ StatusCode: http.StatusBadRequest, }, `{"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}}`, &Error{ Code: http.StatusBadRequest, Errors: []ErrorItem{ { Reason: "keyInvalid", Message: "Bad Request", }, }, Body: `{"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}}`, Message: "Bad Request", }, "googleapi: Error 400: Bad Request, keyInvalid", }, } func TestCheckResponse(t *testing.T) { for _, test := range checkResponseTests { res := test.in if test.bodyText != "" { res.Body = ioutil.NopCloser(strings.NewReader(test.bodyText)) } g := CheckResponse(res) if !reflect.DeepEqual(g, test.want) { t.Errorf("CheckResponse: got %v, want %v", g, test.want) gotJson, err := json.Marshal(g) if err != nil { t.Error(err) } wantJson, err := json.Marshal(test.want) if err != nil { t.Error(err) } t.Errorf("json(got): %q\njson(want): %q", string(gotJson), string(wantJson)) } if g != nil && g.Error() != test.errText { t.Errorf("CheckResponse: unexpected error message.\nGot: %q\nwant: %q", g, test.errText) } } } type VariantPoint struct { Type string Coordinates []float64 } type VariantTest struct { in map[string]interface{} result bool want VariantPoint } var coords = []interface{}{1.0, 2.0} var variantTests = []VariantTest{ { in: map[string]interface{}{ "type": "Point", "coordinates": coords, }, result: true, want: VariantPoint{ Type: "Point", Coordinates: []float64{1.0, 2.0}, }, }, { in: map[string]interface{}{ "type": "Point", "bogus": coords, }, result: true, want: VariantPoint{ Type: "Point", }, }, } func TestVariantType(t *testing.T) { for _, test := range variantTests { if g := VariantType(test.in); g != test.want.Type { t.Errorf("VariantType(%v): got %v, want %v", test.in, g, test.want.Type) } } } func TestConvertVariant(t *testing.T) { for _, test := range variantTests { g := VariantPoint{} r := ConvertVariant(test.in, &g) if r != test.result { t.Errorf("ConvertVariant(%v): got %v, want %v", test.in, r, test.result) } if !reflect.DeepEqual(g, test.want) { t.Errorf("ConvertVariant(%v): got %v, want %v", test.in, g, test.want) } } } func TestRoundChunkSize(t *testing.T) { type testCase struct { in int want int } for _, tc := range []testCase{ {0, 0}, {256*1024 - 1, 256 * 1024}, {256 * 1024, 256 * 1024}, {256*1024 + 1, 2 * 256 * 1024}, } { mo := &MediaOptions{} ChunkSize(tc.in).setOptions(mo) if got := mo.ChunkSize; got != tc.want { t.Errorf("rounding chunk size: got: %v; want %v", got, tc.want) } } }