mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
Implement early printf functionality
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.
This commit is contained in:
181
kernel/kfmt/early/early_fmt_test.go
Normal file
181
kernel/kfmt/early/early_fmt_test.go
Normal file
@@ -0,0 +1,181 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user