supermon: add first simple test for writing a file

Also removes op.symbols, since the map was computed at operator
construction time, and never updated to match the actual symbol table
as it changed.
This commit is contained in:
Zellyn Hunter 2016-11-30 22:29:42 -05:00
parent b9a838400c
commit 55e515554f
2 changed files with 80 additions and 21 deletions

View File

@ -242,6 +242,10 @@ type Symbol struct {
Link int Link int
} }
func (s Symbol) String() string {
return fmt.Sprintf("{%s:%04X:%d}", s.Name, s.Address, s.Link)
}
// decodeSymbol decodes a Super-Mon encoded symbol table entry, // decodeSymbol decodes a Super-Mon encoded symbol table entry,
// returning the string representation. // returning the string representation.
func decodeSymbol(five []byte, extra byte) string { func decodeSymbol(five []byte, extra byte) string {
@ -420,6 +424,17 @@ func (st SymbolTable) SymbolsByAddress() map[uint16][]Symbol {
return result return result
} }
// SymbolsForAddress returns a slice of symbols for a given address.
func (st SymbolTable) SymbolsForAddress(address uint16) []Symbol {
result := []Symbol{}
for _, symbol := range st {
if symbol.Address == address {
result = append(result, symbol)
}
}
return result
}
// DeleteSymbol deletes an existing symbol. Returns true if the named // DeleteSymbol deletes an existing symbol. Returns true if the named
// symbol was found. // symbol was found.
func (st SymbolTable) DeleteSymbol(name string) bool { func (st SymbolTable) DeleteSymbol(name string) bool {
@ -483,7 +498,8 @@ func (st SymbolTable) AddSymbol(name string, address uint16) error {
// NameForFile returns a string representation of a filename: // NameForFile returns a string representation of a filename:
// either DFxx, or a symbol, if one exists for that value. // either DFxx, or a symbol, if one exists for that value.
func NameForFile(file byte, symbols []Symbol) string { func NameForFile(file byte, st SymbolTable) string {
symbols := st.SymbolsForAddress(0xDF00 + uint16(file))
if len(symbols) > 0 { if len(symbols) > 0 {
return symbols[0].Name return symbols[0].Name
} }
@ -492,7 +508,8 @@ func NameForFile(file byte, symbols []Symbol) string {
// FullnameForFile returns a string representation of a filename: // FullnameForFile returns a string representation of a filename:
// either DFxx, or a DFxx:symbol, if one exists for that value. // either DFxx, or a DFxx:symbol, if one exists for that value.
func FullnameForFile(file byte, symbols []Symbol) string { func FullnameForFile(file byte, st SymbolTable) string {
symbols := st.SymbolsForAddress(0xDF00 + uint16(file))
if len(symbols) > 0 { if len(symbols) > 0 {
return fmt.Sprintf("DF%02X:%s", file, symbols[0].Name) return fmt.Sprintf("DF%02X:%s", file, symbols[0].Name)
} }
@ -573,7 +590,6 @@ type operator struct {
sd disk.SectorDisk sd disk.SectorDisk
sm SectorMap sm SectorMap
st SymbolTable st SymbolTable
symbols map[uint16][]Symbol
} }
var _ disk.Operator = operator{} var _ disk.Operator = operator{}
@ -603,10 +619,9 @@ func (o operator) Catalog(subdir string) ([]disk.Descriptor, error) {
if l == 0 { if l == 0 {
continue continue
} }
fileAddr := 0xDF00 + uint16(file)
descs = append(descs, disk.Descriptor{ descs = append(descs, disk.Descriptor{
Name: NameForFile(file, o.symbols[fileAddr]), Name: NameForFile(file, o.st),
Fullname: FullnameForFile(file, o.symbols[fileAddr]), Fullname: FullnameForFile(file, o.st),
Sectors: l, Sectors: l,
Length: l * 256, Length: l * 256,
Locked: false, Locked: false,
@ -630,7 +645,7 @@ func (o operator) GetFile(filename string) (disk.FileInfo, error) {
return disk.FileInfo{}, fmt.Errorf("file DF%02x not fount", file) return disk.FileInfo{}, fmt.Errorf("file DF%02x not fount", file)
} }
desc := disk.Descriptor{ desc := disk.Descriptor{
Name: NameForFile(file, o.symbols[0xDF00+uint16(file)]), Name: NameForFile(file, o.st),
Sectors: len(data) / 256, Sectors: len(data) / 256,
Length: len(data), Length: len(data),
Locked: false, Locked: false,
@ -684,6 +699,7 @@ func (o operator) PutFile(fileInfo disk.FileInfo, overwrite bool) (existed bool,
if err != nil { if err != nil {
return false, err return false, err
} }
fmt.Printf("PLUGH: numFile: %v, namedFile: %v, symbol: %v\n", numFile, namedFile, symbol)
if symbol != "" { if symbol != "" {
if o.st == nil { if o.st == nil {
return false, fmt.Errorf("cannot use symbolic names on disks without valid symbol tables in files 0x03 and 0x04") return false, fmt.Errorf("cannot use symbolic names on disks without valid symbol tables in files 0x03 and 0x04")
@ -703,9 +719,10 @@ func (o operator) PutFile(fileInfo disk.FileInfo, overwrite bool) (existed bool,
return existed, err return existed, err
} }
if namedFile != numFile && symbol != "" { if namedFile != numFile && symbol != "" {
if err := o.st.AddSymbol(symbol, 0xDF+uint16(numFile)); err != nil { if err := o.st.AddSymbol(symbol, 0xDF00+uint16(numFile)); err != nil {
return existed, err return existed, err
} }
fmt.Println("PLUGH: about to write symbol table: %v", o.st)
if err := o.sm.WriteSymbolTable(o.sd, o.st); err != nil { if err := o.sm.WriteSymbolTable(o.sd, o.st); err != nil {
return existed, err return existed, err
} }
@ -729,7 +746,6 @@ func operatorFactory(sd disk.SectorDisk) (disk.Operator, error) {
st, err := sm.ReadSymbolTable(sd) st, err := sm.ReadSymbolTable(sd)
if err == nil { if err == nil {
op.st = st op.st = st
op.symbols = st.SymbolsByAddress()
} }
return op, nil return op, nil

View File

@ -13,6 +13,18 @@ import (
const testDisk = "testdata/chacha20.dsk" const testDisk = "testdata/chacha20.dsk"
const cities = `It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way - in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.`
// The extra newline pads us to 256 bytes…
const hamlet = `To be, or not to be, that is the question:
Whether 'tis Nobler in the mind to suffer
The Slings and Arrows of outrageous Fortune,
Or to take Arms against a Sea of troubles,
And by opposing end them: to die, to sleep
No more; and by a sleep, to say we end
`
// loadSectorMap loads a sector map for the disk image contained in // loadSectorMap loads a sector map for the disk image contained in
// filename. It returns the sector map and a sector disk. // filename. It returns the sector map and a sector disk.
func loadSectorMap(filename string) (SectorMap, disk.SectorDisk, error) { func loadSectorMap(filename string) (SectorMap, disk.SectorDisk, error) {
@ -127,15 +139,7 @@ func TestGetFile(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
got := string(file.Data) got := string(file.Data)
// The extra newline pads us to 256 bytes… want := hamlet
want := `To be, or not to be, that is the question:
Whether 'tis Nobler in the mind to suffer
The Slings and Arrows of outrageous Fortune,
Or to take Arms against a Sea of troubles,
And by opposing end them: to die, to sleep
No more; and by a sleep, to say we end
`
if got != want { if got != want {
t.Errorf("Incorrect result for GetFile(\"TOBE\"): want %q; got %q", want, got) t.Errorf("Incorrect result for GetFile(\"TOBE\"): want %q; got %q", want, got)
} }
@ -205,3 +209,42 @@ func TestReadWriteSymbolTable(t *testing.T) {
t.Fatal("Saved and reloaded symbol table differs from original symbol table") t.Fatal("Saved and reloaded symbol table differs from original symbol table")
} }
} }
// TestPutFile tests the creation of a file, using the Operator
// interface.
func TestPutFile(t *testing.T) {
sd, err := disk.Open(testDisk)
if err != nil {
t.Fatal(err)
}
op, err := disk.OperatorFor(sd)
if err != nil {
t.Fatal(err)
}
contents := []byte(cities)
fileInfo := disk.FileInfo{
Descriptor: disk.Descriptor{
Name: "FNEWFILE",
Length: len(contents),
Type: disk.FiletypeBinary,
},
Data: contents,
}
existed, err := op.PutFile(fileInfo, false)
if err != nil {
t.Fatal(err)
}
if existed {
t.Errorf("want existed=%v; got %v", false, existed)
}
fds, err := op.Catalog("")
if err != nil {
t.Fatal(err)
}
last := fds[len(fds)-1]
want := "DF0B:FNEWFILE"
if got := last.Fullname; got != want {
t.Fatalf("Want last file on disk's FullName=%q; got %q", want, got)
}
}