mirror of https://github.com/gissleh/irc.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
138 lines
2.7 KiB
138 lines
2.7 KiB
package irctest
|
|
|
|
import (
|
|
"bufio"
|
|
"net"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// An Interaction is a "simulated" server that will trigger the
|
|
// client.
|
|
type Interaction struct {
|
|
wg sync.WaitGroup
|
|
|
|
Strict bool
|
|
Lines []InteractionLine
|
|
Log []string
|
|
Failure *InteractionFailure
|
|
}
|
|
|
|
// Listen listens for a client in a separate goroutine.
|
|
func (interaction *Interaction) Listen() (addr string, err error) {
|
|
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
lines := make([]InteractionLine, len(interaction.Lines))
|
|
copy(lines, interaction.Lines)
|
|
|
|
go func() {
|
|
interaction.wg.Add(1)
|
|
defer interaction.wg.Done()
|
|
|
|
conn, err := listener.Accept()
|
|
if err != nil {
|
|
interaction.Failure = &InteractionFailure{
|
|
Index: -1, NetErr: err,
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
defer conn.Close()
|
|
|
|
reader := bufio.NewReader(conn)
|
|
|
|
for i := 0; i < len(lines); i++ {
|
|
line := lines[i]
|
|
|
|
if line.Data != "" {
|
|
switch line.Kind {
|
|
case 'S':
|
|
{
|
|
_, err := conn.Write(append([]byte(line.Data), '\r', '\n'))
|
|
if err != nil {
|
|
interaction.Failure = &InteractionFailure{
|
|
Index: i, NetErr: err,
|
|
}
|
|
return
|
|
}
|
|
}
|
|
case 'C':
|
|
{
|
|
conn.SetReadDeadline(time.Now().Add(time.Second))
|
|
input, err := reader.ReadString('\n')
|
|
if err != nil {
|
|
interaction.Failure = &InteractionFailure{
|
|
Index: i, NetErr: err,
|
|
}
|
|
return
|
|
}
|
|
input = strings.Replace(input, "\r", "", -1)
|
|
input = strings.Replace(input, "\n", "", 1)
|
|
|
|
match := line.Data
|
|
success := false
|
|
|
|
if strings.HasSuffix(match, "*") {
|
|
success = strings.HasPrefix(input, match[:len(match)-1])
|
|
} else {
|
|
success = match == input
|
|
}
|
|
|
|
interaction.Log = append(interaction.Log, input)
|
|
|
|
if !success {
|
|
if !interaction.Strict {
|
|
i--
|
|
continue
|
|
}
|
|
|
|
interaction.Failure = &InteractionFailure{
|
|
Index: i, Result: input,
|
|
}
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if line.Callback != nil {
|
|
err := line.Callback()
|
|
if err != nil {
|
|
interaction.Failure = &InteractionFailure{
|
|
Index: i, CBErr: err,
|
|
}
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
|
|
return listener.Addr().String(), nil
|
|
}
|
|
|
|
// Wait waits for the setup to be done. It's safe to check
|
|
// Failure after that.
|
|
func (interaction *Interaction) Wait() {
|
|
interaction.wg.Wait()
|
|
}
|
|
|
|
// InteractionFailure signifies a test failure.
|
|
type InteractionFailure struct {
|
|
Index int
|
|
Result string
|
|
NetErr error
|
|
CBErr error
|
|
}
|
|
|
|
// InteractionLine is part of an interaction, whether it is a line
|
|
// that is sent to a client or a line expected from a client.
|
|
type InteractionLine struct {
|
|
Kind byte
|
|
Data string
|
|
Callback func() error
|
|
}
|