测试命令行提示时出现问题,扫描器不等待用户输入。

huangapple go评论70阅读模式
英文:

Problem with testing cli prompts interactively, scanner is not waiting for user input

问题

我尝试编写一个测试来验证命令行提示,模拟用户对某些程序输出的响应中的输入。

如何使scanner.Scan等待其他写入?

我目前的代码如下:

	b := &bytes.Buffer{}
	fmt.Fprint(b, "0")
	go func() {
		time.Sleep(1 * time.Second)
		for i := 1; i < 4; i++ {
			fmt.Fprint(b, i)
			time.Sleep(1 * time.Second)
		}
	}()

	scanner := bufio.NewScanner(b)
	for scanner.Scan() {
		log.Print(scanner.Text())
	}
	if err := scanner.Err(); err != nil {
		log.Println("扫描时出现问题:", err)
	}

期望的结果是:0123

实际结果是:0

我尝试了一个使用io.Pipe的版本

	r, w := io.Pipe()
	fmt.Fprint(w, "0")
	go func() {
		time.Sleep(1 * time.Second)
		for i := 1; i < 4; i++ {
			fmt.Fprint(w, i)
			time.Sleep(1 * time.Second)
		}
	}()

	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		log.Print(scanner.Text())
	}
    if err := scanner.Err(); err != nil {
		log.Println("扫描时出现问题:", err)
	}

结果:致命错误:所有goroutine都处于休眠状态-死锁!

英文:

I try to write a test to verify cli prompts, emulate user inputs in response to some program outputs.

How to make scanner.Scan wait for the rest of the writes?

What I have so far:

	b := &bytes.Buffer{}
	fmt.Fprint(b, "0")
	go func() {
		time.Sleep(1 * time.Second)
		for i := 1; i < 4; i++ {
			fmt.Fprint(b, i)
			time.Sleep(1 * time.Second)
		}
	}()

	scanner := bufio.NewScanner(b)
	for scanner.Scan() {
		log.Print(scanner.Text())
	}
	if err := scanner.Err(); err != nil {
		log.Println("problem while scanning:", err)
	}

Expected result is: 0123

Actual result is: 0

I tried a version with io.Pipe

	r, w := io.Pipe()
	fmt.Fprint(w, "0")
	go func() {
		time.Sleep(1 * time.Second)
		for i := 1; i < 4; i++ {
			fmt.Fprint(w, i)
			time.Sleep(1 * time.Second)
		}
	}()

	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		log.Print(scanner.Text())
	}
    if err := scanner.Err(); err != nil {
		log.Println("problem while scanning:", err)
	}

result: fatal error: all goroutines are asleep - deadlock!

答案1

得分: 0

使用管道时,写入和读取是同步的。没有匹配的读取操作,写入操作无法完成。将第一个写入操作移到goroutine中,并关闭管道的写入端,以允许扫描器停止扫描。

    r, w := io.Pipe()
    go func() {
        defer w.Close()

        fmt.Fprint(w, "0")

        time.Sleep(1 * time.Second)
        for i := 1; i < 4; i++ {
            fmt.Fprint(w, i)
            time.Sleep(1 * time.Second)
        }
    }()

    scanner := bufio.NewScanner(r)
    for scanner.Scan() {
        log.Print(scanner.Text())
    }
    if err := scanner.Err(); err != nil {
        log.Println("扫描时出现问题:", err)
    }
英文:

When using a pipe, writes and reads are synchronous. A Write cannot complete without a matching Read. Move the first write into the goroutine. And Close the writing end of the pipe to allow the scanner to stop scanning.

    r, w := io.Pipe()
    go func() {
        defer w.Close()

        fmt.Fprint(w, &quot;0&quot;)

        time.Sleep(1 * time.Second)
        for i := 1; i &lt; 4; i++ {
            fmt.Fprint(w, i)
            time.Sleep(1 * time.Second)
        }
    }()

    scanner := bufio.NewScanner(r)
    for scanner.Scan() {
        log.Print(scanner.Text())
    }
    if err := scanner.Err(); err != nil {
        log.Println(&quot;problem while scanning:&quot;, err)
    }

huangapple
  • 本文由 发表于 2023年2月1日 17:48:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/75308283.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定