unicode_test.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  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: Fail on single byte missing BOM when required",
  109. src: "\x00",
  110. sizeDst: 4,
  111. t: utf16BEEB.NewDecoder(),
  112. err: ErrMissingBOM,
  113. }, {
  114. desc: "utf-16 dec: Fail on short src missing BOM when required",
  115. src: "\x00",
  116. notEOF: true,
  117. sizeDst: 4,
  118. t: utf16BEEB.NewDecoder(),
  119. err: transform.ErrShortSrc,
  120. }, {
  121. desc: "utf-16 dec: SHOULD interpret text as big-endian when BOM not present (RFC 2781:4.3)",
  122. src: "\xD8\x08\xDF\x45\x00\x3D\x00\x52\x00\x61",
  123. sizeDst: 100,
  124. want: "\U00012345=Ra",
  125. nSrc: 10,
  126. t: utf16BEUB.NewDecoder(),
  127. }, {
  128. desc: "utf-16 dec: incorrect UTF-16: odd bytes",
  129. src: "\x00",
  130. sizeDst: 100,
  131. want: "\uFFFD",
  132. nSrc: 1,
  133. t: utf16BEUB.NewDecoder(),
  134. }, {
  135. desc: "utf-16 dec: Fail on incorrect UTF-16: short source odd bytes",
  136. src: "\x00",
  137. notEOF: true,
  138. sizeDst: 100,
  139. t: utf16BEUB.NewDecoder(),
  140. err: transform.ErrShortSrc,
  141. }, {
  142. // This is an error according to RFC 2781. But errors in RFC 2781 are
  143. // open to interpretations, so I guess this is fine.
  144. desc: "utf-16le dec: incorrect BOM is an error (RFC 2781:4.1)",
  145. src: "\xFE\xFF\x08\xD8\x45\xDF\x3D\x00\x52\x00\x61\x00",
  146. sizeDst: 100,
  147. want: "\uFFFE\U00012345=Ra",
  148. nSrc: 12,
  149. t: utf16LEIB.NewDecoder(),
  150. }, {
  151. desc: "utf-16 enc: SHOULD write BOM (RFC 2781:3.3)",
  152. src: "\U00012345=Ra",
  153. sizeDst: 100,
  154. want: "\xFF\xFE\x08\xD8\x45\xDF\x3D\x00\x52\x00\x61\x00",
  155. nSrc: 7,
  156. t: utf16LEUB.NewEncoder(),
  157. }, {
  158. desc: "utf-16 enc: SHOULD write BOM (RFC 2781:3.3)",
  159. src: "\U00012345=Ra",
  160. sizeDst: 100,
  161. want: "\xFE\xFF\xD8\x08\xDF\x45\x00\x3D\x00\x52\x00\x61",
  162. nSrc: 7,
  163. t: utf16BEUB.NewEncoder(),
  164. }, {
  165. desc: "utf-16le enc: MUST NOT write BOM (RFC 2781:3.3)",
  166. src: "\U00012345=Ra",
  167. sizeDst: 100,
  168. want: "\x08\xD8\x45\xDF\x3D\x00\x52\x00\x61\x00",
  169. nSrc: 7,
  170. t: utf16LEIB.NewEncoder(),
  171. }, {
  172. desc: "utf-16be dec: incorrect UTF-16: odd bytes",
  173. src: "\x00",
  174. sizeDst: 100,
  175. want: "\uFFFD",
  176. nSrc: 1,
  177. t: utf16BEIB.NewDecoder(),
  178. }, {
  179. desc: "utf-16be dec: unpaired surrogate, odd bytes",
  180. src: "\xD8\x45\x00",
  181. sizeDst: 100,
  182. want: "\uFFFD\uFFFD",
  183. nSrc: 3,
  184. t: utf16BEIB.NewDecoder(),
  185. }, {
  186. desc: "utf-16be dec: unpaired low surrogate + valid text",
  187. src: "\xD8\x45\x00a",
  188. sizeDst: 100,
  189. want: "\uFFFDa",
  190. nSrc: 4,
  191. t: utf16BEIB.NewDecoder(),
  192. }, {
  193. desc: "utf-16be dec: unpaired low surrogate + valid text + single byte",
  194. src: "\xD8\x45\x00ab",
  195. sizeDst: 100,
  196. want: "\uFFFDa\uFFFD",
  197. nSrc: 5,
  198. t: utf16BEIB.NewDecoder(),
  199. }, {
  200. desc: "utf-16le dec: unpaired high surrogate",
  201. src: "\x00\x00\x00\xDC\x12\xD8",
  202. sizeDst: 100,
  203. want: "\x00\uFFFD\uFFFD",
  204. nSrc: 6,
  205. t: utf16LEIB.NewDecoder(),
  206. }, {
  207. desc: "utf-16be dec: two unpaired low surrogates",
  208. src: "\xD8\x45\xD8\x12",
  209. sizeDst: 100,
  210. want: "\uFFFD\uFFFD",
  211. nSrc: 4,
  212. t: utf16BEIB.NewDecoder(),
  213. }, {
  214. desc: "utf-16be dec: short dst",
  215. src: "\x00a",
  216. sizeDst: 0,
  217. want: "",
  218. nSrc: 0,
  219. t: utf16BEIB.NewDecoder(),
  220. err: transform.ErrShortDst,
  221. }, {
  222. desc: "utf-16be dec: short dst surrogate",
  223. src: "\xD8\xF5\xDC\x12",
  224. sizeDst: 3,
  225. want: "",
  226. nSrc: 0,
  227. t: utf16BEIB.NewDecoder(),
  228. err: transform.ErrShortDst,
  229. }, {
  230. desc: "utf-16be dec: short dst trailing byte",
  231. src: "\x00",
  232. sizeDst: 2,
  233. want: "",
  234. nSrc: 0,
  235. t: utf16BEIB.NewDecoder(),
  236. err: transform.ErrShortDst,
  237. }, {
  238. desc: "utf-16be dec: short src",
  239. src: "\x00",
  240. notEOF: true,
  241. sizeDst: 3,
  242. want: "",
  243. nSrc: 0,
  244. t: utf16BEIB.NewDecoder(),
  245. err: transform.ErrShortSrc,
  246. }, {
  247. desc: "utf-16 enc",
  248. src: "\U00012345=Ra",
  249. sizeDst: 100,
  250. want: "\xFE\xFF\xD8\x08\xDF\x45\x00\x3D\x00\x52\x00\x61",
  251. nSrc: 7,
  252. t: utf16BEUB.NewEncoder(),
  253. }, {
  254. desc: "utf-16 enc: short dst normal",
  255. src: "\U00012345=Ra",
  256. sizeDst: 9,
  257. want: "\xD8\x08\xDF\x45\x00\x3D\x00\x52",
  258. nSrc: 6,
  259. t: utf16BEIB.NewEncoder(),
  260. err: transform.ErrShortDst,
  261. }, {
  262. desc: "utf-16 enc: short dst surrogate",
  263. src: "\U00012345=Ra",
  264. sizeDst: 3,
  265. want: "",
  266. nSrc: 0,
  267. t: utf16BEIB.NewEncoder(),
  268. err: transform.ErrShortDst,
  269. }, {
  270. desc: "utf-16 enc: short src",
  271. src: "\U00012345=Ra\xC2",
  272. notEOF: true,
  273. sizeDst: 100,
  274. want: "\xD8\x08\xDF\x45\x00\x3D\x00\x52\x00\x61",
  275. nSrc: 7,
  276. t: utf16BEIB.NewEncoder(),
  277. err: transform.ErrShortSrc,
  278. }, {
  279. desc: "utf-16be dec: don't change byte order mid-stream",
  280. src: "\xFE\xFF\xD8\x08\xDF\x45\x00\x3D\xFF\xFE\x00\x52\x00\x61",
  281. sizeDst: 100,
  282. want: "\U00012345=\ufffeRa",
  283. nSrc: 14,
  284. t: utf16BEUB.NewDecoder(),
  285. }, {
  286. desc: "utf-16le dec: don't change byte order mid-stream",
  287. src: "\xFF\xFE\x08\xD8\x45\xDF\x3D\x00\xFF\xFE\xFE\xFF\x52\x00\x61\x00",
  288. sizeDst: 100,
  289. want: "\U00012345=\ufeff\ufffeRa",
  290. nSrc: 16,
  291. t: utf16LEUB.NewDecoder(),
  292. }}
  293. for i, tc := range testCases {
  294. for j := 0; j < 2; j++ {
  295. b := make([]byte, tc.sizeDst)
  296. nDst, nSrc, err := tc.t.Transform(b, []byte(tc.src), !tc.notEOF)
  297. if err != tc.err {
  298. t.Errorf("%d:%s: error was %v; want %v", i, tc.desc, err, tc.err)
  299. }
  300. if got := string(b[:nDst]); got != tc.want {
  301. t.Errorf("%d:%s: result was %q: want %q", i, tc.desc, got, tc.want)
  302. }
  303. if nSrc != tc.nSrc {
  304. t.Errorf("%d:%s: nSrc was %d; want %d", i, tc.desc, nSrc, tc.nSrc)
  305. }
  306. // Since Transform is stateful, run failures again
  307. // to ensure that the same error occurs a second time.
  308. if err == nil {
  309. break
  310. }
  311. }
  312. }
  313. }
  314. func TestUTF8Decoder(t *testing.T) {
  315. testCases := []struct {
  316. desc string
  317. src string
  318. notEOF bool // the inverse of atEOF
  319. sizeDst int
  320. want string
  321. nSrc int
  322. err error
  323. }{{
  324. desc: "empty string, empty dest buffer",
  325. }, {
  326. desc: "empty string",
  327. sizeDst: 8,
  328. }, {
  329. desc: "empty string, streaming",
  330. notEOF: true,
  331. sizeDst: 8,
  332. }, {
  333. desc: "ascii",
  334. src: "abcde",
  335. sizeDst: 8,
  336. want: "abcde",
  337. nSrc: 5,
  338. }, {
  339. desc: "ascii and error",
  340. src: "ab\x80de",
  341. sizeDst: 7,
  342. want: "ab\ufffdde",
  343. nSrc: 5,
  344. }, {
  345. desc: "valid two-byte sequence",
  346. src: "a\u0300bc",
  347. sizeDst: 7,
  348. want: "a\u0300bc",
  349. nSrc: 5,
  350. }, {
  351. desc: "valid three-byte sequence",
  352. src: "a\u0300中",
  353. sizeDst: 7,
  354. want: "a\u0300中",
  355. nSrc: 6,
  356. }, {
  357. desc: "valid four-byte sequence",
  358. src: "a中\U00016F50",
  359. sizeDst: 8,
  360. want: "a中\U00016F50",
  361. nSrc: 8,
  362. }, {
  363. desc: "short source buffer",
  364. src: "abc\xf0\x90",
  365. notEOF: true,
  366. sizeDst: 10,
  367. want: "abc",
  368. nSrc: 3,
  369. err: transform.ErrShortSrc,
  370. }, {
  371. // We don't check for the maximal subpart of an ill-formed subsequence
  372. // at the end of an open segment.
  373. desc: "complete invalid that looks like short at end",
  374. src: "abc\xf0\x80",
  375. notEOF: true,
  376. sizeDst: 10,
  377. want: "abc", // instead of "abc\ufffd\ufffd",
  378. nSrc: 3,
  379. err: transform.ErrShortSrc,
  380. }, {
  381. desc: "incomplete sequence at end",
  382. src: "a\x80bc\xf0\x90",
  383. sizeDst: 9,
  384. want: "a\ufffdbc\ufffd",
  385. nSrc: 6,
  386. }, {
  387. desc: "invalid second byte",
  388. src: "abc\xf0dddd",
  389. sizeDst: 10,
  390. want: "abc\ufffddddd",
  391. nSrc: 8,
  392. }, {
  393. desc: "invalid second byte at end",
  394. src: "abc\xf0d",
  395. sizeDst: 10,
  396. want: "abc\ufffdd",
  397. nSrc: 5,
  398. }, {
  399. desc: "invalid third byte",
  400. src: "a\u0300bc\xf0\x90dddd",
  401. sizeDst: 12,
  402. want: "a\u0300bc\ufffddddd",
  403. nSrc: 11,
  404. }, {
  405. desc: "invalid third byte at end",
  406. src: "a\u0300bc\xf0\x90d",
  407. sizeDst: 12,
  408. want: "a\u0300bc\ufffdd",
  409. nSrc: 8,
  410. }, {
  411. desc: "invalid fourth byte, tight buffer",
  412. src: "a\u0300bc\xf0\x90\x80d",
  413. sizeDst: 9,
  414. want: "a\u0300bc\ufffdd",
  415. nSrc: 9,
  416. }, {
  417. desc: "invalid fourth byte at end",
  418. src: "a\u0300bc\xf0\x90\x80",
  419. sizeDst: 8,
  420. want: "a\u0300bc\ufffd",
  421. nSrc: 8,
  422. }, {
  423. desc: "invalid fourth byte and short four byte sequence",
  424. src: "a\u0300bc\xf0\x90\x80\xf0\x90\x80",
  425. notEOF: true,
  426. sizeDst: 20,
  427. want: "a\u0300bc\ufffd",
  428. nSrc: 8,
  429. err: transform.ErrShortSrc,
  430. }, {
  431. desc: "valid four-byte sequence overflowing short buffer",
  432. src: "a\u0300bc\xf0\x90\x80\x80",
  433. notEOF: true,
  434. sizeDst: 8,
  435. want: "a\u0300bc",
  436. nSrc: 5,
  437. err: transform.ErrShortDst,
  438. }, {
  439. desc: "invalid fourth byte at end short, but short dst",
  440. src: "a\u0300bc\xf0\x90\x80\xf0\x90\x80",
  441. notEOF: true,
  442. sizeDst: 8,
  443. // More bytes would fit in the buffer, but this seems to require a more
  444. // complicated and slower algorithm.
  445. want: "a\u0300bc", // instead of "a\u0300bc"
  446. nSrc: 5,
  447. err: transform.ErrShortDst,
  448. }, {
  449. desc: "short dst for error",
  450. src: "abc\x80",
  451. notEOF: true,
  452. sizeDst: 5,
  453. want: "abc",
  454. nSrc: 3,
  455. err: transform.ErrShortDst,
  456. }, {
  457. desc: "adjusting short dst buffer",
  458. src: "abc\x80ef",
  459. notEOF: true,
  460. sizeDst: 6,
  461. want: "abc\ufffd",
  462. nSrc: 4,
  463. err: transform.ErrShortDst,
  464. }}
  465. tr := UTF8.NewDecoder()
  466. for i, tc := range testCases {
  467. b := make([]byte, tc.sizeDst)
  468. nDst, nSrc, err := tr.Transform(b, []byte(tc.src), !tc.notEOF)
  469. if err != tc.err {
  470. t.Errorf("%d:%s: error was %v; want %v", i, tc.desc, err, tc.err)
  471. }
  472. if got := string(b[:nDst]); got != tc.want {
  473. t.Errorf("%d:%s: result was %q: want %q", i, tc.desc, got, tc.want)
  474. }
  475. if nSrc != tc.nSrc {
  476. t.Errorf("%d:%s: nSrc was %d; want %d", i, tc.desc, nSrc, tc.nSrc)
  477. }
  478. }
  479. }
  480. func TestUTF8BOMDecoder(t *testing.T) {
  481. testCases := []struct {
  482. desc string
  483. src string
  484. notEOF bool // the inverse of atEOF
  485. sizeDst int
  486. want string
  487. nSrc int
  488. err error
  489. wantAll string
  490. }{{
  491. desc: "empty string, empty dest buffer",
  492. }, {
  493. desc: "empty string",
  494. sizeDst: 8,
  495. }, {
  496. desc: "empty string, streaming",
  497. notEOF: true,
  498. sizeDst: 8,
  499. }, {
  500. desc: "ascii",
  501. src: "abcde",
  502. sizeDst: 8,
  503. want: "abcde",
  504. nSrc: 5,
  505. wantAll: "abcde",
  506. }, {
  507. desc: "ascii with bom",
  508. src: utf8BOM + "abcde",
  509. sizeDst: 11,
  510. want: "abcde",
  511. nSrc: 8,
  512. wantAll: "abcde",
  513. }, {
  514. desc: "error with bom",
  515. src: utf8BOM + "ab\x80de",
  516. sizeDst: 11,
  517. want: "ab\ufffdde",
  518. nSrc: 8,
  519. wantAll: "ab\ufffdde",
  520. }, {
  521. desc: "short bom",
  522. src: utf8BOM[:2],
  523. notEOF: true,
  524. sizeDst: 7,
  525. want: "",
  526. nSrc: 0,
  527. wantAll: "\ufffd", // needs to be 1 replacement
  528. err: transform.ErrShortSrc,
  529. }, {
  530. desc: "short bom at end",
  531. src: utf8BOM[:2],
  532. sizeDst: 7,
  533. want: "\ufffd", // needs to be 1 replacement
  534. nSrc: 2,
  535. wantAll: "\ufffd", // needs to be 1 replacement
  536. err: nil,
  537. }, {
  538. desc: "short source buffer",
  539. src: "abc\xf0\x90",
  540. notEOF: true,
  541. sizeDst: 10,
  542. want: "abc",
  543. nSrc: 3,
  544. wantAll: "abc\ufffd",
  545. err: transform.ErrShortSrc,
  546. }, {
  547. desc: "short source buffer with bom",
  548. src: utf8BOM + "abc\xf0\x90",
  549. notEOF: true,
  550. sizeDst: 15,
  551. want: "abc",
  552. nSrc: 6,
  553. wantAll: "abc\ufffd",
  554. err: transform.ErrShortSrc,
  555. }, {
  556. desc: "short dst for error",
  557. src: utf8BOM + "abc\x80",
  558. notEOF: true,
  559. sizeDst: 5,
  560. want: "abc",
  561. nSrc: 6,
  562. wantAll: "abc\ufffd",
  563. err: transform.ErrShortDst,
  564. }}
  565. tr := UTF8BOM.NewDecoder()
  566. for i, tc := range testCases {
  567. tr.Reset()
  568. b := make([]byte, tc.sizeDst)
  569. nDst, nSrc, err := tr.Transform(b, []byte(tc.src), !tc.notEOF)
  570. if err != tc.err {
  571. t.Errorf("%d:%s: error was %v; want %v", i, tc.desc, err, tc.err)
  572. }
  573. if got := string(b[:nDst]); got != tc.want {
  574. t.Errorf("%d:%s: result was %q: want %q", i, tc.desc, got, tc.want)
  575. }
  576. if nSrc != tc.nSrc {
  577. t.Errorf("%d:%s: nSrc was %d; want %d", i, tc.desc, nSrc, tc.nSrc)
  578. }
  579. if got, _ := tr.String(tc.src); got != tc.wantAll {
  580. t.Errorf("%d:%s: String was %s; want %s", i, tc.desc, got, tc.wantAll)
  581. }
  582. }
  583. }
  584. func TestUTF8SigEncoder(t *testing.T) {
  585. testCases := []struct {
  586. desc string
  587. src string
  588. notEOF bool // the inverse of atEOF
  589. sizeDst int
  590. want string
  591. wantAll string // converting all bytes
  592. nSrc int
  593. err error
  594. }{{
  595. desc: "empty string, empty dest buffer",
  596. err: transform.ErrShortDst,
  597. wantAll: utf8BOM,
  598. }, {
  599. desc: "empty string",
  600. sizeDst: 8,
  601. want: utf8BOM,
  602. wantAll: utf8BOM,
  603. }, {
  604. desc: "empty string, streaming",
  605. notEOF: true,
  606. sizeDst: 8,
  607. want: utf8BOM,
  608. wantAll: utf8BOM,
  609. }, {
  610. desc: "ascii",
  611. src: "abcde",
  612. sizeDst: 8,
  613. want: utf8BOM + "abcde",
  614. nSrc: 5,
  615. wantAll: utf8BOM + "abcde",
  616. }, {
  617. desc: "short bom at end",
  618. src: utf8BOM[:2],
  619. sizeDst: 11,
  620. want: utf8BOM + "\ufffd",
  621. nSrc: 2,
  622. wantAll: utf8BOM + "\ufffd",
  623. }, {
  624. desc: "short bom",
  625. src: utf8BOM[:2],
  626. notEOF: true,
  627. sizeDst: 7,
  628. want: utf8BOM,
  629. nSrc: 0,
  630. err: transform.ErrShortSrc,
  631. wantAll: utf8BOM + "\ufffd",
  632. }, {
  633. desc: "short bom at end",
  634. src: utf8BOM[:2],
  635. sizeDst: 7,
  636. want: utf8BOM + "\ufffd", // needs to be 1 replacement
  637. nSrc: 2,
  638. err: nil,
  639. wantAll: utf8BOM + "\ufffd",
  640. }, {
  641. desc: "short dst buffer 2",
  642. src: "ab",
  643. sizeDst: 2,
  644. want: "",
  645. nSrc: 0,
  646. err: transform.ErrShortDst,
  647. wantAll: utf8BOM + "ab",
  648. }, {
  649. desc: "short dst buffer 3",
  650. src: "ab",
  651. sizeDst: 3,
  652. want: utf8BOM,
  653. nSrc: 0,
  654. err: transform.ErrShortDst,
  655. wantAll: utf8BOM + "ab",
  656. }, {
  657. desc: "short dst buffer 4",
  658. src: "ab",
  659. sizeDst: 4,
  660. want: utf8BOM + "a",
  661. nSrc: 1,
  662. err: transform.ErrShortDst,
  663. wantAll: utf8BOM + "ab",
  664. }}
  665. tr := UTF8BOM.NewEncoder()
  666. for i, tc := range testCases {
  667. tr.Reset()
  668. b := make([]byte, tc.sizeDst)
  669. nDst, nSrc, err := tr.Transform(b, []byte(tc.src), !tc.notEOF)
  670. if err != tc.err {
  671. t.Errorf("%d:%s: error was %v; want %v", i, tc.desc, err, tc.err)
  672. }
  673. if got := string(b[:nDst]); got != tc.want {
  674. t.Errorf("%d:%s: result was %q: want %q", i, tc.desc, got, tc.want)
  675. }
  676. if nSrc != tc.nSrc {
  677. t.Errorf("%d:%s: nSrc was %d; want %d", i, tc.desc, nSrc, tc.nSrc)
  678. }
  679. if got, _ := tr.String(tc.src); got != tc.wantAll {
  680. t.Errorf("%d:%s: String was %s; want %s", i, tc.desc, got, tc.wantAll)
  681. }
  682. }
  683. }
  684. func TestBOMOverride(t *testing.T) {
  685. dec := BOMOverride(charmap.CodePage437.NewDecoder())
  686. dst := make([]byte, 100)
  687. for i, tc := range []struct {
  688. src string
  689. atEOF bool
  690. dst string
  691. nSrc int
  692. err error
  693. }{
  694. 0: {"H\x82ll\x93", true, "Héllô", 5, nil},
  695. 1: {"\uFEFFHéllö", true, "Héllö", 10, nil},
  696. 2: {"\xFE\xFF\x00H\x00e\x00l\x00l\x00o", true, "Hello", 12, nil},
  697. 3: {"\xFF\xFEH\x00e\x00l\x00l\x00o\x00", true, "Hello", 12, nil},
  698. 4: {"\uFEFF", true, "", 3, nil},
  699. 5: {"\xFE\xFF", true, "", 2, nil},
  700. 6: {"\xFF\xFE", true, "", 2, nil},
  701. 7: {"\xEF\xBB", true, "\u2229\u2557", 2, nil},
  702. 8: {"\xEF", true, "\u2229", 1, nil},
  703. 9: {"", true, "", 0, nil},
  704. 10: {"\xFE", true, "\u25a0", 1, nil},
  705. 11: {"\xFF", true, "\u00a0", 1, nil},
  706. 12: {"\xEF\xBB", false, "", 0, transform.ErrShortSrc},
  707. 13: {"\xEF", false, "", 0, transform.ErrShortSrc},
  708. 14: {"", false, "", 0, transform.ErrShortSrc},
  709. 15: {"\xFE", false, "", 0, transform.ErrShortSrc},
  710. 16: {"\xFF", false, "", 0, transform.ErrShortSrc},
  711. 17: {"\xFF\xFE", false, "", 0, transform.ErrShortSrc},
  712. } {
  713. dec.Reset()
  714. nDst, nSrc, err := dec.Transform(dst, []byte(tc.src), tc.atEOF)
  715. got := string(dst[:nDst])
  716. if nSrc != tc.nSrc {
  717. t.Errorf("%d: nSrc: got %d; want %d", i, nSrc, tc.nSrc)
  718. }
  719. if got != tc.dst {
  720. t.Errorf("%d: got %+q; want %+q", i, got, tc.dst)
  721. }
  722. if err != tc.err {
  723. t.Errorf("%d: error: got %v; want %v", i, err, tc.err)
  724. }
  725. }
  726. }