294 lines
7.5 KiB
Go
294 lines
7.5 KiB
Go
|
// +build step3 !step1,!step2
|
||
|
|
||
|
package robot
|
||
|
|
||
|
import "testing"
|
||
|
|
||
|
// Step 3 has three major changes:
|
||
|
//
|
||
|
// * Robots run scripts rather than respond to individual commands.
|
||
|
// * A log channel allows robots and the room to log messages.
|
||
|
// * The room allows multiple robots to exist and operate concurrently.
|
||
|
//
|
||
|
// Step 3 API:
|
||
|
//
|
||
|
// StartRobot3(name, script string, action chan Action3, log chan string)
|
||
|
// Room3(extent Rect, robots []Step3Robot, action chan Action3, report chan []Step3Robot, log chan string)
|
||
|
//
|
||
|
// Again, you define Action3.
|
||
|
//
|
||
|
// For the final position report sent from StartRobot3, you can return the same slice
|
||
|
// received from the robots channel, just with updated positions and directions.
|
||
|
//
|
||
|
// Messages must be sent on the log channel for
|
||
|
// * A robot without a name
|
||
|
// * Duplicate robot names
|
||
|
// * Robots placed at the same place
|
||
|
// * A robot placed outside of the room
|
||
|
// * An undefined command in a script
|
||
|
// * An action from an unknown robot
|
||
|
// * A robot attempting to advance into a wall
|
||
|
// * A robot attempting to advance into another robot
|
||
|
|
||
|
var testOneRobot = []struct {
|
||
|
cmd byte
|
||
|
Step2Robot
|
||
|
nMsg int
|
||
|
}{
|
||
|
// (test2 data with message counts added)
|
||
|
{' ', Step2Robot{N, Pos{1, 1}}, 0},
|
||
|
{'A', Step2Robot{N, Pos{1, 2}}, 0},
|
||
|
{'R', Step2Robot{E, Pos{1, 2}}, 0},
|
||
|
{'A', Step2Robot{E, Pos{2, 2}}, 0},
|
||
|
{'L', Step2Robot{N, Pos{2, 2}}, 0},
|
||
|
{'L', Step2Robot{W, Pos{2, 2}}, 0},
|
||
|
{'L', Step2Robot{S, Pos{2, 2}}, 0},
|
||
|
{'A', Step2Robot{S, Pos{2, 1}}, 0},
|
||
|
{'R', Step2Robot{W, Pos{2, 1}}, 0},
|
||
|
{'A', Step2Robot{W, Pos{1, 1}}, 0},
|
||
|
{'A', Step2Robot{W, Pos{1, 1}}, 1}, // bump W wall
|
||
|
{'L', Step2Robot{S, Pos{1, 1}}, 1},
|
||
|
{'A', Step2Robot{S, Pos{1, 1}}, 2}, // bump S wall
|
||
|
{'L', Step2Robot{E, Pos{1, 1}}, 2},
|
||
|
{'A', Step2Robot{E, Pos{2, 1}}, 2},
|
||
|
{'A', Step2Robot{E, Pos{2, 1}}, 3}, // bump E wall
|
||
|
{'L', Step2Robot{N, Pos{2, 1}}, 3},
|
||
|
{'A', Step2Robot{N, Pos{2, 2}}, 3},
|
||
|
{'A', Step2Robot{N, Pos{2, 2}}, 4}, // bump N wall
|
||
|
}
|
||
|
|
||
|
func logMon(log chan string, nMsg chan int, t *testing.T) {
|
||
|
n := 0
|
||
|
for msg := range log {
|
||
|
t.Log("Sim:", msg)
|
||
|
n++
|
||
|
}
|
||
|
nMsg <- n
|
||
|
}
|
||
|
|
||
|
// Same tests as step 2; single robot, but expect log messages on wall bumps.
|
||
|
func TestOneStep3(t *testing.T) {
|
||
|
for i := 1; i <= len(testOneRobot); i++ {
|
||
|
log := make(chan string)
|
||
|
nMsg := make(chan int)
|
||
|
go logMon(log, nMsg, t)
|
||
|
act := make(chan Action3)
|
||
|
rep := make(chan []Step3Robot)
|
||
|
go Room3(
|
||
|
Rect{Pos{1, 1}, Pos{2, 2}},
|
||
|
[]Step3Robot{{"Robbie", testOneRobot[0].Step2Robot}},
|
||
|
act, rep, log)
|
||
|
scr := ""
|
||
|
for j := 1; j < i; j++ {
|
||
|
scr += string(testOneRobot[j].cmd)
|
||
|
}
|
||
|
t.Logf("Script %q", scr)
|
||
|
go StartRobot3("Robbie", scr, act, log)
|
||
|
pls := <-rep
|
||
|
lastTest := testOneRobot[i-1]
|
||
|
if len(pls) != 1 {
|
||
|
t.Fatalf("Got report on %d robots, want 1.", len(pls))
|
||
|
}
|
||
|
pl := pls[0]
|
||
|
if pl.Name != "Robbie" {
|
||
|
t.Fatalf(`Got report for robot %q, want report for "Robbie".`,
|
||
|
pl.Name)
|
||
|
}
|
||
|
da := pl.Step2Robot
|
||
|
want := lastTest.Step2Robot
|
||
|
if da.Pos != want.Pos {
|
||
|
t.Fatalf("Script %q, Pos = %v, want %v", scr, da.Pos, want.Pos)
|
||
|
}
|
||
|
if da.Dir != want.Dir {
|
||
|
t.Fatalf("Script %q, Dir = %v, want %v", scr, da.Dir, want.Dir)
|
||
|
}
|
||
|
close(log)
|
||
|
if n := <-nMsg; n != lastTest.nMsg {
|
||
|
t.Errorf("%d sim messages logged, want %d.", n, lastTest.nMsg)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestNoName(t *testing.T) {
|
||
|
log := make(chan string)
|
||
|
nMsg := make(chan int)
|
||
|
go logMon(log, nMsg, t)
|
||
|
act := make(chan Action3)
|
||
|
rep := make(chan []Step3Robot)
|
||
|
go Room3(
|
||
|
Rect{Pos{1, 1}, Pos{1, 1}},
|
||
|
[]Step3Robot{{"", Step2Robot{N, Pos{1, 1}}}},
|
||
|
act, rep, log)
|
||
|
go StartRobot3("", "", act, log)
|
||
|
<-rep
|
||
|
close(log)
|
||
|
if n := <-nMsg; n != 1 {
|
||
|
t.Fatalf("Got %d messages, want 1.", n)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSameName(t *testing.T) {
|
||
|
log := make(chan string)
|
||
|
nMsg := make(chan int)
|
||
|
go logMon(log, nMsg, t)
|
||
|
act := make(chan Action3)
|
||
|
rep := make(chan []Step3Robot)
|
||
|
go Room3(
|
||
|
Rect{Pos{1, 1}, Pos{2, 1}},
|
||
|
[]Step3Robot{
|
||
|
{"Daryl", Step2Robot{N, Pos{1, 1}}},
|
||
|
{"Daryl", Step2Robot{N, Pos{2, 1}}},
|
||
|
},
|
||
|
act, rep, log)
|
||
|
go StartRobot3("Daryl", "", act, log)
|
||
|
go StartRobot3("Daryl", "", act, log)
|
||
|
<-rep
|
||
|
close(log)
|
||
|
if n := <-nMsg; n != 1 {
|
||
|
t.Fatalf("Got %d messages, want 1.", n)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSamePosition(t *testing.T) {
|
||
|
log := make(chan string)
|
||
|
nMsg := make(chan int)
|
||
|
go logMon(log, nMsg, t)
|
||
|
act := make(chan Action3)
|
||
|
rep := make(chan []Step3Robot)
|
||
|
go Room3(
|
||
|
Rect{Pos{1, 1}, Pos{100, 100}},
|
||
|
[]Step3Robot{
|
||
|
{"Matter", Step2Robot{N, Pos{23, 47}}},
|
||
|
{"Antimatter", Step2Robot{N, Pos{23, 47}}},
|
||
|
},
|
||
|
act, rep, log)
|
||
|
go StartRobot3("Matter", "", act, log)
|
||
|
go StartRobot3("Antimatter", "", act, log)
|
||
|
<-rep
|
||
|
close(log)
|
||
|
if n := <-nMsg; n != 1 {
|
||
|
t.Fatalf("Got %d messages, want 1.", n)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestOutsideRoom(t *testing.T) {
|
||
|
log := make(chan string)
|
||
|
nMsg := make(chan int)
|
||
|
go logMon(log, nMsg, t)
|
||
|
act := make(chan Action3)
|
||
|
rep := make(chan []Step3Robot)
|
||
|
go Room3(
|
||
|
Rect{Pos{1, 1}, Pos{1, 1}},
|
||
|
[]Step3Robot{{"Elvis", Step2Robot{N, Pos{2, 3}}}},
|
||
|
act, rep, log)
|
||
|
go StartRobot3("Elvis", "", act, log)
|
||
|
<-rep
|
||
|
close(log)
|
||
|
if n := <-nMsg; n != 1 {
|
||
|
t.Fatalf("Got %d messages, want 1.", n)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestBadCommand(t *testing.T) {
|
||
|
log := make(chan string)
|
||
|
nMsg := make(chan int)
|
||
|
go logMon(log, nMsg, t)
|
||
|
act := make(chan Action3)
|
||
|
rep := make(chan []Step3Robot)
|
||
|
go Room3(
|
||
|
Rect{Pos{0, 0}, Pos{0, 99}},
|
||
|
[]Step3Robot{{"Vgr", Step2Robot{N, Pos{0, 99}}}},
|
||
|
act, rep, log)
|
||
|
go StartRobot3("Vgr", "RET", act, log)
|
||
|
<-rep
|
||
|
close(log)
|
||
|
if n := <-nMsg; n != 1 {
|
||
|
t.Fatalf("Got %d messages, want 1.", n)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestBadRobot(t *testing.T) {
|
||
|
log := make(chan string)
|
||
|
nMsg := make(chan int)
|
||
|
go logMon(log, nMsg, t)
|
||
|
act := make(chan Action3)
|
||
|
rep := make(chan []Step3Robot)
|
||
|
go Room3(
|
||
|
Rect{Pos{0, 0}, Pos{0, 0}},
|
||
|
[]Step3Robot{{"Data", Step2Robot{N, Pos{0, 0}}}},
|
||
|
act, rep, log)
|
||
|
go StartRobot3("Lore", "A", act, log)
|
||
|
<-rep
|
||
|
close(log)
|
||
|
if n := <-nMsg; n != 1 {
|
||
|
t.Fatalf("Got %d messages, want 1.", n)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestThree(t *testing.T) { // no bumping
|
||
|
log := make(chan string)
|
||
|
nMsg := make(chan int)
|
||
|
go logMon(log, nMsg, t)
|
||
|
act := make(chan Action3)
|
||
|
go StartRobot3("clutz", "LAAARALA", act, log)
|
||
|
go StartRobot3("sphero", "RRAAAAALA", act, log)
|
||
|
go StartRobot3("roomba", "LAAARRRALLLL", act, log)
|
||
|
rep := make(chan []Step3Robot)
|
||
|
go Room3(
|
||
|
Rect{Pos{-10, -10}, Pos{15, 10}},
|
||
|
[]Step3Robot{
|
||
|
{"clutz", Step2Robot{N, Pos{0, 0}}},
|
||
|
{"sphero", Step2Robot{E, Pos{2, -7}}},
|
||
|
{"roomba", Step2Robot{S, Pos{8, 4}}},
|
||
|
},
|
||
|
act, rep, log)
|
||
|
pls := <-rep
|
||
|
if len(pls) != 3 {
|
||
|
t.Fatalf("Got report on %d robots, want 3.", len(pls))
|
||
|
}
|
||
|
exp:
|
||
|
for _, exp := range []Step3Robot{
|
||
|
{"clutz", Step2Robot{W, Pos{-4, 1}}},
|
||
|
{"sphero", Step2Robot{S, Pos{-3, -8}}},
|
||
|
{"roomba", Step2Robot{N, Pos{11, 5}}},
|
||
|
} {
|
||
|
for _, pl := range pls {
|
||
|
if pl.Name != exp.Name {
|
||
|
continue
|
||
|
}
|
||
|
if pl.Step2Robot.Pos != exp.Step2Robot.Pos {
|
||
|
t.Fatalf("%s at %v, want %v",
|
||
|
pl.Name, pl.Step2Robot.Pos, exp.Step2Robot.Pos)
|
||
|
}
|
||
|
if pl.Step2Robot.Dir != exp.Step2Robot.Dir {
|
||
|
t.Fatalf("%s facing %v, want %v",
|
||
|
pl.Name, pl.Step2Robot.Dir, exp.Step2Robot.Dir)
|
||
|
}
|
||
|
continue exp
|
||
|
}
|
||
|
t.Fatalf("Missing %s", exp.Name)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestBattle(t *testing.T) {
|
||
|
log := make(chan string)
|
||
|
nMsg := make(chan int)
|
||
|
go logMon(log, nMsg, t)
|
||
|
act := make(chan Action3)
|
||
|
go StartRobot3("Toro", "AAAAAAA", act, log)
|
||
|
go StartRobot3("Phere", "AAAAAAA", act, log)
|
||
|
rep := make(chan []Step3Robot)
|
||
|
go Room3(
|
||
|
Rect{Pos{1, 1}, Pos{9, 9}},
|
||
|
[]Step3Robot{
|
||
|
{"Toro", Step2Robot{E, Pos{1, 5}}},
|
||
|
{"Phere", Step2Robot{W, Pos{9, 5}}},
|
||
|
},
|
||
|
act, rep, log)
|
||
|
<-rep
|
||
|
close(log)
|
||
|
if n := <-nMsg; n != 7 {
|
||
|
t.Fatalf("Got %d messages, want 7.", n)
|
||
|
}
|
||
|
}
|