golang.org/x/text@v0.14.0/encoding/japanese/all_test.go (about) 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 5 package japanese 6 7 import ( 8 "fmt" 9 "strings" 10 "testing" 11 "unicode/utf8" 12 13 "golang.org/x/text/encoding" 14 "golang.org/x/text/encoding/internal" 15 "golang.org/x/text/encoding/internal/enctest" 16 "golang.org/x/text/transform" 17 ) 18 19 func dec(e encoding.Encoding) (dir string, t transform.Transformer, err error) { 20 return "Decode", e.NewDecoder(), nil 21 } 22 func enc(e encoding.Encoding) (dir string, t transform.Transformer, err error) { 23 return "Encode", e.NewEncoder(), internal.ErrASCIIReplacement 24 } 25 26 func TestNonRepertoire(t *testing.T) { 27 // Pick n to cause the destination buffer in transform.String to overflow. 28 const n = 100 29 long := strings.Repeat(".", n) 30 testCases := []struct { 31 init func(e encoding.Encoding) (string, transform.Transformer, error) 32 e encoding.Encoding 33 src, want string 34 }{ 35 {enc, EUCJP, "갂", ""}, 36 {enc, EUCJP, "a갂", "a"}, 37 {enc, EUCJP, "丌갂", "\x8f\xb0\xa4"}, 38 39 {enc, ISO2022JP, "갂", ""}, 40 {enc, ISO2022JP, "a갂", "a"}, 41 {enc, ISO2022JP, "朗갂", "\x1b$BzF\x1b(B"}, // switch back to ASCII mode at end 42 43 {enc, ShiftJIS, "갂", ""}, 44 {enc, ShiftJIS, "a갂", "a"}, 45 {enc, ShiftJIS, "\u2190갂", "\x81\xa9"}, 46 47 // Continue correctly after errors 48 {dec, EUCJP, "\x8e\xa0", "\ufffd\ufffd"}, 49 {dec, EUCJP, "\x8e\xe0", "\ufffd"}, 50 {dec, EUCJP, "\x8e\xff", "\ufffd\ufffd"}, 51 {dec, EUCJP, "\x8ea", "\ufffda"}, 52 {dec, EUCJP, "\x8f\xa0", "\ufffd\ufffd"}, 53 {dec, EUCJP, "\x8f\xa1\xa0", "\ufffd\ufffd"}, 54 {dec, EUCJP, "\x8f\xa1a", "\ufffda"}, 55 {dec, EUCJP, "\x8f\xa1a", "\ufffda"}, 56 {dec, EUCJP, "\x8f\xa1a", "\ufffda"}, 57 {dec, EUCJP, "\x8f\xa2\xa2", "\ufffd"}, 58 {dec, EUCJP, "\xfe", "\ufffd"}, 59 {dec, EUCJP, "\xfe\xfc", "\ufffd"}, 60 {dec, EUCJP, "\xfe\xff", "\ufffd\ufffd"}, 61 // Correct handling of end of source 62 {dec, EUCJP, strings.Repeat("\x8e", n), strings.Repeat("\ufffd", n)}, 63 {dec, EUCJP, strings.Repeat("\x8f", n), strings.Repeat("\ufffd", n)}, 64 {dec, EUCJP, strings.Repeat("\x8f\xa0", n), strings.Repeat("\ufffd", 2*n)}, 65 {dec, EUCJP, "a" + strings.Repeat("\x8f\xa1", n), "a" + strings.Repeat("\ufffd", n)}, 66 {dec, EUCJP, "a" + strings.Repeat("\x8f\xa1\xff", n), "a" + strings.Repeat("\ufffd", 2*n)}, 67 68 // Continue correctly after errors 69 {dec, ShiftJIS, "\x80", "\u0080"}, // It's what the spec says. 70 {dec, ShiftJIS, "\x81", "\ufffd"}, 71 {dec, ShiftJIS, "\x81\x7f", "\ufffd\u007f"}, 72 {dec, ShiftJIS, "\xe0", "\ufffd"}, 73 {dec, ShiftJIS, "\xe0\x39", "\ufffd\u0039"}, 74 {dec, ShiftJIS, "\xe0\x9f", "燹"}, 75 {dec, ShiftJIS, "\xe0\xfd", "\ufffd"}, 76 {dec, ShiftJIS, "\xef\xfc", "\ufffd"}, 77 {dec, ShiftJIS, "\xfc\xfc", "\ufffd"}, 78 {dec, ShiftJIS, "\xfc\xfd", "\ufffd"}, 79 {dec, ShiftJIS, "\xfdaa", "\ufffdaa"}, 80 81 {dec, ShiftJIS, strings.Repeat("\x81\x81", n), strings.Repeat("=", n)}, 82 {dec, ShiftJIS, strings.Repeat("\xe0\xfd", n), strings.Repeat("\ufffd", n)}, 83 {dec, ShiftJIS, "a" + strings.Repeat("\xe0\xfd", n), "a" + strings.Repeat("\ufffd", n)}, 84 85 {dec, ISO2022JP, "\x1b$", "\ufffd$"}, 86 {dec, ISO2022JP, "\x1b(", "\ufffd("}, 87 {dec, ISO2022JP, "\x1b@", "\ufffd@"}, 88 {dec, ISO2022JP, "\x1bZ", "\ufffdZ"}, 89 // incomplete escapes 90 {dec, ISO2022JP, "\x1b$", "\ufffd$"}, 91 {dec, ISO2022JP, "\x1b$J.", "\ufffd$J."}, // illegal 92 {dec, ISO2022JP, "\x1b$B.", "\ufffd"}, // JIS208 93 {dec, ISO2022JP, "\x1b$(", "\ufffd$("}, // JIS212 94 {dec, ISO2022JP, "\x1b$(..", "\ufffd$(.."}, // JIS212 95 {dec, ISO2022JP, "\x1b$(" + long, "\ufffd$(" + long}, // JIS212 96 {dec, ISO2022JP, "\x1b$(D.", "\ufffd"}, // JIS212 97 {dec, ISO2022JP, "\x1b$(D..", "\ufffd"}, // JIS212 98 {dec, ISO2022JP, "\x1b$(D...", "\ufffd\ufffd"}, // JIS212 99 {dec, ISO2022JP, "\x1b(B.", "."}, // ascii 100 {dec, ISO2022JP, "\x1b(B..", ".."}, // ascii 101 {dec, ISO2022JP, "\x1b(J.", "."}, // roman 102 {dec, ISO2022JP, "\x1b(J..", ".."}, // roman 103 {dec, ISO2022JP, "\x1b(I\x20", "\ufffd"}, // katakana 104 {dec, ISO2022JP, "\x1b(I\x20\x20", "\ufffd\ufffd"}, // katakana 105 // recover to same state 106 {dec, ISO2022JP, "\x1b(B\x1b.", "\ufffd."}, 107 {dec, ISO2022JP, "\x1b(I\x1b.", "\ufffdョ"}, 108 {dec, ISO2022JP, "\x1b(I\x1b$.", "\ufffd、ョ"}, 109 {dec, ISO2022JP, "\x1b(I\x1b(.", "\ufffdィョ"}, 110 {dec, ISO2022JP, "\x1b$B\x7e\x7e", "\ufffd"}, 111 {dec, ISO2022JP, "\x1b$@\x0a.", "\x0a."}, 112 {dec, ISO2022JP, "\x1b$B\x0a.", "\x0a."}, 113 {dec, ISO2022JP, "\x1b$(D\x0a.", "\x0a."}, 114 {dec, ISO2022JP, "\x1b$(D\x7e\x7e", "\ufffd"}, 115 {dec, ISO2022JP, "\x80", "\ufffd"}, 116 117 // TODO: according to https://encoding.spec.whatwg.org/#iso-2022-jp, 118 // these should all be correct. 119 // {dec, ISO2022JP, "\x1b(B\x0E", "\ufffd"}, 120 // {dec, ISO2022JP, "\x1b(B\x0F", "\ufffd"}, 121 {dec, ISO2022JP, "\x1b(B\x5C", "\u005C"}, 122 {dec, ISO2022JP, "\x1b(B\x7E", "\u007E"}, 123 // {dec, ISO2022JP, "\x1b(J\x0E", "\ufffd"}, 124 // {dec, ISO2022JP, "\x1b(J\x0F", "\ufffd"}, 125 // {dec, ISO2022JP, "\x1b(J\x5C", "\u00A5"}, 126 // {dec, ISO2022JP, "\x1b(J\x7E", "\u203E"}, 127 } 128 for _, tc := range testCases { 129 dir, tr, wantErr := tc.init(tc.e) 130 t.Run(fmt.Sprintf("%s/%v/%q", dir, tc.e, short(tc.src)), func(t *testing.T) { 131 dst := make([]byte, 100000) 132 src := []byte(tc.src) 133 for i := 0; i <= len(tc.src); i++ { 134 nDst, nSrc, err := tr.Transform(dst, src[:i], false) 135 if err != nil && err != transform.ErrShortSrc && err != wantErr { 136 t.Fatalf("error on first call to Transform: %v", err) 137 } 138 n, _, err := tr.Transform(dst[nDst:], src[nSrc:], true) 139 nDst += n 140 if err != wantErr { 141 t.Fatalf("(%q|%q): got %v; want %v", tc.src[:i], tc.src[i:], err, wantErr) 142 } 143 if got := string(dst[:nDst]); got != tc.want { 144 t.Errorf("(%q|%q):\ngot %q\nwant %q", tc.src[:i], tc.src[i:], got, tc.want) 145 } 146 } 147 }) 148 } 149 } 150 151 func short(s string) string { 152 if len(s) <= 50 { 153 return s 154 } 155 var i int 156 for i = 1; i < utf8.UTFMax && !utf8.RuneStart(s[50-i]); i++ { 157 } 158 return s[:50-i] + "…" 159 } 160 161 func TestCorrect(t *testing.T) { 162 testCases := []struct { 163 init func(e encoding.Encoding) (string, transform.Transformer, error) 164 e encoding.Encoding 165 src, want string 166 }{ 167 {dec, ShiftJIS, "\x9f\xfc", "滌"}, 168 {dec, ShiftJIS, "\xfb\xfc", "髙"}, 169 {dec, ShiftJIS, "\xfa\xb1", "﨑"}, 170 {enc, ShiftJIS, "滌", "\x9f\xfc"}, 171 {enc, ShiftJIS, "﨑", "\xed\x95"}, 172 } 173 for _, tc := range testCases { 174 dir, tr, _ := tc.init(tc.e) 175 176 dst, _, err := transform.String(tr, tc.src) 177 if err != nil { 178 t.Errorf("%s %v(%q): got %v; want %v", dir, tc.e, tc.src, err, nil) 179 } 180 if got := string(dst); got != tc.want { 181 t.Errorf("%s %v(%q):\ngot %q\nwant %q", dir, tc.e, tc.src, got, tc.want) 182 } 183 } 184 } 185 186 func TestBasics(t *testing.T) { 187 // The encoded forms can be verified by the iconv program: 188 // $ echo 月日は百代 | iconv -f UTF-8 -t SHIFT-JIS | xxd 189 testCases := []struct { 190 e encoding.Encoding 191 encPrefix string 192 encSuffix string 193 encoded string 194 utf8 string 195 }{{ 196 // "A。カ゚ 0208: etc 0212: etc" is a nonsense string that contains ASCII, half-width 197 // kana, JIS X 0208 (including two near the kink in the Shift JIS second byte 198 // encoding) and JIS X 0212 encodable codepoints. 199 // 200 // "月日は百代の過客にして、行かふ年も又旅人也。" is from the 17th century poem 201 // "Oku no Hosomichi" and contains both hiragana and kanji. 202 e: EUCJP, 203 encoded: "A\x8e\xa1\x8e\xb6\x8e\xdf " + 204 "0208: \xa1\xa1\xa1\xa2\xa1\xdf\xa1\xe0\xa1\xfd\xa1\xfe\xa2\xa1\xa2\xa2\xf4\xa6 " + 205 "0212: \x8f\xa2\xaf\x8f\xed\xe3", 206 utf8: "A。カ゚ " + 207 "0208: \u3000\u3001\u00d7\u00f7\u25ce\u25c7\u25c6\u25a1\u7199 " + 208 "0212: \u02d8\u9fa5", 209 }, { 210 e: EUCJP, 211 encoded: "\xb7\xee\xc6\xfc\xa4\xcf\xc9\xb4\xc2\xe5\xa4\xce\xb2\xe1\xb5\xd2" + 212 "\xa4\xcb\xa4\xb7\xa4\xc6\xa1\xa2\xb9\xd4\xa4\xab\xa4\xd5\xc7\xaf" + 213 "\xa4\xe2\xcb\xf4\xce\xb9\xbf\xcd\xcc\xe9\xa1\xa3", 214 utf8: "月日は百代の過客にして、行かふ年も又旅人也。", 215 }, { 216 e: ISO2022JP, 217 encSuffix: "\x1b\x28\x42", 218 encoded: "\x1b\x28\x49\x21\x36\x5f\x1b\x28\x42 " + 219 "0208: \x1b\x24\x42\x21\x21\x21\x22\x21\x5f\x21\x60\x21\x7d\x21\x7e\x22\x21\x22\x22\x74\x26", 220 utf8: "。カ゚ " + 221 "0208: \u3000\u3001\u00d7\u00f7\u25ce\u25c7\u25c6\u25a1\u7199", 222 }, { 223 e: ISO2022JP, 224 encPrefix: "\x1b\x24\x42", 225 encSuffix: "\x1b\x28\x42", 226 encoded: "\x37\x6e\x46\x7c\x24\x4f\x49\x34\x42\x65\x24\x4e\x32\x61\x35\x52" + 227 "\x24\x4b\x24\x37\x24\x46\x21\x22\x39\x54\x24\x2b\x24\x55\x47\x2f" + 228 "\x24\x62\x4b\x74\x4e\x39\x3f\x4d\x4c\x69\x21\x23", 229 utf8: "月日は百代の過客にして、行かふ年も又旅人也。", 230 }, { 231 e: ShiftJIS, 232 encoded: "A\xa1\xb6\xdf " + 233 "0208: \x81\x40\x81\x41\x81\x7e\x81\x80\x81\x9d\x81\x9e\x81\x9f\x81\xa0\xea\xa4", 234 utf8: "A。カ゚ " + 235 "0208: \u3000\u3001\u00d7\u00f7\u25ce\u25c7\u25c6\u25a1\u7199", 236 }, { 237 e: ShiftJIS, 238 encoded: "\x8c\x8e\x93\xfa\x82\xcd\x95\x53\x91\xe3\x82\xcc\x89\xdf\x8b\x71" + 239 "\x82\xc9\x82\xb5\x82\xc4\x81\x41\x8d\x73\x82\xa9\x82\xd3\x94\x4e" + 240 "\x82\xe0\x96\x94\x97\xb7\x90\x6c\x96\xe7\x81\x42", 241 utf8: "月日は百代の過客にして、行かふ年も又旅人也。", 242 }} 243 244 for _, tc := range testCases { 245 enctest.TestEncoding(t, tc.e, tc.encoded, tc.utf8, tc.encPrefix, tc.encSuffix) 246 } 247 } 248 249 func TestFiles(t *testing.T) { 250 enctest.TestFile(t, EUCJP) 251 enctest.TestFile(t, ISO2022JP) 252 enctest.TestFile(t, ShiftJIS) 253 } 254 255 func BenchmarkEncoding(b *testing.B) { 256 enctest.Benchmark(b, EUCJP) 257 enctest.Benchmark(b, ISO2022JP) 258 enctest.Benchmark(b, ShiftJIS) 259 }