Издевательский bufio.сканер вход - PullRequest
0 голосов
/ 28 января 2019

У меня был большой успех в определении интерфейсов и замене макетов во время тестирования, но я столкнулся с проблемой с имитацией bufio.Scanner input:

file := &mockFile{
    ReadFunc: func(p []byte) (int, error) {
        reader := bufio.NewReader(bytes.NewReader([]byte(consulPropertiesFile)))
        return reader.Read(p)
    },
    CloseFunc: func() error {
        return nil
    },
}

fs := &mockFileSystem{
    OpenFunc: func(name string) (File, error) {
        return file, nil
    },
}

properties, err := readConsulPropertiesFile(fs)

Хотя, похоже, это работает, как толькосканер дошел до конца моей строки, кажется, он просто возвращается в начало и читает слишком много (на этот раз кажется, что он прочитал больше, чем строку).Как будто мне нужно вручную возвратить ошибку EOF в соответствующее время в моем ReadFunc, но я не уверен, как выяснить, когда мне следует это сделать ...

Код сканера (снято с здесь ):

f, err := file.Open("/run/secrets/consul-web4.properties")
if err != nil {
    return nil, err
}
defer f.Close()

properties := map[string]string{}

scanner := bufio.NewScanner(f)
for scanner.Scan() {
    line := scanner.Text()
    if equal := strings.Index(line, "="); equal >= 0 {
        if key := strings.TrimSpace(line[:equal]); len(key) > 0 {
            value := ""
            if len(line) > equal {
                value = strings.TrimSpace(line[equal+1:])
            }
            properties[key] = value
        }
    }
}

Я еще не реорганизовал вышеуказанное ...

Я пробовал следующие варианты моей тестовой строки:

const input = `key=value
key=value
key=value
`
const input = "key=value\nkey=value\nkey=value\n"

И я попробовал реализации bufio.Reader и io.Reader.

Любая помощь / понимание приветствуется!

1 Ответ

0 голосов
/ 28 января 2019

Спасибо @Adrian:

По пути домой я понял, что это, вероятно, связано с созданием нового читателя каждый раз, когда вызывается метод.Удаление экземпляра читателя из моего ReadFunc работало отлично!

И спасибо @Thundercat за подсказку strings.NewReader(), обновленный код:

reader := ioutil.NopCloser(strings.NewReader(consulPropertiesFile))

file := &mockFile{
    ReadFunc: func(p []byte) (int, error) {
        return reader.Read(p)
    },
    CloseFunc: func() error {
        return nil
    },
}

Для всех, кто ищет этот пост, ищетинформация о том, как макетировать файловую систему и т. д .:

Интерфейс для открытия и статистики файлов, а также конкретная реализация с использованием пакета os:

// FileSystem - interface to the filesystem
type FileSystem interface {
    Open(name string) (File, error)
    Stat(name string) (os.FileInfo, error)
}

// OsFS - filesystem backed by default os package
type OsFS struct {
}

// Open - open a file
func (o *OsFS) Open(name string) (File, error) {
    return os.Open(name)
}

// Stat - get file status
func (o *OsFS) Stat(name string) (os.FileInfo, error) {
    return os.Stat(name)
}

Указанный выше интерфейс файла:

// File - file interface
type File interface {
    io.Closer
    io.Reader
    io.ReaderAt
    io.Seeker
    Stat() (os.FileInfo, error)
}

Создайте макет файла, который вы хотите вернуть вашей файловой системе (реализуйте методы, которые будут использоваться вашим кодом):

type mockFile struct {
    CloseFunc  func() error
    ReadFunc   func(p []byte) (int, error)
    ReadAtFunc func(p []byte, off int64) (int, error)
    SeekFunc   func(offset int64, whence int) (int64, error)
    StatFunc   func() (os.FileInfo, error)
}

func (m *mockFile) Close() error {
    return m.CloseFunc()
}

func (m *mockFile) Read(p []byte) (int, error) {
    return m.ReadFunc(p)
}

func (m *mockFile) ReadAt(p []byte, off int64) (int, error) {
    return m.ReadAtFunc(p, off)
}

func (m *mockFile) Seek(offset int64, whence int) (int64, error) {
    return m.SeekFunc(offset, whence)
}

func (m *mockFile) Stat() (os.FileInfo, error) {
    return m.StatFunc()
}

---

reader := ioutil.NopCloser(strings.NewReader("some string, replace with bytes etc"))

file := &mockFile{
    ReadFunc: func(p []byte) (int, error) {
        return reader.Read(p)
    },
    CloseFunc: func() error {
        return nil
    },
}

И верните свой mockFile через mockFileSystem:

fs := &mockFileSystem{
    OpenFunc: func(name string) (File, error) {
        return file, nil
    },
}
...