yaml_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. // Copyright 2015 go-swagger maintainers
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package swag
  15. import (
  16. "encoding/json"
  17. "net/http"
  18. "net/http/httptest"
  19. "testing"
  20. "github.com/stretchr/testify/assert"
  21. yaml "gopkg.in/yaml.v2"
  22. )
  23. /* currently unused:
  24. type failJSONMarshal struct {
  25. }
  26. func (f failJSONMarshal) MarshalJSON() ([]byte, error) {
  27. return nil, errors.New("expected")
  28. }
  29. */
  30. func TestLoadHTTPBytes(t *testing.T) {
  31. _, err := LoadFromFileOrHTTP("httx://12394:abd")
  32. assert.Error(t, err)
  33. serv := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  34. rw.WriteHeader(http.StatusNotFound)
  35. }))
  36. defer serv.Close()
  37. _, err = LoadFromFileOrHTTP(serv.URL)
  38. assert.Error(t, err)
  39. ts2 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  40. rw.WriteHeader(http.StatusOK)
  41. _, _ = rw.Write([]byte("the content"))
  42. }))
  43. defer ts2.Close()
  44. d, err := LoadFromFileOrHTTP(ts2.URL)
  45. assert.NoError(t, err)
  46. assert.Equal(t, []byte("the content"), d)
  47. }
  48. func TestYAMLToJSON(t *testing.T) {
  49. sd := `---
  50. 1: the int key value
  51. name: a string value
  52. 'y': some value
  53. `
  54. var data yaml.MapSlice
  55. _ = yaml.Unmarshal([]byte(sd), &data)
  56. d, err := YAMLToJSON(data)
  57. if assert.NoError(t, err) {
  58. assert.Equal(t, `{"1":"the int key value","name":"a string value","y":"some value"}`, string(d))
  59. }
  60. data = append(data, yaml.MapItem{Key: true, Value: "the bool value"})
  61. d, err = YAMLToJSON(data)
  62. assert.Error(t, err)
  63. assert.Nil(t, d)
  64. data = data[:len(data)-1]
  65. tag := yaml.MapSlice{{Key: "name", Value: "tag name"}}
  66. data = append(data, yaml.MapItem{Key: "tag", Value: tag})
  67. d, err = YAMLToJSON(data)
  68. assert.NoError(t, err)
  69. assert.Equal(t, `{"1":"the int key value","name":"a string value","y":"some value","tag":{"name":"tag name"}}`, string(d))
  70. tag = yaml.MapSlice{{Key: true, Value: "bool tag name"}}
  71. data = append(data[:len(data)-1], yaml.MapItem{Key: "tag", Value: tag})
  72. d, err = YAMLToJSON(data)
  73. assert.Error(t, err)
  74. assert.Nil(t, d)
  75. var lst []interface{}
  76. lst = append(lst, "hello")
  77. d, err = YAMLToJSON(lst)
  78. assert.NoError(t, err)
  79. assert.Equal(t, []byte(`["hello"]`), []byte(d))
  80. lst = append(lst, data)
  81. d, err = YAMLToJSON(lst)
  82. assert.Error(t, err)
  83. assert.Nil(t, d)
  84. // _, err := yamlToJSON(failJSONMarhal{})
  85. // assert.Error(t, err)
  86. _, err = BytesToYAMLDoc([]byte("- name: hello\n"))
  87. assert.Error(t, err)
  88. dd, err := BytesToYAMLDoc([]byte("description: 'object created'\n"))
  89. assert.NoError(t, err)
  90. d, err = YAMLToJSON(dd)
  91. assert.NoError(t, err)
  92. assert.Equal(t, json.RawMessage(`{"description":"object created"}`), d)
  93. }
  94. func TestLoadStrategy(t *testing.T) {
  95. loader := func(p string) ([]byte, error) {
  96. return []byte(yamlPetStore), nil
  97. }
  98. remLoader := func(p string) ([]byte, error) {
  99. return []byte("not it"), nil
  100. }
  101. ld := LoadStrategy("blah", loader, remLoader)
  102. b, _ := ld("")
  103. assert.Equal(t, []byte(yamlPetStore), b)
  104. serv := httptest.NewServer(http.HandlerFunc(yamlPestoreServer))
  105. defer serv.Close()
  106. s, err := YAMLDoc(serv.URL)
  107. assert.NoError(t, err)
  108. assert.NotNil(t, s)
  109. ts2 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  110. rw.WriteHeader(http.StatusNotFound)
  111. _, _ = rw.Write([]byte("\n"))
  112. }))
  113. defer ts2.Close()
  114. _, err = YAMLDoc(ts2.URL)
  115. assert.Error(t, err)
  116. }
  117. var yamlPestoreServer = func(rw http.ResponseWriter, r *http.Request) {
  118. rw.WriteHeader(http.StatusOK)
  119. _, _ = rw.Write([]byte(yamlPetStore))
  120. }
  121. func TestWithYKey(t *testing.T) {
  122. doc, err := BytesToYAMLDoc([]byte(withYKey))
  123. if assert.NoError(t, err) {
  124. _, err := YAMLToJSON(doc)
  125. if assert.Error(t, err) {
  126. doc, err := BytesToYAMLDoc([]byte(withQuotedYKey))
  127. if assert.NoError(t, err) {
  128. jsond, err := YAMLToJSON(doc)
  129. if assert.NoError(t, err) {
  130. var yt struct {
  131. Definitions struct {
  132. Viewbox struct {
  133. Properties struct {
  134. Y struct {
  135. Type string `json:"type"`
  136. } `json:"y"`
  137. } `json:"properties"`
  138. } `json:"viewbox"`
  139. } `json:"definitions"`
  140. }
  141. if assert.NoError(t, json.Unmarshal(jsond, &yt)) {
  142. assert.Equal(t, "integer", yt.Definitions.Viewbox.Properties.Y.Type)
  143. }
  144. }
  145. }
  146. }
  147. }
  148. }
  149. func TestMapKeyTypes(t *testing.T) {
  150. d := yaml.MapSlice{
  151. yaml.MapItem{Key: 12345, Value: "int"},
  152. yaml.MapItem{Key: int8(1), Value: "int8"},
  153. yaml.MapItem{Key: int16(12345), Value: "int16"},
  154. yaml.MapItem{Key: int32(12345678), Value: "int32"},
  155. yaml.MapItem{Key: int64(12345678910), Value: "int64"},
  156. yaml.MapItem{Key: uint(12345), Value: "uint"},
  157. yaml.MapItem{Key: uint8(1), Value: "uint8"},
  158. yaml.MapItem{Key: uint16(12345), Value: "uint16"},
  159. yaml.MapItem{Key: uint32(12345678), Value: "uint32"},
  160. yaml.MapItem{Key: uint64(12345678910), Value: "uint64"},
  161. }
  162. _, err := YAMLToJSON(d)
  163. assert.NoError(t, err)
  164. dm := map[interface{}]interface{}{
  165. 12345: "int",
  166. int8(1): "int8",
  167. int16(12345): "int16",
  168. int32(12345678): "int32",
  169. int64(12345678910): "int64",
  170. uint(12345): "uint",
  171. uint8(1): "uint8",
  172. uint16(12345): "uint16",
  173. uint32(12345678): "uint32",
  174. uint64(12345678910): "uint64",
  175. }
  176. _, err = YAMLToJSON(dm)
  177. assert.NoError(t, err)
  178. }
  179. const withQuotedYKey = `consumes:
  180. - application/json
  181. definitions:
  182. viewBox:
  183. type: object
  184. properties:
  185. x:
  186. type: integer
  187. format: int16
  188. # y -> types don't match: expect map key string or int get: bool
  189. "y":
  190. type: integer
  191. format: int16
  192. width:
  193. type: integer
  194. format: int16
  195. height:
  196. type: integer
  197. format: int16
  198. info:
  199. description: Test RESTful APIs
  200. title: Test Server
  201. version: 1.0.0
  202. basePath: /api
  203. paths:
  204. /test:
  205. get:
  206. operationId: findAll
  207. parameters:
  208. - name: since
  209. in: query
  210. type: integer
  211. format: int64
  212. - name: limit
  213. in: query
  214. type: integer
  215. format: int32
  216. default: 20
  217. responses:
  218. 200:
  219. description: Array[Trigger]
  220. schema:
  221. type: array
  222. items:
  223. $ref: "#/definitions/viewBox"
  224. produces:
  225. - application/json
  226. schemes:
  227. - https
  228. swagger: "2.0"
  229. `
  230. const withYKey = `consumes:
  231. - application/json
  232. definitions:
  233. viewBox:
  234. type: object
  235. properties:
  236. x:
  237. type: integer
  238. format: int16
  239. # y -> types don't match: expect map key string or int get: bool
  240. y:
  241. type: integer
  242. format: int16
  243. width:
  244. type: integer
  245. format: int16
  246. height:
  247. type: integer
  248. format: int16
  249. info:
  250. description: Test RESTful APIs
  251. title: Test Server
  252. version: 1.0.0
  253. basePath: /api
  254. paths:
  255. /test:
  256. get:
  257. operationId: findAll
  258. parameters:
  259. - name: since
  260. in: query
  261. type: integer
  262. format: int64
  263. - name: limit
  264. in: query
  265. type: integer
  266. format: int32
  267. default: 20
  268. responses:
  269. 200:
  270. description: Array[Trigger]
  271. schema:
  272. type: array
  273. items:
  274. $ref: "#/definitions/viewBox"
  275. produces:
  276. - application/json
  277. schemes:
  278. - https
  279. swagger: "2.0"
  280. `
  281. const yamlPetStore = `swagger: '2.0'
  282. info:
  283. version: '1.0.0'
  284. title: Swagger Petstore
  285. description: A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification
  286. termsOfService: http://helloreverb.com/terms/
  287. contact:
  288. name: Swagger API team
  289. email: foo@example.com
  290. url: http://swagger.io
  291. license:
  292. name: MIT
  293. url: http://opensource.org/licenses/MIT
  294. host: petstore.swagger.wordnik.com
  295. basePath: /api
  296. schemes:
  297. - http
  298. consumes:
  299. - application/json
  300. produces:
  301. - application/json
  302. paths:
  303. /pets:
  304. get:
  305. description: Returns all pets from the system that the user has access to
  306. operationId: findPets
  307. produces:
  308. - application/json
  309. - application/xml
  310. - text/xml
  311. - text/html
  312. parameters:
  313. - name: tags
  314. in: query
  315. description: tags to filter by
  316. required: false
  317. type: array
  318. items:
  319. type: string
  320. collectionFormat: csv
  321. - name: limit
  322. in: query
  323. description: maximum number of results to return
  324. required: false
  325. type: integer
  326. format: int32
  327. responses:
  328. '200':
  329. description: pet response
  330. schema:
  331. type: array
  332. items:
  333. $ref: '#/definitions/pet'
  334. default:
  335. description: unexpected error
  336. schema:
  337. $ref: '#/definitions/errorModel'
  338. post:
  339. description: Creates a new pet in the store. Duplicates are allowed
  340. operationId: addPet
  341. produces:
  342. - application/json
  343. parameters:
  344. - name: pet
  345. in: body
  346. description: Pet to add to the store
  347. required: true
  348. schema:
  349. $ref: '#/definitions/newPet'
  350. responses:
  351. '200':
  352. description: pet response
  353. schema:
  354. $ref: '#/definitions/pet'
  355. default:
  356. description: unexpected error
  357. schema:
  358. $ref: '#/definitions/errorModel'
  359. /pets/{id}:
  360. get:
  361. description: Returns a user based on a single ID, if the user does not have access to the pet
  362. operationId: findPetById
  363. produces:
  364. - application/json
  365. - application/xml
  366. - text/xml
  367. - text/html
  368. parameters:
  369. - name: id
  370. in: path
  371. description: ID of pet to fetch
  372. required: true
  373. type: integer
  374. format: int64
  375. responses:
  376. '200':
  377. description: pet response
  378. schema:
  379. $ref: '#/definitions/pet'
  380. default:
  381. description: unexpected error
  382. schema:
  383. $ref: '#/definitions/errorModel'
  384. delete:
  385. description: deletes a single pet based on the ID supplied
  386. operationId: deletePet
  387. parameters:
  388. - name: id
  389. in: path
  390. description: ID of pet to delete
  391. required: true
  392. type: integer
  393. format: int64
  394. responses:
  395. '204':
  396. description: pet deleted
  397. default:
  398. description: unexpected error
  399. schema:
  400. $ref: '#/definitions/errorModel'
  401. definitions:
  402. pet:
  403. required:
  404. - id
  405. - name
  406. properties:
  407. id:
  408. type: integer
  409. format: int64
  410. name:
  411. type: string
  412. tag:
  413. type: string
  414. newPet:
  415. allOf:
  416. - $ref: '#/definitions/pet'
  417. - required:
  418. - name
  419. properties:
  420. id:
  421. type: integer
  422. format: int64
  423. name:
  424. type: string
  425. errorModel:
  426. required:
  427. - code
  428. - message
  429. properties:
  430. code:
  431. type: integer
  432. format: int32
  433. message:
  434. type: string
  435. `