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
}
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,
// returning the string representation.
func decodeSymbol(five []byte, extra byte) string {
@ -420,6 +424,17 @@ func (st SymbolTable) SymbolsByAddress() map[uint16][]Symbol {
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
// symbol was found.
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:
// 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 {
return symbols[0].Name
}
@ -492,7 +508,8 @@ func NameForFile(file byte, symbols []Symbol) string {
// FullnameForFile returns a string representation of a filename:
// 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 {
return fmt.Sprintf("DF%02X:%s", file, symbols[0].Name)
}
@ -570,10 +587,9 @@ func (st SymbolTable) FilesForCompoundName(filename string) (numFile byte, named
// operator is a disk.Operator - an interface for performing
// high-level operations on files and directories.
type operator struct {
sd disk.SectorDisk
sm SectorMap
st SymbolTable
symbols map[uint16][]Symbol
sd disk.SectorDisk
sm SectorMap
st SymbolTable
}
var _ disk.Operator = operator{}
@ -603,10 +619,9 @@ func (o operator) Catalog(subdir string) ([]disk.Descriptor, error) {
if l == 0 {
continue
}
fileAddr := 0xDF00 + uint16(file)
descs = append(descs, disk.Descriptor{
Name: NameForFile(file, o.symbols[fileAddr]),
Fullname: FullnameForFile(file, o.symbols[fileAddr]),
Name: NameForFile(file, o.st),
Fullname: FullnameForFile(file, o.st),
Sectors: l,
Length: l * 256,
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)
}
desc := disk.Descriptor{
Name: NameForFile(file, o.symbols[0xDF00+uint16(file)]),
Name: NameForFile(file, o.st),
Sectors: len(data) / 256,
Length: len(data),
Locked: false,
@ -684,6 +699,7 @@ func (o operator) PutFile(fileInfo disk.FileInfo, overwrite bool) (existed bool,
if err != nil {
return false, err
}
fmt.Printf("PLUGH: numFile: %v, namedFile: %v, symbol: %v\n", numFile, namedFile, symbol)
if symbol != "" {
if o.st == nil {
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
}
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
}
fmt.Println("PLUGH: about to write symbol table: %v", o.st)
if err := o.sm.WriteSymbolTable(o.sd, o.st); err != nil {
return existed, err
}
@ -729,7 +746,6 @@ func operatorFactory(sd disk.SectorDisk) (disk.Operator, error) {
st, err := sm.ReadSymbolTable(sd)
if err == nil {
op.st = st
op.symbols = st.SymbolsByAddress()
}
return op, nil

View File

@ -13,6 +13,18 @@ import (
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
// filename. It returns the sector map and a sector disk.
func loadSectorMap(filename string) (SectorMap, disk.SectorDisk, error) {
@ -127,15 +139,7 @@ func TestGetFile(t *testing.T) {
t.Fatal(err)
}
got := string(file.Data)
// The extra newline pads us to 256 bytes…
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
`
want := hamlet
if got != want {
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")
}
}
// 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)
}
}