Skip to content

Commit

Permalink
Merge pull request #155 from skx/154-integration
Browse files Browse the repository at this point in the history
154 integration tests
  • Loading branch information
skx authored Jul 13, 2024
2 parents 45f09e2 + 59e57bf commit 61bf02f
Show file tree
Hide file tree
Showing 12 changed files with 291 additions and 28 deletions.
14 changes: 2 additions & 12 deletions consolein/consolein.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func (ci *ConsoleIn) BlockForCharacterNoEcho() (byte, error) {
// Do we have faked/stuffed input to process?
if len(ci.stuffed) > 0 {
c := ci.stuffed[0]
ci.stuffed = ci.stuffed[:1]
ci.stuffed = ci.stuffed[1:]
return c, nil
}

Expand Down Expand Up @@ -160,7 +160,7 @@ func (ci *ConsoleIn) BlockForCharacterWithEcho() (byte, error) {
// Do we have faked/stuffed input to process?
if len(ci.stuffed) > 0 {
c := ci.stuffed[0]
ci.stuffed = ci.stuffed[:1]
ci.stuffed = ci.stuffed[1:]
return c, nil
}

Expand Down Expand Up @@ -205,16 +205,6 @@ func (ci *ConsoleIn) BlockForCharacterWithEcho() (byte, error) {
// Ctrl-p and Ctrl-n.
func (ci *ConsoleIn) ReadLine(max uint8) (string, error) {

// Do we have faked/stuffed input to process?
if len(ci.stuffed) > 0 {

// If so return that fake output, and remove it
// to ensure it is only processed once.
text := ci.stuffed
ci.stuffed = ""
return text, nil
}

// Do we need to change state? If so then do it.
if ci.State != Echo {
ci.enableEcho()
Expand Down
22 changes: 20 additions & 2 deletions consoleout/consoleout.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,19 @@ type ConsoleDriver interface {
SetWriter(io.Writer)
}

// ConsoleRecorder is an interface that allows returning the contents that
// have been previously sent to the console.
//
// This is used solely for integration tests.
type ConsoleRecorder interface {

// GetOutput returns the contents which have been displayed.
GetOutput() string

// Reset removes any stored state.
Reset()
}

// This is a map of known-drivers
var handlers = struct {
m map[string]Constructor
Expand Down Expand Up @@ -68,6 +81,11 @@ func New(name string) (*ConsoleOut, error) {
}, nil
}

// GetDriver allows getting our driver at runtime.
func (co *ConsoleOut) GetDriver() ConsoleDriver {
return co.driver
}

// ChangeDriver allows changing our driver at runtime.
func (co *ConsoleOut) ChangeDriver(name string) error {

Expand All @@ -89,12 +107,12 @@ func (co *ConsoleOut) GetName() string {

// GetDrivers returns all available driver-names.
//
// We hide the internal "null" driver.
// We hide the internal "null", and "logger" drivers.
func (co *ConsoleOut) GetDrivers() []string {
valid := []string{}

for x := range handlers.m {
if x != "null" {
if x != "null" && x != "logger" {
valid = append(valid, x)
}
}
Expand Down
48 changes: 48 additions & 0 deletions consoleout/console_test.go → consoleout/consoleout_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ func TestName(t *testing.T) {
if d.GetName() != nm {
t.Fatalf("%s != %s", d.GetName(), nm)
}
if d.GetDriver().GetName() != nm {
t.Fatalf("%s != %s", d.GetDriver().GetName(), nm)
}
}

// Lookup a driver that wont exist
Expand Down Expand Up @@ -98,6 +101,10 @@ func TestNull(t *testing.T) {
t.Fatalf("null driver has the wrong name")
}

if null.GetDriver().GetName() != null.GetName() {
t.Fatalf("getting driver went wrong")
}

// ensure we redirect the output
tmp := &bytes.Buffer{}

Expand All @@ -110,6 +117,47 @@ func TestNull(t *testing.T) {
}
}

// TestLogger ensures nothing is written by the logging output driver
func TestLogger(t *testing.T) {

// Start with a known-good driver
drv, err := New("logger")
if err != nil {
t.Fatalf("failed to load starting driver %s", err)
}
if drv.GetName() != "logger" {
t.Fatalf("driver has the wrong name")
}

if drv.GetDriver().GetName() != drv.GetName() {
t.Fatalf("getting driver went wrong")
}

// ensure we redirect the output
tmp := &bytes.Buffer{}

drv.driver.SetWriter(tmp)

drv.PutCharacter('s')
drv.PutCharacter('t')
drv.PutCharacter('e')
drv.PutCharacter('v')
drv.PutCharacter('e')

if tmp.String() != "" {
t.Fatalf("got output, expected none: '%s'", tmp.String())
}

// Cast the driver to get the history
o, ok := drv.GetDriver().(*OutputLoggingDriver)
if !ok {
t.Fatalf("failed to cast driver")
}
if o.GetOutput() != "steve" {
t.Fatalf("wrong history")
}
}

func TestList(t *testing.T) {
x, _ := New("foo")

Expand Down
File renamed without changes.
File renamed without changes.
60 changes: 60 additions & 0 deletions consoleout/drv_logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package consoleout

import (
"io"
"os"
)

// OutputLoggingDriver holds our state.
type OutputLoggingDriver struct {

// writer is where we send our output
writer io.Writer

// history stores our history
history string
}

// GetName returns the name of this driver.
//
// This is part of the OutputDriver interface.
func (ol *OutputLoggingDriver) GetName() string {
return "logger"
}

// PutCharacter writes the specified character to the console,
// as this is a recording-driver nothing happens and instead the output
// is discarded saved into our history
//
// This is part of the OutputDriver interface.
func (ol *OutputLoggingDriver) PutCharacter(c uint8) {
ol.history += string(c)
}

// SetWriter will update the writer.
func (ol *OutputLoggingDriver) SetWriter(w io.Writer) {
ol.writer = w
}

// GetOutput returns our history.
//
// This is part of the ConsoleRecorder interface.
func (ol *OutputLoggingDriver) GetOutput() string {
return ol.history
}

// Reset truncates our saved history.
//
// This is part of the ConsoleRecorder interface.
func (ol *OutputLoggingDriver) Reset() {
ol.history = ""
}

// init registers our driver, by name.
func init() {
Register("logger", func() ConsoleDriver {
return &OutputLoggingDriver{
writer: os.Stdout,
}
})
}
File renamed without changes.
18 changes: 14 additions & 4 deletions cpm/cpm.go
Original file line number Diff line number Diff line change
Expand Up @@ -522,9 +522,9 @@ func (cpm *CPM) Cleanup() {
cpm.input.Reset()
}

// GetOutputDriver returns the name of our configured output driver.
func (cpm *CPM) GetOutputDriver() string {
return cpm.output.GetName()
// GetOutputDriver returns the configured output driver.
func (cpm *CPM) GetOutputDriver() consoleout.ConsoleDriver {
return cpm.output.GetDriver()
}

// GetCCPName returns the name of the CCP we've been configured to load.
Expand Down Expand Up @@ -943,7 +943,7 @@ func (cpm *CPM) RunAutoExec() {
}

// OK we have both files
cpm.input.StuffInput("SUBMIT AUTOEXEC")
cpm.input.StuffInput("SUBMIT AUTOEXEC\n")
}

// SetStaticFilesystem allows adding a reference to an embedded filesyste,.
Expand Down Expand Up @@ -1008,3 +1008,13 @@ func (cpm *CPM) Out(addr uint8, val uint8) {
//
cpm.BiosHandler(val)
}

// StuffText inserts text into the read-buffer of the console
// input-driver.
//
// This is used for two purposes; to drive the "SUBMIT AUTOEXEC"
// integration at run-time, and to support integration tests to be
// written.
func (cpm *CPM) StuffText(input string) {
cpm.input.StuffInput(input)
}
16 changes: 8 additions & 8 deletions cpm/cpm_bdos_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func TestConsoleInput(t *testing.T) {
defer c.Cleanup()

// ReadChar
c.input.StuffInput("s")
c.StuffText("s")
err = BdosSysCallReadChar(c)
if err != nil {
t.Fatalf("failed to call CP/M")
Expand All @@ -32,7 +32,7 @@ func TestConsoleInput(t *testing.T) {
}

// AuxRead
c.input.StuffInput("k")
c.StuffText("k")
err = BdosSysCallAuxRead(c)
if err != nil {
t.Fatalf("failed to call CP/M")
Expand All @@ -42,7 +42,7 @@ func TestConsoleInput(t *testing.T) {
}

// RawIO
c.input.StuffInput("x")
c.StuffText("x")
c.CPU.States.DE.Lo = 0xFF
err = BdosSysCallRawIO(c)
if err != nil {
Expand All @@ -52,7 +52,7 @@ func TestConsoleInput(t *testing.T) {
t.Fatalf("got the wrong input")
}

c.input.StuffInput("x")
c.StuffText("x")
c.CPU.States.DE.Lo = 0xFE
err = BdosSysCallRawIO(c)
if err != nil {
Expand All @@ -62,7 +62,7 @@ func TestConsoleInput(t *testing.T) {
t.Fatalf("got the wrong response")
}

c.input.StuffInput("1")
c.StuffText("1")
c.CPU.States.DE.Lo = 0xFD
err = BdosSysCallRawIO(c)
if err != nil {
Expand All @@ -72,14 +72,14 @@ func TestConsoleInput(t *testing.T) {
t.Fatalf("got the wrong response")
}

c.input.StuffInput("1")
c.StuffText("1")
c.CPU.States.DE.Lo = 42
err = BdosSysCallRawIO(c)
if err != nil {
t.Fatalf("failed to call CP/M")
}

c.input.StuffInput("1")
c.StuffText("1")
err = BdosSysCallConsoleStatus(c)
if err != nil {
t.Fatalf("failed to call CP/M")
Expand Down Expand Up @@ -297,7 +297,7 @@ func TestReadLine(t *testing.T) {

// Stuff some fake input
c.input = consolein.New()
c.input.StuffInput("steve")
c.StuffText("steve\n")

// Setup a buffer, so we can read 5 characters
c.Memory.Set(0x0100, 5)
Expand Down
2 changes: 1 addition & 1 deletion cpm/cpm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func TestSimple(t *testing.T) {
}

// Confirm the output driver is null, as expected
if obj.GetOutputDriver() != "null" {
if obj.GetOutputDriver().GetName() != "null" {
t.Fatalf("console driver name mismatch!")
}
if obj.GetCCPName() != "ccp" {
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ func main() {
}

// Show a startup-banner.
fmt.Printf("\ncpmulator %s loaded CCP %s, with %s output driver\n", cpmver.GetVersionString(), obj.GetCCPName(), obj.GetOutputDriver())
fmt.Printf("\ncpmulator %s loaded CCP %s, with %s output driver\n", cpmver.GetVersionString(), obj.GetCCPName(), obj.GetOutputDriver().GetName())

// We will load AUTOEXEC.SUB, once, if it exists (*)
//
Expand Down
Loading

0 comments on commit 61bf02f

Please sign in to comment.