manifoldco / promptui

Interactive prompt for command-line applications
https://www.manifold.co
BSD 3-Clause "New" or "Revised" License
6.03k stars 333 forks source link

UnitTesting: validation gets called one char at the time - reading from stdin? #157

Closed JCzz closed 3 years ago

JCzz commented 4 years ago

Hi

I have the following test code:


package std

import (
    "fmt"
    "io/ioutil"
    "os"
    "testing"
)

func TestSetEmail(t *testing.T) {
    if err := _TestExpectedStdinFunc("email@test.com", setEmail); err != nil {
        t.Error(err)
        return
    }
    fmt.Println("success")
}

func _TestExpectedStdinFunc(expected string, f func() string) error {
    content := []byte(expected)
    tmpfile, err := ioutil.TempFile("", "example")
    if err != nil {
        return err
    }   defer os.Remove(tmpfile.Name()) // clean up

    if _, err := tmpfile.Write(content); err != nil {
        return err
    }
    if _, err := tmpfile.Seek(0, 0); err != nil {
        return err
    }

    oldStdin := os.Stdin
    defer func() { os.Stdin = oldStdin }()

    os.Stdin = tmpfile
    actual := f()
    if actual != expected {
        return fmt.Errorf("test failed, exptected: %s actual: %s", expected, actual)
    }

    if err := tmpfile.Close(); err != nil {
        return err
    }
    return nil
}

The problem is that Promptui validation in setEmail(beneath code) gets called one char at the time giving this:


✗ Input your Email: █
 e 
✗ Input your Email: e█
e 
 m 
✗ Input your Email: em█
m 
 a 
✗ Input your Email: ema█
a 
 i 
✗ Input your Email: emai█
i 
 l 
✗ Input your Email: email█
l 
 @ 
✗ Input your Email: email@█
@ 
 t 
✗ Input your Email: email@t█
t 
 e 
✗ Input your Email: email@te█
e 
 s 
✗ Input your Email: email@tes█
s 
 t 
✗ Input your Email: email@test█
t 
 . 
✗ Input your Email: email@test.█
. 
 c 
✗ Input your Email: email@test.c█
c 
 o 
✗ Input your Email: email@test.co█
o 
 m 
✗ Input your Email: email@test.com█

Code: Note: printStdin func is just to verify stdin has values, and therefore commented out(//)

package mypackage

import (
    "bufio"
    "errors"
    "fmt"
    "io/ioutil"
    "log"
    "os"
    "strconv"

    "github.com/manifoldco/promptui"
)

func setEmail() string {
    emailValidations := func(input string) error {
        _, err := strconv.ParseFloat(input, 64)
        if err != nil {
            return errors.New("Invalid number")
        }
        return nil
    }

    // stdin := os.Stdin
    rc := ioutil.NopCloser(bufio.NewReader(os.Stdin))
    // printStdin(os.Stdin)

    prompt := promptui.Prompt{
        Label:    "Input your Email",
        Validate: emailValidations,
        Stdin:    rc, // stdin
    }

    email, err := prompt.Run()
    if err != nil {
        fmt.Println("failed getting email")
        // os.exit(3)
    }
    return email
}

func printStdin(file *os.File) {

    fi, err := file.Stat()
    if err != nil {
        fmt.Println("file.Stat()", err)
    }

    size := fi.Size()
    if size > 0 {
        fmt.Printf("%v bytes available in Stdin\n", size)
    } else {
        fmt.Println("Stdin is empty")
    }

    scanner := bufio.NewScanner(file)

    for scanner.Scan() {
        fmt.Println(scanner.Text())
    }
    if err := scanner.Err(); err != nil {
        log.Fatal(err)
    }
}
tamj0rd2 commented 2 years ago

How did you fix it?