func TestReadStdin(t *testing.T) { old := *os.ReadConsoleFunc defer func() { *os.ReadConsoleFunc = old }() testConsole := os.NewConsoleFile(syscall.Stdin, "test") var tests = []string{ "abc", "äöü", "\u3042", "“hi”™", "hello\x1aworld", "\U0001F648\U0001F649\U0001F64A", } for _, consoleSize := range []int{1, 2, 3, 10, 16, 100, 1000} { for _, readSize := range []int{1, 2, 3, 4, 5, 8, 10, 16, 20, 50, 100} { for _, s := range tests { t.Run(fmt.Sprintf("c%d/r%d/%s", consoleSize, readSize, s), func(t *testing.T) { s16 := utf16.Encode([]rune(s)) *os.ReadConsoleFunc = func(h syscall.Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) error { if inputControl != nil { t.Fatalf("inputControl not nil") } n := int(toread) if n > consoleSize { n = consoleSize } n = copy((*[10000]uint16)(unsafe.Pointer(buf))[:n], s16) s16 = s16[n:] *read = uint32(n) t.Logf("read %d -> %d", toread, *read) return nil } var all []string var buf []byte chunk := make([]byte, readSize) for { n, err := testConsole.Read(chunk) buf = append(buf, chunk[:n]...) if err == io.EOF { all = append(all, string(buf)) if len(all) >= 5 { break } buf = buf[:0] } else if err != nil { t.Fatalf("reading %q: error: %v", s, err) } if len(buf) >= 2000 { t.Fatalf("reading %q: stuck in loop: %q", s, buf) } } want := strings.Split(s, "\x1a") for len(want) < 5 { want = append(want, "") } if !reflect.DeepEqual(all, want) { t.Errorf("reading %q:\nhave %x\nwant %x", s, all, want) } }) } } } }
func TestReadStdin(t *testing.T) { defer os.ResetGetConsoleCPAndReadFileFuncs() testConsole := os.NewConsoleFile(syscall.Stdin, "test") var ( hiraganaA_CP932 = []byte{0x82, 0xa0} hiraganaA_UTF8 = "\u3042" tests = []struct { cp uint32 input []byte output string // always utf8 }{ { cp: 437, input: []byte("abc"), output: "abc", }, { cp: 850, input: []byte{0x84, 0x94, 0x81}, output: "äöü", }, { cp: 932, input: hiraganaA_CP932, output: hiraganaA_UTF8, }, { cp: 932, input: bytes.Repeat(hiraganaA_CP932, 2), output: strings.Repeat(hiraganaA_UTF8, 2), }, { cp: 932, input: append(bytes.Repeat(hiraganaA_CP932, 3), '.'), output: strings.Repeat(hiraganaA_UTF8, 3) + ".", }, { cp: 932, input: append(append([]byte("hello"), hiraganaA_CP932...), []byte("world")...), output: "hello" + hiraganaA_UTF8 + "world", }, { cp: 932, input: append(append([]byte("hello"), bytes.Repeat(hiraganaA_CP932, 5)...), []byte("world")...), output: "hello" + strings.Repeat(hiraganaA_UTF8, 5) + "world", }, } ) for _, consoleReadBufSize := range []int{1, 2, 3, 4, 5, 8, 10, 16, 20, 50, 100} { for _, readFileBufSize := range []int{1, 2, 3, 10, 16, 100, 1000} { nextTest: for ti, test := range tests { input := bytes.NewBuffer(test.input) *os.ReadFileP = func(h syscall.Handle, buf []byte, done *uint32, o *syscall.Overlapped) error { if len(buf) > readFileBufSize { buf = buf[:readFileBufSize] } n, err := input.Read(buf) *done = uint32(n) return err } *os.GetCPP = func() uint32 { return test.cp } var bigbuf []byte for len(bigbuf) < len([]byte(test.output)) { buf := make([]byte, consoleReadBufSize) n, err := testConsole.Read(buf) if err != nil { t.Errorf("test=%d bufsizes=%d,%d: read failed: %v", ti, consoleReadBufSize, readFileBufSize, err) continue nextTest } bigbuf = append(bigbuf, buf[:n]...) } have := hex.Dump(bigbuf) expected := hex.Dump([]byte(test.output)) if have != expected { t.Errorf("test=%d bufsizes=%d,%d: %q expected, but %q received", ti, consoleReadBufSize, readFileBufSize, expected, have) continue nextTest } } } } }