Files
coder/console/expect_opt.go
Bryan 6009c90d1d refactor: Rename 'expect' package to 'console' (#297)
Fixes #291 - renames the `expect` go package to `console`, and changes the api from `expect.NewTestConsole` to `console.New`, and a few other small changes to support the linter (ie, `ConsoleOpts` -> `Opts`)
2022-02-15 16:47:33 -08:00

140 lines
3.4 KiB
Go

// Copyright 2018 Netflix, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package console
import (
"bytes"
"strings"
"time"
)
// ExpectOpt allows settings Expect options.
type ExpectOpt func(*ExpectOpts) error
// Callback is a callback function to execute if a match is found for
// the chained matcher.
type Callback func(buf *bytes.Buffer) error
// ExpectOpts provides additional options on Expect.
type ExpectOpts struct {
Matchers []Matcher
ReadTimeout *time.Duration
}
// Match sequentially calls Match on all matchers in ExpectOpts and returns the
// first matcher if a match exists, otherwise nil.
func (eo ExpectOpts) Match(v interface{}) Matcher {
for _, matcher := range eo.Matchers {
if matcher.Match(v) {
return matcher
}
}
return nil
}
// CallbackMatcher is a matcher that provides a Callback function.
type CallbackMatcher interface {
// Callback executes the matcher's callback with the content buffer at the
// time of match.
Callback(buf *bytes.Buffer) error
}
// Matcher provides an interface for finding a match in content read from
// Console's tty.
type Matcher interface {
// Match returns true iff a match is found.
Match(v interface{}) bool
Criteria() interface{}
}
// stringMatcher fulfills the Matcher interface to match strings against a given
// bytes.Buffer.
type stringMatcher struct {
str string
}
func (sm *stringMatcher) Match(v interface{}) bool {
buf, ok := v.(*bytes.Buffer)
if !ok {
return false
}
if strings.Contains(buf.String(), sm.str) {
return true
}
return false
}
func (sm *stringMatcher) Criteria() interface{} {
return sm.str
}
// allMatcher fulfills the Matcher interface to match a group of ExpectOpt
// against any value.
type allMatcher struct {
options ExpectOpts
}
func (am *allMatcher) Match(v interface{}) bool {
var matchers []Matcher
for _, matcher := range am.options.Matchers {
if matcher.Match(v) {
continue
}
matchers = append(matchers, matcher)
}
am.options.Matchers = matchers
return len(matchers) == 0
}
func (am *allMatcher) Criteria() interface{} {
var criteria []interface{}
for _, matcher := range am.options.Matchers {
criteria = append(criteria, matcher.Criteria())
}
return criteria
}
// All adds an Expect condition to exit if the content read from Console's tty
// matches all of the provided ExpectOpt, in any order.
func All(expectOpts ...ExpectOpt) ExpectOpt {
return func(opts *ExpectOpts) error {
var options ExpectOpts
for _, opt := range expectOpts {
if err := opt(&options); err != nil {
return err
}
}
opts.Matchers = append(opts.Matchers, &allMatcher{
options: options,
})
return nil
}
}
// String adds an Expect condition to exit if the content read from Console's
// tty contains any of the given strings.
func String(strs ...string) ExpectOpt {
return func(opts *ExpectOpts) error {
for _, str := range strs {
opts.Matchers = append(opts.Matchers, &stringMatcher{
str: str,
})
}
return nil
}
}