mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
The kfmt/early package provides a minimal printf implementation that does not use memory allocations (everything is allocated on the stack). This implementation can be used to emit debug messages before the memory manager is initialized.
182 lines
3.8 KiB
Go
182 lines
3.8 KiB
Go
package early
|
|
|
|
import (
|
|
"bytes"
|
|
"testing"
|
|
"unsafe"
|
|
|
|
"github.com/achilleasa/gopher-os/kernel/driver/tty"
|
|
"github.com/achilleasa/gopher-os/kernel/driver/video/console"
|
|
"github.com/achilleasa/gopher-os/kernel/hal"
|
|
)
|
|
|
|
func TestPrintf(t *testing.T) {
|
|
origTerm := hal.ActiveTerminal
|
|
defer func() {
|
|
hal.ActiveTerminal = origTerm
|
|
}()
|
|
|
|
// mute vet warnings about malformed printf formatting strings
|
|
printfn := Printf
|
|
|
|
ega := &console.Ega{}
|
|
fb := make([]uint8, 160*25)
|
|
ega.Init(80, 25, uintptr(unsafe.Pointer(&fb[0])))
|
|
|
|
vt := &tty.Vt{}
|
|
vt.AttachTo(ega)
|
|
hal.ActiveTerminal = vt
|
|
|
|
specs := []struct {
|
|
fn func()
|
|
expOutput string
|
|
}{
|
|
{
|
|
func() { printfn("no args") },
|
|
"no args",
|
|
},
|
|
// bool values
|
|
{
|
|
func() { printfn("%t", true) },
|
|
"true",
|
|
},
|
|
{
|
|
func() { printfn("%41t", false) },
|
|
"false",
|
|
},
|
|
// strings and byte slices
|
|
{
|
|
func() { printfn("%s arg", "STRING") },
|
|
"STRING arg",
|
|
},
|
|
{
|
|
func() { printfn("%s arg", []byte("BYTE SLICE")) },
|
|
"BYTE SLICE arg",
|
|
},
|
|
{
|
|
func() { printfn("'%4s' arg with padding", "ABC") },
|
|
"' ABC' arg with padding",
|
|
},
|
|
{
|
|
func() { printfn("'%4s' arg longer than padding", "ABCDE") },
|
|
"'ABCDE' arg longer than padding",
|
|
},
|
|
// uints
|
|
{
|
|
func() { printfn("uint arg: %d", uint8(10)) },
|
|
"uint arg: 10",
|
|
},
|
|
{
|
|
func() { printfn("uint arg: %o", uint16(0777)) },
|
|
"uint arg: 777",
|
|
},
|
|
{
|
|
func() { printfn("uint arg: %x", uint32(0xbadf00d)) },
|
|
"uint arg: 0xbadf00d",
|
|
},
|
|
{
|
|
func() { printfn("uint arg with padding: '%10d'", uint64(123)) },
|
|
"uint arg with padding: ' 123'",
|
|
},
|
|
{
|
|
func() { printfn("uint arg with padding: '%4o'", uint64(0777)) },
|
|
"uint arg with padding: '0777'",
|
|
},
|
|
{
|
|
func() { printfn("uint arg with padding: '%10x'", uint64(0xbadf00d)) },
|
|
"uint arg with padding: '0x000badf00d'",
|
|
},
|
|
{
|
|
func() { printfn("uint arg longer than padding: '%5x'", int64(0xbadf00d)) },
|
|
"uint arg longer than padding: '0xbadf00d'",
|
|
},
|
|
// pointers
|
|
{
|
|
func() { printfn("uintptr %x", uintptr(0xb8000)) },
|
|
"uintptr 0xb8000",
|
|
},
|
|
// ints
|
|
|
|
{
|
|
func() { printfn("int arg: %d", int8(-10)) },
|
|
"int arg: -10",
|
|
},
|
|
{
|
|
func() { printfn("int arg: %o", int16(0777)) },
|
|
"int arg: 777",
|
|
},
|
|
{
|
|
func() { printfn("int arg: %x", int32(-0xbadf00d)) },
|
|
"int arg: -0xbadf00d",
|
|
},
|
|
{
|
|
func() { printfn("int arg with padding: '%10d'", int64(-12345678)) },
|
|
"int arg with padding: ' -12345678'",
|
|
},
|
|
{
|
|
func() { printfn("int arg with padding: '%10d'", int64(-123456789)) },
|
|
"int arg with padding: '-123456789'",
|
|
},
|
|
{
|
|
func() { printfn("int arg with padding: '%10d'", int64(-1234567890)) },
|
|
"int arg with padding: '-1234567890'",
|
|
},
|
|
{
|
|
func() { printfn("int arg longer than padding: '%5x'", int(-0xbadf00d)) },
|
|
"int arg longer than padding: '-0xbadf00d'",
|
|
},
|
|
// multiple arguments
|
|
{
|
|
func() { printfn("%%%s%d%t", "foo", 123, true) },
|
|
`%foo123true`,
|
|
},
|
|
// errors
|
|
{
|
|
func() { printfn("more args", "foo", "bar", "baz") },
|
|
`more args%!(EXTRA)%!(EXTRA)%!(EXTRA)`,
|
|
},
|
|
{
|
|
func() { printfn("missing args %s") },
|
|
`missing args (MISSING)`,
|
|
},
|
|
{
|
|
func() { printfn("bad verb %Q") },
|
|
`bad verb %!(NOVERB)`,
|
|
},
|
|
{
|
|
func() { printfn("not bool %t", "foo") },
|
|
`not bool %!(WRONGTYPE)`,
|
|
},
|
|
{
|
|
func() { printfn("not int %d", "foo") },
|
|
`not int %!(WRONGTYPE)`,
|
|
},
|
|
{
|
|
func() { printfn("not string %s", 123) },
|
|
`not string %!(WRONGTYPE)`,
|
|
},
|
|
}
|
|
|
|
for specIndex, spec := range specs {
|
|
for index := 0; index < len(fb); index++ {
|
|
fb[index] = 0
|
|
}
|
|
vt.SetPosition(0, 0)
|
|
|
|
spec.fn()
|
|
|
|
var buf bytes.Buffer
|
|
for index := 0; ; index += 2 {
|
|
if fb[index] == 0 {
|
|
break
|
|
}
|
|
|
|
buf.WriteByte(fb[index])
|
|
}
|
|
|
|
if got := buf.String(); got != spec.expOutput {
|
|
t.Errorf("[spec %d] expected to get %q; got %q", specIndex, spec.expOutput, got)
|
|
}
|
|
}
|
|
}
|