You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

336 lines
7.8 KiB

  1. // Copyright 2011 Google Inc. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package googleapi
  5. import (
  6. "encoding/json"
  7. "io/ioutil"
  8. "net/http"
  9. "net/url"
  10. "reflect"
  11. "strings"
  12. "testing"
  13. )
  14. type ExpandTest struct {
  15. in string
  16. expansions map[string]string
  17. want string
  18. }
  19. var expandTests = []ExpandTest{
  20. // no expansions
  21. {
  22. "http://www.golang.org/",
  23. map[string]string{},
  24. "http://www.golang.org/",
  25. },
  26. // one expansion, no escaping
  27. {
  28. "http://www.golang.org/{bucket}/delete",
  29. map[string]string{
  30. "bucket": "red",
  31. },
  32. "http://www.golang.org/red/delete",
  33. },
  34. // one expansion, with hex escapes
  35. {
  36. "http://www.golang.org/{bucket}/delete",
  37. map[string]string{
  38. "bucket": "red/blue",
  39. },
  40. "http://www.golang.org/red%2Fblue/delete",
  41. },
  42. // one expansion, with space
  43. {
  44. "http://www.golang.org/{bucket}/delete",
  45. map[string]string{
  46. "bucket": "red or blue",
  47. },
  48. "http://www.golang.org/red%20or%20blue/delete",
  49. },
  50. // expansion not found
  51. {
  52. "http://www.golang.org/{object}/delete",
  53. map[string]string{
  54. "bucket": "red or blue",
  55. },
  56. "http://www.golang.org//delete",
  57. },
  58. // multiple expansions
  59. {
  60. "http://www.golang.org/{one}/{two}/{three}/get",
  61. map[string]string{
  62. "one": "ONE",
  63. "two": "TWO",
  64. "three": "THREE",
  65. },
  66. "http://www.golang.org/ONE/TWO/THREE/get",
  67. },
  68. // utf-8 characters
  69. {
  70. "http://www.golang.org/{bucket}/get",
  71. map[string]string{
  72. "bucket": "£100",
  73. },
  74. "http://www.golang.org/%C2%A3100/get",
  75. },
  76. // punctuations
  77. {
  78. "http://www.golang.org/{bucket}/get",
  79. map[string]string{
  80. "bucket": `/\@:,.`,
  81. },
  82. "http://www.golang.org/%2F%5C%40%3A%2C./get",
  83. },
  84. // mis-matched brackets
  85. {
  86. "http://www.golang.org/{bucket/get",
  87. map[string]string{
  88. "bucket": "red",
  89. },
  90. "http://www.golang.org/%7Bbucket/get",
  91. },
  92. // "+" prefix for suppressing escape
  93. // See also: http://tools.ietf.org/html/rfc6570#section-3.2.3
  94. {
  95. "http://www.golang.org/{+topic}",
  96. map[string]string{
  97. "topic": "/topics/myproject/mytopic",
  98. },
  99. // The double slashes here look weird, but it's intentional
  100. "http://www.golang.org//topics/myproject/mytopic",
  101. },
  102. }
  103. func TestExpand(t *testing.T) {
  104. for i, test := range expandTests {
  105. u := url.URL{
  106. Path: test.in,
  107. }
  108. Expand(&u, test.expansions)
  109. got := u.EscapedPath()
  110. if got != test.want {
  111. t.Errorf("got %q expected %q in test %d", got, test.want, i+1)
  112. }
  113. }
  114. }
  115. func TestResolveRelative(t *testing.T) {
  116. resolveRelativeTests := []struct {
  117. basestr string
  118. relstr string
  119. want string
  120. }{
  121. {
  122. "http://www.golang.org/", "topics/myproject/mytopic",
  123. "http://www.golang.org/topics/myproject/mytopic",
  124. },
  125. {
  126. "http://www.golang.org/", "topics/{+myproject}/{release}:build:test:deploy",
  127. "http://www.golang.org/topics/{+myproject}/{release}:build:test:deploy",
  128. },
  129. {
  130. "https://www.googleapis.com/admin/reports/v1/", "/admin/reports_v1/channels/stop",
  131. "https://www.googleapis.com/admin/reports_v1/channels/stop",
  132. },
  133. {
  134. "https://www.googleapis.com/admin/directory/v1/", "customer/{customerId}/orgunits{/orgUnitPath*}",
  135. "https://www.googleapis.com/admin/directory/v1/customer/{customerId}/orgunits{/orgUnitPath*}",
  136. },
  137. {
  138. "https://www.googleapis.com/tagmanager/v2/", "accounts",
  139. "https://www.googleapis.com/tagmanager/v2/accounts",
  140. },
  141. {
  142. "https://www.googleapis.com/tagmanager/v2/", "{+parent}/workspaces",
  143. "https://www.googleapis.com/tagmanager/v2/{+parent}/workspaces",
  144. },
  145. {
  146. "https://www.googleapis.com/tagmanager/v2/", "{+path}:create_version",
  147. "https://www.googleapis.com/tagmanager/v2/{+path}:create_version",
  148. },
  149. }
  150. for i, test := range resolveRelativeTests {
  151. got := ResolveRelative(test.basestr, test.relstr)
  152. if got != test.want {
  153. t.Errorf("got %q expected %q in test %d", got, test.want, i+1)
  154. }
  155. }
  156. }
  157. type CheckResponseTest struct {
  158. in *http.Response
  159. bodyText string
  160. want error
  161. errText string
  162. }
  163. var checkResponseTests = []CheckResponseTest{
  164. {
  165. &http.Response{
  166. StatusCode: http.StatusOK,
  167. },
  168. "",
  169. nil,
  170. "",
  171. },
  172. {
  173. &http.Response{
  174. StatusCode: http.StatusInternalServerError,
  175. },
  176. `{"error":{}}`,
  177. &Error{
  178. Code: http.StatusInternalServerError,
  179. Body: `{"error":{}}`,
  180. },
  181. `googleapi: got HTTP response code 500 with body: {"error":{}}`,
  182. },
  183. {
  184. &http.Response{
  185. StatusCode: http.StatusNotFound,
  186. },
  187. `{"error":{"message":"Error message for StatusNotFound."}}`,
  188. &Error{
  189. Code: http.StatusNotFound,
  190. Message: "Error message for StatusNotFound.",
  191. Body: `{"error":{"message":"Error message for StatusNotFound."}}`,
  192. },
  193. "googleapi: Error 404: Error message for StatusNotFound.",
  194. },
  195. {
  196. &http.Response{
  197. StatusCode: http.StatusBadRequest,
  198. },
  199. `{"error":"invalid_token","error_description":"Invalid Value"}`,
  200. &Error{
  201. Code: http.StatusBadRequest,
  202. Body: `{"error":"invalid_token","error_description":"Invalid Value"}`,
  203. },
  204. `googleapi: got HTTP response code 400 with body: {"error":"invalid_token","error_description":"Invalid Value"}`,
  205. },
  206. {
  207. &http.Response{
  208. StatusCode: http.StatusBadRequest,
  209. },
  210. `{"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}}`,
  211. &Error{
  212. Code: http.StatusBadRequest,
  213. Errors: []ErrorItem{
  214. {
  215. Reason: "keyInvalid",
  216. Message: "Bad Request",
  217. },
  218. },
  219. Body: `{"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}}`,
  220. Message: "Bad Request",
  221. },
  222. "googleapi: Error 400: Bad Request, keyInvalid",
  223. },
  224. }
  225. func TestCheckResponse(t *testing.T) {
  226. for _, test := range checkResponseTests {
  227. res := test.in
  228. if test.bodyText != "" {
  229. res.Body = ioutil.NopCloser(strings.NewReader(test.bodyText))
  230. }
  231. g := CheckResponse(res)
  232. if !reflect.DeepEqual(g, test.want) {
  233. t.Errorf("CheckResponse: got %v, want %v", g, test.want)
  234. gotJson, err := json.Marshal(g)
  235. if err != nil {
  236. t.Error(err)
  237. }
  238. wantJson, err := json.Marshal(test.want)
  239. if err != nil {
  240. t.Error(err)
  241. }
  242. t.Errorf("json(got): %q\njson(want): %q", string(gotJson), string(wantJson))
  243. }
  244. if g != nil && g.Error() != test.errText {
  245. t.Errorf("CheckResponse: unexpected error message.\nGot: %q\nwant: %q", g, test.errText)
  246. }
  247. }
  248. }
  249. type VariantPoint struct {
  250. Type string
  251. Coordinates []float64
  252. }
  253. type VariantTest struct {
  254. in map[string]interface{}
  255. result bool
  256. want VariantPoint
  257. }
  258. var coords = []interface{}{1.0, 2.0}
  259. var variantTests = []VariantTest{
  260. {
  261. in: map[string]interface{}{
  262. "type": "Point",
  263. "coordinates": coords,
  264. },
  265. result: true,
  266. want: VariantPoint{
  267. Type: "Point",
  268. Coordinates: []float64{1.0, 2.0},
  269. },
  270. },
  271. {
  272. in: map[string]interface{}{
  273. "type": "Point",
  274. "bogus": coords,
  275. },
  276. result: true,
  277. want: VariantPoint{
  278. Type: "Point",
  279. },
  280. },
  281. }
  282. func TestVariantType(t *testing.T) {
  283. for _, test := range variantTests {
  284. if g := VariantType(test.in); g != test.want.Type {
  285. t.Errorf("VariantType(%v): got %v, want %v", test.in, g, test.want.Type)
  286. }
  287. }
  288. }
  289. func TestConvertVariant(t *testing.T) {
  290. for _, test := range variantTests {
  291. g := VariantPoint{}
  292. r := ConvertVariant(test.in, &g)
  293. if r != test.result {
  294. t.Errorf("ConvertVariant(%v): got %v, want %v", test.in, r, test.result)
  295. }
  296. if !reflect.DeepEqual(g, test.want) {
  297. t.Errorf("ConvertVariant(%v): got %v, want %v", test.in, g, test.want)
  298. }
  299. }
  300. }
  301. func TestRoundChunkSize(t *testing.T) {
  302. type testCase struct {
  303. in int
  304. want int
  305. }
  306. for _, tc := range []testCase{
  307. {0, 0},
  308. {256*1024 - 1, 256 * 1024},
  309. {256 * 1024, 256 * 1024},
  310. {256*1024 + 1, 2 * 256 * 1024},
  311. } {
  312. mo := &MediaOptions{}
  313. ChunkSize(tc.in).setOptions(mo)
  314. if got := mo.ChunkSize; got != tc.want {
  315. t.Errorf("rounding chunk size: got: %v; want %v", got, tc.want)
  316. }
  317. }
  318. }