bytes_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. package jsonpointer
  2. import (
  3. "compress/gzip"
  4. "io/ioutil"
  5. "math/rand"
  6. "os"
  7. "reflect"
  8. "strings"
  9. "testing"
  10. "testing/quick"
  11. "github.com/dustin/gojson"
  12. )
  13. var ptests = []struct {
  14. path string
  15. exp interface{}
  16. }{
  17. {"/foo", []interface{}{"bar", "baz"}},
  18. {"/foo/0", "bar"},
  19. {"/", 0.0},
  20. {"/a~1b", 1.0},
  21. {"/c%d", 2.0},
  22. {"/e^f", 3.0},
  23. {"/g|h", 4.0},
  24. {"/i\\j", 5.0},
  25. {"/k\"l", 6.0},
  26. {"/ ", 7.0},
  27. {"/m~0n", 8.0},
  28. {"/g~1n~1r", "has slash, will travel"},
  29. {"/g/n/r", "where's tito?"},
  30. }
  31. func TestFindDecode(t *testing.T) {
  32. in := []byte(objSrc)
  33. var fl float64
  34. if err := FindDecode(in, "/g|h", &fl); err != nil {
  35. t.Errorf("Failed to decode /g|h: %v", err)
  36. }
  37. if fl != 4.0 {
  38. t.Errorf("Expected 4.0 at /g|h, got %v", fl)
  39. }
  40. fl = 0
  41. if err := FindDecode(in, "/z", &fl); err == nil {
  42. t.Errorf("Expected failure to decode /z: got %v", fl)
  43. }
  44. if err := FindDecode([]byte(`{"a": 1.x35}`), "/a", &fl); err == nil {
  45. t.Errorf("Expected failure, got %v", fl)
  46. }
  47. }
  48. func TestListPointers(t *testing.T) {
  49. got, err := ListPointers(nil)
  50. if err == nil {
  51. t.Errorf("Expected error on nil input, got %v", got)
  52. }
  53. got, err = ListPointers([]byte(`{"x": {"y"}}`))
  54. if err == nil {
  55. t.Errorf("Expected error on broken input, got %v", got)
  56. }
  57. got, err = ListPointers([]byte(objSrc))
  58. if err != nil {
  59. t.Fatalf("Error getting list of pointers: %v", err)
  60. }
  61. exp := []string{"", "/foo", "/foo/0", "/foo/1", "/", "/a~1b",
  62. "/c%d", "/e^f", "/g|h", "/i\\j", "/k\"l", "/ ", "/m~0n",
  63. "/g~1n~1r", "/g", "/g/n", "/g/n/r",
  64. }
  65. if !reflect.DeepEqual(exp, got) {
  66. t.Fatalf("Expected\n%#v\ngot\n%#v", exp, got)
  67. }
  68. }
  69. func TestPointerRoot(t *testing.T) {
  70. got, err := Find([]byte(objSrc), "")
  71. if err != nil {
  72. t.Fatalf("Error finding root: %v", err)
  73. }
  74. if !reflect.DeepEqual([]byte(objSrc), got) {
  75. t.Fatalf("Error finding root, found\n%s\n, wanted\n%s",
  76. got, objSrc)
  77. }
  78. }
  79. func TestPointerManyRoot(t *testing.T) {
  80. got, err := FindMany([]byte(objSrc), []string{""})
  81. if err != nil {
  82. t.Fatalf("Error finding root: %v", err)
  83. }
  84. if !reflect.DeepEqual([]byte(objSrc), got[""]) {
  85. t.Fatalf("Error finding root, found\n%s\n, wanted\n%s",
  86. got, objSrc)
  87. }
  88. }
  89. func TestPointerManyBroken(t *testing.T) {
  90. got, err := FindMany([]byte(`{"a": {"b": "something}}`), []string{"/a/b"})
  91. if err == nil {
  92. t.Errorf("Expected error parsing broken JSON, got %v", got)
  93. }
  94. }
  95. func TestPointerMissing(t *testing.T) {
  96. got, err := Find([]byte(objSrc), "/missing")
  97. if err != nil {
  98. t.Fatalf("Error finding missing item: %v", err)
  99. }
  100. if got != nil {
  101. t.Fatalf("Expected nil looking for /missing, got %v",
  102. got)
  103. }
  104. }
  105. func TestManyPointers(t *testing.T) {
  106. pointers := []string{}
  107. exp := map[string]interface{}{}
  108. for _, test := range ptests {
  109. pointers = append(pointers, test.path)
  110. exp[test.path] = test.exp
  111. }
  112. rv, err := FindMany([]byte(objSrc), pointers)
  113. if err != nil {
  114. t.Fatalf("Error finding many: %v", err)
  115. }
  116. got := map[string]interface{}{}
  117. for k, v := range rv {
  118. var val interface{}
  119. err = json.Unmarshal(v, &val)
  120. if err != nil {
  121. t.Fatalf("Error unmarshaling %s: %v", v, err)
  122. }
  123. got[k] = val
  124. }
  125. if !reflect.DeepEqual(got, exp) {
  126. for k, v := range exp {
  127. if !reflect.DeepEqual(got[k], v) {
  128. t.Errorf("At %v, expected %#v, got %#v", k, v, got[k])
  129. }
  130. }
  131. t.Fail()
  132. }
  133. }
  134. func TestManyPointersMissing(t *testing.T) {
  135. got, err := FindMany([]byte(objSrc), []string{"/missing"})
  136. if err != nil {
  137. t.Fatalf("Error finding missing item: %v", err)
  138. }
  139. if len(got) != 0 {
  140. t.Fatalf("Expected empty looking for many /missing, got %v",
  141. got)
  142. }
  143. }
  144. var badDocs = [][]byte{
  145. []byte{}, []byte(" "), nil,
  146. []byte{'{'}, []byte{'['},
  147. []byte{'}'}, []byte{']'},
  148. }
  149. func TestManyPointersBadDoc(t *testing.T) {
  150. for _, b := range badDocs {
  151. got, _ := FindMany(b, []string{"/broken"})
  152. if len(got) > 0 {
  153. t.Errorf("Expected failure on %v, got %v", b, got)
  154. }
  155. }
  156. }
  157. func TestPointersBadDoc(t *testing.T) {
  158. for _, b := range badDocs {
  159. got, _ := Find(b, "/broken")
  160. if len(got) > 0 {
  161. t.Errorf("Expected failure on %s, got %v", b, got)
  162. }
  163. }
  164. }
  165. func TestPointer(t *testing.T) {
  166. for _, test := range ptests {
  167. got, err := Find([]byte(objSrc), test.path)
  168. var val interface{}
  169. if err == nil {
  170. err = json.Unmarshal([]byte(got), &val)
  171. }
  172. if err != nil {
  173. t.Errorf("Got an error on key %v: %v", test.path, err)
  174. } else if !reflect.DeepEqual(val, test.exp) {
  175. t.Errorf("On %#v, expected %+v (%T), got %+v (%T)",
  176. test.path, test.exp, test.exp, val, val)
  177. } else {
  178. t.Logf("Success - got %s for %#v", got, test.path)
  179. }
  180. }
  181. }
  182. func TestPointerCoder(t *testing.T) {
  183. tests := map[string][]string{
  184. "/": []string{""},
  185. "/a": []string{"a"},
  186. "/a~1b": []string{"a/b"},
  187. "/m~0n": []string{"m~n"},
  188. "/ ": []string{" "},
  189. "/g~1n~1r": []string{"g/n/r"},
  190. "/g/n/r": []string{"g", "n", "r"},
  191. }
  192. for k, v := range tests {
  193. parsed := parsePointer(k)
  194. encoded := encodePointer(v)
  195. if k != encoded {
  196. t.Errorf("Expected to encode %#v as %#v, got %#v",
  197. v, k, encoded)
  198. }
  199. if !arreq(v, parsed) {
  200. t.Errorf("Expected to decode %#v as %#v, got %#v",
  201. k, v, parsed)
  202. }
  203. }
  204. }
  205. func TestCBugg406(t *testing.T) {
  206. data, err := ioutil.ReadFile("testdata/pools.json")
  207. if err != nil {
  208. t.Fatalf("Error reading pools data: %v", err)
  209. }
  210. found, err := Find(data, "/implementationVersion")
  211. if err != nil {
  212. t.Fatalf("Failed to find thing: %v", err)
  213. }
  214. exp := ` "2.0.0-1976-rel-enterprise"`
  215. if string(found) != exp {
  216. t.Fatalf("Expected %q, got %q", exp, found)
  217. }
  218. }
  219. func BenchmarkEncodePointer(b *testing.B) {
  220. aPath := []string{"a", "ab", "a~0b", "a~1b", "a~0~1~0~1b"}
  221. for i := 0; i < b.N; i++ {
  222. encodePointer(aPath)
  223. }
  224. }
  225. func BenchmarkAll(b *testing.B) {
  226. obj := []byte(objSrc)
  227. for i := 0; i < b.N; i++ {
  228. for _, test := range tests {
  229. Find(obj, test.path)
  230. }
  231. }
  232. }
  233. func BenchmarkManyPointer(b *testing.B) {
  234. pointers := []string{}
  235. for _, test := range ptests {
  236. pointers = append(pointers, test.path)
  237. }
  238. obj := []byte(objSrc)
  239. b.ResetTimer()
  240. for i := 0; i < b.N; i++ {
  241. FindMany(obj, pointers)
  242. }
  243. }
  244. func TestMustParseInt(t *testing.T) {
  245. tests := map[string]bool{
  246. "": true,
  247. "0": false,
  248. "13": false,
  249. }
  250. for in, out := range tests {
  251. var panicked bool
  252. func() {
  253. defer func() {
  254. panicked = recover() != nil
  255. }()
  256. mustParseInt(in)
  257. if panicked != out {
  258. t.Logf("Expected panicked=%v", panicked)
  259. }
  260. }()
  261. }
  262. }
  263. func TestFindBrokenJSON(t *testing.T) {
  264. x, err := Find([]byte(`{]`), "/foo/x")
  265. if err == nil {
  266. t.Errorf("Expected error, got %q", x)
  267. }
  268. }
  269. func TestGrokLiteral(t *testing.T) {
  270. brokenStr := "---broken---"
  271. tests := []struct {
  272. in []byte
  273. exp string
  274. }{
  275. {[]byte(`"simple"`), "simple"},
  276. {[]byte(`"has\nnewline"`), "has\nnewline"},
  277. {[]byte(`"broken`), brokenStr},
  278. }
  279. for _, test := range tests {
  280. var got string
  281. func() {
  282. defer func() {
  283. if e := recover(); e != nil {
  284. got = brokenStr
  285. }
  286. }()
  287. got = grokLiteral(test.in)
  288. }()
  289. if test.exp != got {
  290. t.Errorf("Expected %q for %s, got %q",
  291. test.exp, test.in, got)
  292. }
  293. }
  294. }
  295. func TestSerieslySample(t *testing.T) {
  296. data, err := ioutil.ReadFile("testdata/serieslysample.json")
  297. if err != nil {
  298. t.Fatalf("Error opening sample file: %v", err)
  299. }
  300. tests := []struct {
  301. pointer string
  302. exp string
  303. }{
  304. {"/kind", "Listing"},
  305. {"/data/children/0/data/id", "w568e"},
  306. {"/data/children/0/data/name", "t3_w568e"},
  307. }
  308. for _, test := range tests {
  309. var found string
  310. err := FindDecode(data, test.pointer, &found)
  311. if err != nil {
  312. t.Errorf("Error on %v: %v", test.pointer, err)
  313. }
  314. if found != test.exp {
  315. t.Errorf("Expected %q, got %q", test.exp, found)
  316. }
  317. }
  318. }
  319. func TestSerieslySampleMany(t *testing.T) {
  320. data, err := ioutil.ReadFile("testdata/serieslysample.json")
  321. if err != nil {
  322. t.Fatalf("Error opening sample file: %v", err)
  323. }
  324. keys := []string{"/kind", "/data/children/0/data/id", "/data/children/0/data/name"}
  325. exp := []string{` "Listing"`, ` "w568e"`, ` "t3_w568e"`}
  326. found, err := FindMany(data, keys)
  327. if err != nil {
  328. t.Fatalf("Error in FindMany: %v", err)
  329. }
  330. for i, k := range keys {
  331. if string(found[k]) != exp[i] {
  332. t.Errorf("Expected %q on %q, got %q", exp[i], k, found[k])
  333. }
  334. }
  335. }
  336. func TestSerieslySampleList(t *testing.T) {
  337. data, err := ioutil.ReadFile("testdata/serieslysample.json")
  338. if err != nil {
  339. t.Fatalf("Error opening sample file: %v", err)
  340. }
  341. pointers, err := ListPointers(data)
  342. if err != nil {
  343. t.Fatalf("Error listing pointers: %v", err)
  344. }
  345. exp := 932
  346. if len(pointers) != exp {
  347. t.Fatalf("Expected %v pointers, got %v", exp, len(pointers))
  348. }
  349. }
  350. func Test357ListPointers(t *testing.T) {
  351. data, err := ioutil.ReadFile("testdata/357.json")
  352. if err != nil {
  353. t.Fatalf("Error beer-sample brewery 357 data: %v", err)
  354. }
  355. exp := []string{"", "/name", "/city", "/state", "/code",
  356. "/country", "/phone", "/website", "/type", "/updated",
  357. "/description",
  358. "/address", "/address/0", "/address2",
  359. "/address2/0", "/address3", "/address3/0"}
  360. got, err := ListPointers(data)
  361. if err != nil {
  362. t.Fatalf("error listing pointers: %v", err)
  363. }
  364. if !reflect.DeepEqual(exp, got) {
  365. t.Fatalf("Expected\n%#v\ngot\n%#v", exp, got)
  366. }
  367. }
  368. func TestEscape(t *testing.T) {
  369. tests := []string{
  370. "/", "~1", "~0", "/~1", "/~1/",
  371. }
  372. for _, test := range tests {
  373. esc := string(escape(test, nil))
  374. got := unescape(esc)
  375. if got != test {
  376. t.Errorf("unescape(escape(%q) [%q]) = %q", test, esc, got)
  377. }
  378. }
  379. tf := func(s chars) bool {
  380. uns := unescape(string(s))
  381. got := string(escape(uns, nil))
  382. return got == string(s)
  383. }
  384. quick.Check(tf, nil)
  385. }
  386. func TestUnescape(t *testing.T) {
  387. tests := []struct {
  388. in, exp string
  389. }{
  390. {"", ""},
  391. {"/", "/"},
  392. {"/thing", "/thing"},
  393. {"~0", "~"},
  394. {"~1", "/"},
  395. {"~2", "~2"},
  396. {"~", "~"},
  397. {"thing~", "thing~"},
  398. }
  399. for _, test := range tests {
  400. got := string(unescape(test.in))
  401. if got != test.exp {
  402. t.Errorf("on %q, got %q, wanted %q", test.in, got, test.exp)
  403. }
  404. }
  405. }
  406. var codeJSON []byte
  407. func init() {
  408. f, err := os.Open("testdata/code.json.gz")
  409. if err != nil {
  410. panic(err)
  411. }
  412. defer f.Close()
  413. gz, err := gzip.NewReader(f)
  414. if err != nil {
  415. panic(err)
  416. }
  417. data, err := ioutil.ReadAll(gz)
  418. if err != nil {
  419. panic(err)
  420. }
  421. codeJSON = data
  422. }
  423. func BenchmarkLarge3Key(b *testing.B) {
  424. keys := []string{
  425. "/tree/kids/0/kids/0/name",
  426. "/tree/kids/0/name",
  427. "/tree/kids/0/kids/0/kids/0/kids/0/kids/0/name",
  428. }
  429. b.SetBytes(int64(len(codeJSON)))
  430. for i := 0; i < b.N; i++ {
  431. found, err := FindMany(codeJSON, keys)
  432. if err != nil || len(found) != 3 {
  433. b.Fatalf("Didn't find all the things from %v/%v",
  434. found, err)
  435. }
  436. }
  437. }
  438. func BenchmarkLargeShallow(b *testing.B) {
  439. keys := []string{
  440. "/tree/kids/0/kids/0/kids/1/kids/1/kids/3/name",
  441. }
  442. b.SetBytes(int64(len(codeJSON)))
  443. for i := 0; i < b.N; i++ {
  444. found, err := FindMany(codeJSON, keys)
  445. if err != nil || len(found) != 1 {
  446. b.Fatalf("Didn't find all the things: %v/%v",
  447. found, err)
  448. }
  449. }
  450. }
  451. func BenchmarkLargeMissing(b *testing.B) {
  452. keys := []string{
  453. "/this/does/not/exist",
  454. }
  455. b.SetBytes(int64(len(codeJSON)))
  456. for i := 0; i < b.N; i++ {
  457. found, err := FindMany(codeJSON, keys)
  458. if err != nil || len(found) != 0 {
  459. b.Fatalf("Didn't find all the things: %v/%v",
  460. found, err)
  461. }
  462. }
  463. }
  464. func BenchmarkLargeIdentity(b *testing.B) {
  465. keys := []string{
  466. "",
  467. }
  468. b.SetBytes(int64(len(codeJSON)))
  469. for i := 0; i < b.N; i++ {
  470. found, err := FindMany(codeJSON, keys)
  471. if err != nil || len(found) != 1 {
  472. b.Fatalf("Didn't find all the things: %v/%v",
  473. found, err)
  474. }
  475. }
  476. }
  477. func BenchmarkLargeBest(b *testing.B) {
  478. keys := []string{
  479. "/tree/name",
  480. }
  481. b.SetBytes(int64(len(codeJSON)))
  482. for i := 0; i < b.N; i++ {
  483. found, err := FindMany(codeJSON, keys)
  484. if err != nil || len(found) != 1 {
  485. b.Fatalf("Didn't find all the things: %v/%v",
  486. found, err)
  487. }
  488. }
  489. }
  490. const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01233456789/~."
  491. type chars string
  492. func (c chars) Generate(rand *rand.Rand, _ int) reflect.Value {
  493. size := rand.Intn(128)
  494. var o []byte
  495. for i := 0; i < size; i++ {
  496. o = append(o, alphabet[rand.Intn(len(alphabet))])
  497. }
  498. s := chars(escape(string(o), nil))
  499. return reflect.ValueOf(s)
  500. }
  501. // unescape unescapes a tilde escaped string.
  502. //
  503. // It's dumb looking, but it benches faster than strings.NewReplacer
  504. func oldunescape(s string) string {
  505. return strings.Replace(strings.Replace(s, "~1", "/", -1), "~0", "~", -1)
  506. }
  507. func TestNewEscaper(t *testing.T) {
  508. of := func(in chars) string {
  509. return oldunescape(string(in))
  510. }
  511. nf := func(in chars) string {
  512. return unescape(string(in))
  513. }
  514. if err := quick.CheckEqual(of, nf, nil); err != nil {
  515. t.Errorf("quickcheck failure: %v", err)
  516. }
  517. }
  518. func BenchmarkLargeMap(b *testing.B) {
  519. keys := []string{
  520. "/tree/kids/0/kids/0/kids/0/kids/0/kids/0/name",
  521. }
  522. b.SetBytes(int64(len(codeJSON)))
  523. for i := 0; i < b.N; i++ {
  524. m := map[string]interface{}{}
  525. err := json.Unmarshal(codeJSON, &m)
  526. if err != nil {
  527. b.Fatalf("Error parsing JSON: %v", err)
  528. }
  529. Get(m, keys[0])
  530. }
  531. }
  532. const (
  533. tildeTestKey = "/name~0contained"
  534. slashTestKey = "/name~1contained"
  535. twoTestKey = "/name~1cont~0ned"
  536. )
  537. func testDoubleReplacer(s string) string {
  538. return unescape(s)
  539. }
  540. func BenchmarkReplacerSlash(b *testing.B) {
  541. r := strings.NewReplacer("~1", "/", "~0", "~")
  542. for i := 0; i < b.N; i++ {
  543. r.Replace(slashTestKey)
  544. }
  545. }
  546. func BenchmarkReplacerTilde(b *testing.B) {
  547. r := strings.NewReplacer("~1", "/", "~0", "~")
  548. for i := 0; i < b.N; i++ {
  549. r.Replace(tildeTestKey)
  550. }
  551. }
  552. func BenchmarkDblReplacerSlash(b *testing.B) {
  553. for i := 0; i < b.N; i++ {
  554. testDoubleReplacer(slashTestKey)
  555. }
  556. }
  557. func BenchmarkDblReplacerTilde(b *testing.B) {
  558. for i := 0; i < b.N; i++ {
  559. testDoubleReplacer(tildeTestKey)
  560. }
  561. }
  562. func BenchmarkDblReplacerTwo(b *testing.B) {
  563. for i := 0; i < b.N; i++ {
  564. testDoubleReplacer(twoTestKey)
  565. }
  566. }