...

Source file src/golang.org/x/text/encoding/japanese/all_test.go

Documentation: golang.org/x/text/encoding/japanese

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

View as plain text