unicode_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. // Copyright 2015 The Go Authors. 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 unicode
  5. import (
  6. "testing"
  7. "golang.org/x/text/encoding"
  8. "golang.org/x/text/encoding/charmap"
  9. "golang.org/x/text/encoding/internal/enctest"
  10. "golang.org/x/text/transform"
  11. )
  12. func TestBasics(t *testing.T) {
  13. testCases := []struct {
  14. e encoding.Encoding
  15. encPrefix string
  16. encSuffix string
  17. encoded string
  18. utf8 string
  19. }{{
  20. e: utf16BEIB,
  21. encoded: "\x00\x57\x00\xe4\xd8\x35\xdd\x65",
  22. utf8: "\x57\u00e4\U0001d565",
  23. }, {
  24. e: utf16BEEB,
  25. encPrefix: "\xfe\xff",
  26. encoded: "\x00\x57\x00\xe4\xd8\x35\xdd\x65",
  27. utf8: "\x57\u00e4\U0001d565",
  28. }, {
  29. e: utf16LEIB,
  30. encoded: "\x57\x00\xe4\x00\x35\xd8\x65\xdd",
  31. utf8: "\x57\u00e4\U0001d565",
  32. }, {
  33. e: utf16LEEB,
  34. encPrefix: "\xff\xfe",
  35. encoded: "\x57\x00\xe4\x00\x35\xd8\x65\xdd",
  36. utf8: "\x57\u00e4\U0001d565",
  37. }}
  38. for _, tc := range testCases {
  39. enctest.TestEncoding(t, tc.e, tc.encoded, tc.utf8, tc.encPrefix, tc.encSuffix)
  40. }
  41. }
  42. func TestFiles(t *testing.T) {
  43. enctest.TestFile(t, UTF8)
  44. enctest.TestFile(t, utf16LEIB)
  45. }
  46. func BenchmarkEncoding(b *testing.B) {
  47. enctest.Benchmark(b, UTF8)
  48. enctest.Benchmark(b, utf16LEIB)
  49. }
  50. var (
  51. utf16LEIB = UTF16(LittleEndian, IgnoreBOM) // UTF-16LE (atypical interpretation)
  52. utf16LEUB = UTF16(LittleEndian, UseBOM) // UTF-16, LE
  53. utf16LEEB = UTF16(LittleEndian, ExpectBOM) // UTF-16, LE, Expect
  54. utf16BEIB = UTF16(BigEndian, IgnoreBOM) // UTF-16BE (atypical interpretation)
  55. utf16BEUB = UTF16(BigEndian, UseBOM) // UTF-16 default
  56. utf16BEEB = UTF16(BigEndian, ExpectBOM) // UTF-16 Expect
  57. )
  58. func TestUTF16(t *testing.T) {
  59. testCases := []struct {
  60. desc string
  61. src string
  62. notEOF bool // the inverse of atEOF
  63. sizeDst int
  64. want string
  65. nSrc int
  66. err error
  67. t transform.Transformer
  68. }{{
  69. desc: "utf-16 IgnoreBOM dec: empty string",
  70. t: utf16BEIB.NewDecoder(),
  71. }, {
  72. desc: "utf-16 UseBOM dec: empty string",
  73. t: utf16BEUB.NewDecoder(),
  74. }, {
  75. desc: "utf-16 ExpectBOM dec: empty string",
  76. err: ErrMissingBOM,
  77. t: utf16BEEB.NewDecoder(),
  78. }, {
  79. desc: "utf-16 dec: BOM determines encoding BE (RFC 2781:3.3)",
  80. src: "\xFE\xFF\xD8\x08\xDF\x45\x00\x3D\x00\x52\x00\x61",
  81. sizeDst: 100,
  82. want: "\U00012345=Ra",
  83. nSrc: 12,
  84. t: utf16BEUB.NewDecoder(),
  85. }, {
  86. desc: "utf-16 dec: BOM determines encoding LE (RFC 2781:3.3)",
  87. src: "\xFF\xFE\x08\xD8\x45\xDF\x3D\x00\x52\x00\x61\x00",
  88. sizeDst: 100,
  89. want: "\U00012345=Ra",
  90. nSrc: 12,
  91. t: utf16LEUB.NewDecoder(),
  92. }, {
  93. desc: "utf-16 dec: BOM determines encoding LE, change default (RFC 2781:3.3)",
  94. src: "\xFF\xFE\x08\xD8\x45\xDF\x3D\x00\x52\x00\x61\x00",
  95. sizeDst: 100,
  96. want: "\U00012345=Ra",
  97. nSrc: 12,
  98. t: utf16BEUB.NewDecoder(),
  99. }, {
  100. desc: "utf-16 dec: Fail on missing BOM when required",
  101. src: "\x08\xD8\x45\xDF\x3D\x00\xFF\xFE\xFE\xFF\x00\x52\x00\x61",
  102. sizeDst: 100,
  103. want: "",
  104. nSrc: 0,
  105. err: ErrMissingBOM,
  106. t: utf16BEEB.NewDecoder(),
  107. }, {
  108. desc: "utf-16 dec: SHOULD interpret text as big-endian when BOM not present (RFC 2781:4.3)",
  109. src: "\xD8\x08\xDF\x45\x00\x3D\x00\x52\x00\x61",
  110. sizeDst: 100,
  111. want: "\U00012345=Ra",
  112. nSrc: 10,
  113. t: utf16BEUB.NewDecoder(),
  114. }, {
  115. // This is an error according to RFC 2781. But errors in RFC 2781 are
  116. // open to interpretations, so I guess this is fine.
  117. desc: "utf-16le dec: incorrect BOM is an error (RFC 2781:4.1)",
  118. src: "\xFE\xFF\x08\xD8\x45\xDF\x3D\x00\x52\x00\x61\x00",
  119. sizeDst: 100,
  120. want: "\uFFFE\U00012345=Ra",
  121. nSrc: 12,
  122. t: utf16LEIB.NewDecoder(),
  123. }, {
  124. desc: "utf-16 enc: SHOULD write BOM (RFC 2781:3.3)",
  125. src: "\U00012345=Ra",
  126. sizeDst: 100,
  127. want: "\xFF\xFE\x08\xD8\x45\xDF\x3D\x00\x52\x00\x61\x00",
  128. nSrc: 7,
  129. t: utf16LEUB.NewEncoder(),
  130. }, {
  131. desc: "utf-16 enc: SHOULD write BOM (RFC 2781:3.3)",
  132. src: "\U00012345=Ra",
  133. sizeDst: 100,
  134. want: "\xFE\xFF\xD8\x08\xDF\x45\x00\x3D\x00\x52\x00\x61",
  135. nSrc: 7,
  136. t: utf16BEUB.NewEncoder(),
  137. }, {
  138. desc: "utf-16le enc: MUST NOT write BOM (RFC 2781:3.3)",
  139. src: "\U00012345=Ra",
  140. sizeDst: 100,
  141. want: "\x08\xD8\x45\xDF\x3D\x00\x52\x00\x61\x00",
  142. nSrc: 7,
  143. t: utf16LEIB.NewEncoder(),
  144. }, {
  145. desc: "utf-16be dec: incorrect UTF-16: odd bytes",
  146. src: "\x00",
  147. sizeDst: 100,
  148. want: "\uFFFD",
  149. nSrc: 1,
  150. t: utf16BEIB.NewDecoder(),
  151. }, {
  152. desc: "utf-16be dec: unpaired surrogate, odd bytes",
  153. src: "\xD8\x45\x00",
  154. sizeDst: 100,
  155. want: "\uFFFD\uFFFD",
  156. nSrc: 3,
  157. t: utf16BEIB.NewDecoder(),
  158. }, {
  159. desc: "utf-16be dec: unpaired low surrogate + valid text",
  160. src: "\xD8\x45\x00a",
  161. sizeDst: 100,
  162. want: "\uFFFDa",
  163. nSrc: 4,
  164. t: utf16BEIB.NewDecoder(),
  165. }, {
  166. desc: "utf-16be dec: unpaired low surrogate + valid text + single byte",
  167. src: "\xD8\x45\x00ab",
  168. sizeDst: 100,
  169. want: "\uFFFDa\uFFFD",
  170. nSrc: 5,
  171. t: utf16BEIB.NewDecoder(),
  172. }, {
  173. desc: "utf-16le dec: unpaired high surrogate",
  174. src: "\x00\x00\x00\xDC\x12\xD8",
  175. sizeDst: 100,
  176. want: "\x00\uFFFD\uFFFD",
  177. nSrc: 6,
  178. t: utf16LEIB.NewDecoder(),
  179. }, {
  180. desc: "utf-16be dec: two unpaired low surrogates",
  181. src: "\xD8\x45\xD8\x12",
  182. sizeDst: 100,
  183. want: "\uFFFD\uFFFD",
  184. nSrc: 4,
  185. t: utf16BEIB.NewDecoder(),
  186. }, {
  187. desc: "utf-16be dec: short dst",
  188. src: "\x00a",
  189. sizeDst: 0,
  190. want: "",
  191. nSrc: 0,
  192. t: utf16BEIB.NewDecoder(),
  193. err: transform.ErrShortDst,
  194. }, {
  195. desc: "utf-16be dec: short dst surrogate",
  196. src: "\xD8\xF5\xDC\x12",
  197. sizeDst: 3,
  198. want: "",
  199. nSrc: 0,
  200. t: utf16BEIB.NewDecoder(),
  201. err: transform.ErrShortDst,
  202. }, {
  203. desc: "utf-16be dec: short dst trailing byte",
  204. src: "\x00",
  205. sizeDst: 2,
  206. want: "",
  207. nSrc: 0,
  208. t: utf16BEIB.NewDecoder(),
  209. err: transform.ErrShortDst,
  210. }, {
  211. desc: "utf-16be dec: short src",
  212. src: "\x00",
  213. notEOF: true,
  214. sizeDst: 3,
  215. want: "",
  216. nSrc: 0,
  217. t: utf16BEIB.NewDecoder(),
  218. err: transform.ErrShortSrc,
  219. }, {
  220. desc: "utf-16 enc",
  221. src: "\U00012345=Ra",
  222. sizeDst: 100,
  223. want: "\xFE\xFF\xD8\x08\xDF\x45\x00\x3D\x00\x52\x00\x61",
  224. nSrc: 7,
  225. t: utf16BEUB.NewEncoder(),
  226. }, {
  227. desc: "utf-16 enc: short dst normal",
  228. src: "\U00012345=Ra",
  229. sizeDst: 9,
  230. want: "\xD8\x08\xDF\x45\x00\x3D\x00\x52",
  231. nSrc: 6,
  232. t: utf16BEIB.NewEncoder(),
  233. err: transform.ErrShortDst,
  234. }, {
  235. desc: "utf-16 enc: short dst surrogate",
  236. src: "\U00012345=Ra",
  237. sizeDst: 3,
  238. want: "",
  239. nSrc: 0,
  240. t: utf16BEIB.NewEncoder(),
  241. err: transform.ErrShortDst,
  242. }, {
  243. desc: "utf-16 enc: short src",
  244. src: "\U00012345=Ra\xC2",
  245. notEOF: true,
  246. sizeDst: 100,
  247. want: "\xD8\x08\xDF\x45\x00\x3D\x00\x52\x00\x61",
  248. nSrc: 7,
  249. t: utf16BEIB.NewEncoder(),
  250. err: transform.ErrShortSrc,
  251. }, {
  252. desc: "utf-16be dec: don't change byte order mid-stream",
  253. src: "\xFE\xFF\xD8\x08\xDF\x45\x00\x3D\xFF\xFE\x00\x52\x00\x61",
  254. sizeDst: 100,
  255. want: "\U00012345=\ufffeRa",
  256. nSrc: 14,
  257. t: utf16BEUB.NewDecoder(),
  258. }, {
  259. desc: "utf-16le dec: don't change byte order mid-stream",
  260. src: "\xFF\xFE\x08\xD8\x45\xDF\x3D\x00\xFF\xFE\xFE\xFF\x52\x00\x61\x00",
  261. sizeDst: 100,
  262. want: "\U00012345=\ufeff\ufffeRa",
  263. nSrc: 16,
  264. t: utf16LEUB.NewDecoder(),
  265. }}
  266. for i, tc := range testCases {
  267. b := make([]byte, tc.sizeDst)
  268. nDst, nSrc, err := tc.t.Transform(b, []byte(tc.src), !tc.notEOF)
  269. if err != tc.err {
  270. t.Errorf("%d:%s: error was %v; want %v", i, tc.desc, err, tc.err)
  271. }
  272. if got := string(b[:nDst]); got != tc.want {
  273. t.Errorf("%d:%s: result was %q: want %q", i, tc.desc, got, tc.want)
  274. }
  275. if nSrc != tc.nSrc {
  276. t.Errorf("%d:%s: nSrc was %d; want %d", i, tc.desc, nSrc, tc.nSrc)
  277. }
  278. }
  279. }
  280. func TestUTF8Decoder(t *testing.T) {
  281. testCases := []struct {
  282. desc string
  283. src string
  284. notEOF bool // the inverse of atEOF
  285. sizeDst int
  286. want string
  287. nSrc int
  288. err error
  289. }{{
  290. desc: "empty string, empty dest buffer",
  291. }, {
  292. desc: "empty string",
  293. sizeDst: 8,
  294. }, {
  295. desc: "empty string, streaming",
  296. notEOF: true,
  297. sizeDst: 8,
  298. }, {
  299. desc: "ascii",
  300. src: "abcde",
  301. sizeDst: 8,
  302. want: "abcde",
  303. nSrc: 5,
  304. }, {
  305. desc: "ascii and error",
  306. src: "ab\x80de",
  307. sizeDst: 7,
  308. want: "ab\ufffdde",
  309. nSrc: 5,
  310. }, {
  311. desc: "valid two-byte sequence",
  312. src: "a\u0300bc",
  313. sizeDst: 7,
  314. want: "a\u0300bc",
  315. nSrc: 5,
  316. }, {
  317. desc: "valid three-byte sequence",
  318. src: "a\u0300中",
  319. sizeDst: 7,
  320. want: "a\u0300中",
  321. nSrc: 6,
  322. }, {
  323. desc: "valid four-byte sequence",
  324. src: "a中\U00016F50",
  325. sizeDst: 8,
  326. want: "a中\U00016F50",
  327. nSrc: 8,
  328. }, {
  329. desc: "short source buffer",
  330. src: "abc\xf0\x90",
  331. notEOF: true,
  332. sizeDst: 10,
  333. want: "abc",
  334. nSrc: 3,
  335. err: transform.ErrShortSrc,
  336. }, {
  337. // We don't check for the maximal subpart of an ill-formed subsequence
  338. // at the end of an open segment.
  339. desc: "complete invalid that looks like short at end",
  340. src: "abc\xf0\x80",
  341. notEOF: true,
  342. sizeDst: 10,
  343. want: "abc", // instead of "abc\ufffd\ufffd",
  344. nSrc: 3,
  345. err: transform.ErrShortSrc,
  346. }, {
  347. desc: "incomplete sequence at end",
  348. src: "a\x80bc\xf0\x90",
  349. sizeDst: 9,
  350. want: "a\ufffdbc\ufffd",
  351. nSrc: 6,
  352. }, {
  353. desc: "invalid second byte",
  354. src: "abc\xf0dddd",
  355. sizeDst: 10,
  356. want: "abc\ufffddddd",
  357. nSrc: 8,
  358. }, {
  359. desc: "invalid second byte at end",
  360. src: "abc\xf0d",
  361. sizeDst: 10,
  362. want: "abc\ufffdd",
  363. nSrc: 5,
  364. }, {
  365. desc: "invalid third byte",
  366. src: "a\u0300bc\xf0\x90dddd",
  367. sizeDst: 12,
  368. want: "a\u0300bc\ufffddddd",
  369. nSrc: 11,
  370. }, {
  371. desc: "invalid third byte at end",
  372. src: "a\u0300bc\xf0\x90d",
  373. sizeDst: 12,
  374. want: "a\u0300bc\ufffdd",
  375. nSrc: 8,
  376. }, {
  377. desc: "invalid fourth byte, tight buffer",
  378. src: "a\u0300bc\xf0\x90\x80d",
  379. sizeDst: 9,
  380. want: "a\u0300bc\ufffdd",
  381. nSrc: 9,
  382. }, {
  383. desc: "invalid fourth byte at end",
  384. src: "a\u0300bc\xf0\x90\x80",
  385. sizeDst: 8,
  386. want: "a\u0300bc\ufffd",
  387. nSrc: 8,
  388. }, {
  389. desc: "invalid fourth byte and short four byte sequence",
  390. src: "a\u0300bc\xf0\x90\x80\xf0\x90\x80",
  391. notEOF: true,
  392. sizeDst: 20,
  393. want: "a\u0300bc\ufffd",
  394. nSrc: 8,
  395. err: transform.ErrShortSrc,
  396. }, {
  397. desc: "valid four-byte sequence overflowing short buffer",
  398. src: "a\u0300bc\xf0\x90\x80\x80",
  399. notEOF: true,
  400. sizeDst: 8,
  401. want: "a\u0300bc",
  402. nSrc: 5,
  403. err: transform.ErrShortDst,
  404. }, {
  405. desc: "invalid fourth byte at end short, but short dst",
  406. src: "a\u0300bc\xf0\x90\x80\xf0\x90\x80",
  407. notEOF: true,
  408. sizeDst: 8,
  409. // More bytes would fit in the buffer, but this seems to require a more
  410. // complicated and slower algorithm.
  411. want: "a\u0300bc", // instead of "a\u0300bc"
  412. nSrc: 5,
  413. err: transform.ErrShortDst,
  414. }, {
  415. desc: "short dst for error",
  416. src: "abc\x80",
  417. notEOF: true,
  418. sizeDst: 5,
  419. want: "abc",
  420. nSrc: 3,
  421. err: transform.ErrShortDst,
  422. }, {
  423. desc: "adjusting short dst buffer",
  424. src: "abc\x80ef",
  425. notEOF: true,
  426. sizeDst: 6,
  427. want: "abc\ufffd",
  428. nSrc: 4,
  429. err: transform.ErrShortDst,
  430. }}
  431. tr := UTF8.NewDecoder()
  432. for i, tc := range testCases {
  433. b := make([]byte, tc.sizeDst)
  434. nDst, nSrc, err := tr.Transform(b, []byte(tc.src), !tc.notEOF)
  435. if err != tc.err {
  436. t.Errorf("%d:%s: error was %v; want %v", i, tc.desc, err, tc.err)
  437. }
  438. if got := string(b[:nDst]); got != tc.want {
  439. t.Errorf("%d:%s: result was %q: want %q", i, tc.desc, got, tc.want)
  440. }
  441. if nSrc != tc.nSrc {
  442. t.Errorf("%d:%s: nSrc was %d; want %d", i, tc.desc, nSrc, tc.nSrc)
  443. }
  444. }
  445. }
  446. func TestBOMOverride(t *testing.T) {
  447. dec := BOMOverride(charmap.CodePage437.NewDecoder())
  448. dst := make([]byte, 100)
  449. for i, tc := range []struct {
  450. src string
  451. atEOF bool
  452. dst string
  453. nSrc int
  454. err error
  455. }{
  456. 0: {"H\x82ll\x93", true, "Héllô", 5, nil},
  457. 1: {"\uFEFFHéllö", true, "Héllö", 10, nil},
  458. 2: {"\xFE\xFF\x00H\x00e\x00l\x00l\x00o", true, "Hello", 12, nil},
  459. 3: {"\xFF\xFEH\x00e\x00l\x00l\x00o\x00", true, "Hello", 12, nil},
  460. 4: {"\uFEFF", true, "", 3, nil},
  461. 5: {"\xFE\xFF", true, "", 2, nil},
  462. 6: {"\xFF\xFE", true, "", 2, nil},
  463. 7: {"\xEF\xBB", true, "\u2229\u2557", 2, nil},
  464. 8: {"\xEF", true, "\u2229", 1, nil},
  465. 9: {"", true, "", 0, nil},
  466. 10: {"\xFE", true, "\u25a0", 1, nil},
  467. 11: {"\xFF", true, "\u00a0", 1, nil},
  468. 12: {"\xEF\xBB", false, "", 0, transform.ErrShortSrc},
  469. 13: {"\xEF", false, "", 0, transform.ErrShortSrc},
  470. 14: {"", false, "", 0, transform.ErrShortSrc},
  471. 15: {"\xFE", false, "", 0, transform.ErrShortSrc},
  472. 16: {"\xFF", false, "", 0, transform.ErrShortSrc},
  473. 17: {"\xFF\xFE", false, "", 0, transform.ErrShortSrc},
  474. } {
  475. dec.Reset()
  476. nDst, nSrc, err := dec.Transform(dst, []byte(tc.src), tc.atEOF)
  477. got := string(dst[:nDst])
  478. if nSrc != tc.nSrc {
  479. t.Errorf("%d: nSrc: got %d; want %d", i, nSrc, tc.nSrc)
  480. }
  481. if got != tc.dst {
  482. t.Errorf("%d: got %+q; want %+q", i, got, tc.dst)
  483. }
  484. if err != tc.err {
  485. t.Errorf("%d: error: got %v; want %v", i, err, tc.err)
  486. }
  487. }
  488. }