Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added test-coverage for the console output functions #123

Merged
merged 4 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 44 additions & 30 deletions consoleout/console_adm3a.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package consoleout

import "fmt"
import (
"fmt"
"io"
"os"
)

// Adm3AOutputDriver holds our state.
type Adm3AOutputDriver struct {
Expand All @@ -13,6 +17,9 @@ type Adm3AOutputDriver struct {

// y stores the cursor Y
y uint8

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

// GetName returns the name of this driver.
Expand All @@ -31,40 +38,40 @@ func (a3a *Adm3AOutputDriver) PutCharacter(c uint8) {
case 0:
switch c {
case 0x07: /* BEL: flash screen */
fmt.Printf("\033[?5h\033[?5l")
fmt.Fprintf(a3a.writer, "\033[?5h\033[?5l")
case 0x7F: /* DEL: echo BS, space, BS */
fmt.Printf("\b \b")
fmt.Fprintf(a3a.writer, "\b \b")
case 0x1A: /* adm3a clear screen */
fmt.Printf("\033[H\033[2J")
fmt.Fprintf(a3a.writer, "\033[H\033[2J")
case 0x0C: /* vt52 clear screen */
fmt.Printf("\033[H\033[2J")
fmt.Fprintf(a3a.writer, "\033[H\033[2J")
case 0x1E: /* adm3a cursor home */
fmt.Printf("\033[H")
fmt.Fprintf(a3a.writer, "\033[H")
case 0x1B:
a3a.status = 1 /* esc-prefix */
case 1:
a3a.status = 2 /* cursor motion prefix */
case 2: /* insert line */
fmt.Printf("\033[L")
fmt.Fprintf(a3a.writer, "\033[L")
case 3: /* delete line */
fmt.Printf("\033[M")
fmt.Fprintf(a3a.writer, "\033[M")
case 0x18, 5: /* clear to eol */
fmt.Printf("\033[K")
fmt.Fprintf(a3a.writer, "\033[K")
case 0x12, 0x13:
// nop
default:
fmt.Printf("%c", c)
fmt.Fprintf(a3a.writer, "%c", c)
}
case 1: /* we had an esc-prefix */
switch c {
case 0x1B:
fmt.Printf("%c", c)
fmt.Fprintf(a3a.writer, "%c", c)
case '=', 'Y':
a3a.status = 2
case 'E': /* insert line */
fmt.Printf("\033[L")
fmt.Fprintf(a3a.writer, "\033[L")
case 'R': /* delete line */
fmt.Printf("\033[M")
fmt.Fprintf(a3a.writer, "\033[M")
case 'B': /* enable attribute */
a3a.status = 4
case 'C': /* disable attribute */
Expand All @@ -75,58 +82,58 @@ func (a3a *Adm3AOutputDriver) PutCharacter(c uint8) {
a3a.status = 8
default: /* some true ANSI sequence? */
a3a.status = 0
fmt.Printf("%c%c", 0x1B, c)
fmt.Fprintf(a3a.writer, "%c%c", 0x1B, c)
}
case 2:
a3a.y = c - ' ' + 1
a3a.status = 3
case 3:
a3a.x = c - ' ' + 1
a3a.status = 0
fmt.Printf("\033[%d;%dH", a3a.y, a3a.x)
fmt.Fprintf(a3a.writer, "\033[%d;%dH", a3a.y, a3a.x)
case 4: /* <ESC>+B prefix */
a3a.status = 0
switch c {
case '0': /* start reverse video */
fmt.Printf("\033[7m")
fmt.Fprintf(a3a.writer, "\033[7m")
case '1': /* start half intensity */
fmt.Printf("\033[1m")
fmt.Fprintf(a3a.writer, "\033[1m")
case '2': /* start blinking */
fmt.Printf("\033[5m")
fmt.Fprintf(a3a.writer, "\033[5m")
case '3': /* start underlining */
fmt.Printf("\033[4m")
fmt.Fprintf(a3a.writer, "\033[4m")
case '4': /* cursor on */
fmt.Printf("\033[?25h")
fmt.Fprintf(a3a.writer, "\033[?25h")
case '5': /* video mode on */
// nop
case '6': /* remember cursor position */
fmt.Printf("\033[s")
fmt.Fprintf(a3a.writer, "\033[s")
case '7': /* preserve status line */
// nop
default:
fmt.Printf("%cB%c", 0x1B, c)
fmt.Fprintf(a3a.writer, "%cB%c", 0x1B, c)
}
case 5: /* <ESC>+C prefix */
a3a.status = 0
switch c {
case '0': /* stop reverse video */
fmt.Printf("\033[27m")
fmt.Fprintf(a3a.writer, "\033[27m")
case '1': /* stop half intensity */
fmt.Printf("\033[m")
fmt.Fprintf(a3a.writer, "\033[m")
case '2': /* stop blinking */
fmt.Printf("\033[25m")
fmt.Fprintf(a3a.writer, "\033[25m")
case '3': /* stop underlining */
fmt.Printf("\033[24m")
fmt.Fprintf(a3a.writer, "\033[24m")
case '4': /* cursor off */
fmt.Printf("\033[?25l")
fmt.Fprintf(a3a.writer, "\033[?25l")
case '6': /* restore cursor position */
fmt.Printf("\033[u")
fmt.Fprintf(a3a.writer, "\033[u")
case '5': /* video mode off */
// nop
case '7': /* don't preserve status line */
// nop
default:
fmt.Printf("%cC%c", 0x1B, c)
fmt.Fprintf(a3a.writer, "%cC%c", 0x1B, c)
}
/* set/clear line/point */
case 6:
Expand All @@ -141,9 +148,16 @@ func (a3a *Adm3AOutputDriver) PutCharacter(c uint8) {

}

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

// init registers our driver, by name.
func init() {
Register("adm-3a", func() ConsoleDriver {
return &Adm3AOutputDriver{}
return &Adm3AOutputDriver{
writer: os.Stdout,
}
})
}
19 changes: 16 additions & 3 deletions consoleout/console_ansi.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package consoleout

import "fmt"
import (
"fmt"
"io"
"os"
)

// AnsiOutputDriver holds our state.
type AnsiOutputDriver struct {
// writer is where we send our output
writer io.Writer
}

// GetName returns the name of this driver.
Expand All @@ -17,12 +23,19 @@ func (ad *AnsiOutputDriver) GetName() string {
//
// This is part of the OutputDriver interface.
func (ad *AnsiOutputDriver) PutCharacter(c uint8) {
fmt.Printf("%c", c)
fmt.Fprintf(ad.writer, "%c", c)
}

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

// init registers our driver, by name.
func init() {
Register("ansi", func() ConsoleDriver {
return &AnsiOutputDriver{}
return &AnsiOutputDriver{
writer: os.Stdout,
}
})
}
43 changes: 43 additions & 0 deletions consoleout/console_null.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package consoleout

import (
"io"
"os"
)

// NullOutputDriver holds our state.
type NullOutputDriver struct {

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

// GetName returns the name of this driver.
//
// This is part of the OutputDriver interface.
func (no *NullOutputDriver) GetName() string {
return "null"
}

// PutCharacter writes the specified character to the console,
// as this is a null-driver nothing happens and instead the output
// is discarded.
//
// This is part of the OutputDriver interface.
func (n *NullOutputDriver) PutCharacter(c uint8) {
// NOTHING HAppens
}

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

// init registers our driver, by name.
func init() {
Register("null", func() ConsoleDriver {
return &NullOutputDriver{
writer: os.Stdout,
}
})
}
59 changes: 58 additions & 1 deletion consoleout/console_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package consoleout

import "testing"
import (
"bytes"
"testing"
)

// TestName ensures we can lookup a driver by name
func TestName(t *testing.T) {
Expand Down Expand Up @@ -52,3 +55,57 @@ func TestChangeDriver(t *testing.T) {
t.Fatalf("driver changed unexpectedly")
}
}

// TestOutput ensures that our two "real" drivers output, as expected
func TestOutput(t *testing.T) {

// Drivers that should produce output
valid := []string{"ansi", "adm-3a"}

for _, nm := range valid {

d, e := New(nm)
if e != nil {
t.Fatalf("failed to lookup driver by name %s:%s", nm, e)
}

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

d.driver.SetWriter(tmp)

for _, c := range "Steve Kemp" {
d.PutCharacter(byte(c))
}

// Test we got the output we expected
if tmp.String() != "Steve Kemp" {
t.Fatalf("output driver %s produced '%s'", d.GetName(), tmp.String())
}
}

}

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

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

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

null.driver.SetWriter(tmp)

null.PutCharacter('s')

if tmp.String() != "" {
t.Fatalf("got output, expected none: '%s'", tmp.String())
}
}
8 changes: 7 additions & 1 deletion consoleout/consoleout.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
// given just a name.
package consoleout

import "fmt"
import (
"fmt"
"io"
)

// ConsoleDriver is the interface that must be implemented by anything
// that wishes to be used as a console driver.
Expand All @@ -19,6 +22,9 @@ type ConsoleDriver interface {

// GetName will return the name of the driver.
GetName() string

// SetWriter will update the writer
SetWriter(io.Writer)
}

// This is a map of known-drivers
Expand Down
2 changes: 1 addition & 1 deletion cpm/cpm.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ type CPM struct {
input *consolein.ConsoleIn

// output is used for writing characters to the conolse
output consoleout.ConsoleDriver
output *consoleout.ConsoleOut

// dma contains the address of the DMA area in RAM.
//
Expand Down
24 changes: 24 additions & 0 deletions static/static_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package static

import (
"strings"
"testing"
)

// TestStatic just ensures we have some files.
func TestStatic(t *testing.T) {

// Read the subdirectory
files, err := Content.ReadDir("A")
if err != nil {
t.Fatalf("error reading contents")
}

// Ensure each file is a .COM files
for _, entry := range files {
name := entry.Name()
if !strings.HasSuffix(name, ".COM") {
t.Fatalf("file '%s' is not a .COM file", name)
}
}
}
17 changes: 17 additions & 0 deletions version/version_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package version

import (
"strings"
"testing"
)

// TestVersion is a nop-test that performs coverage of our version package.
func TestVersion(t *testing.T) {
x := GetVersionString()
y := GetVersionBanner()

// Banner should have our version
if !strings.Contains(y, x) {
t.Fatalf("banner doesn't contain our version")
}
}
Loading