Skip to content

Commit a0bd124

Browse files
committed
Adds other tests for ZObject
Implements directly inside ZObject GetDefaultProperty. Little fix to GetPropertyAddr when retrieving the first property address. Creates facility(but badly implemented) for getting property ids in sorted order.
1 parent 2f3b45d commit a0bd124

File tree

4 files changed

+209
-42
lines changed

4 files changed

+209
-42
lines changed

gork/zmachine.go

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -209,17 +209,6 @@ func (zm *ZMachine) ResetObjectParent(objectId uint8, newParentId uint8) {
209209
zm.objects[objectId-1].parent = newParentId
210210
}
211211

212-
func (zm *ZMachine) GetDefaultProperty(propertyIdx byte) uint16 {
213-
// v3
214-
if propertyIdx < 1 || propertyIdx > 31 {
215-
log.Fatalf("Invalid propertyIndex %d, values range in v3 is [1,31]\n", propertyIdx)
216-
}
217-
218-
// property table is a sequence of words
219-
addr := uint32(zm.header.objTblPos) + uint32((propertyIdx-1)*2)
220-
return zm.seq.mem.WordAt(addr)
221-
}
222-
223212
func (zm *ZMachine) InterpretAll() {
224213
for !zm.quitted {
225214
zm.Interpret()

gork/zobject.go

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package gork
22

33
import (
4-
"errors"
54
"fmt"
65
"log"
76
"sort"
@@ -24,6 +23,7 @@ type ZObject struct {
2423
propertiesPos uint16
2524
properties map[byte][]byte
2625
mem *ZMemory
26+
header *ZHeader
2727
}
2828

2929
func NewZObject(mem *ZMemory, number uint8, header *ZHeader) *ZObject {
@@ -36,6 +36,7 @@ func (obj *ZObject) configure(mem *ZMemory, number uint8, header *ZHeader) {
3636
obj.number = number
3737

3838
obj.mem = mem
39+
obj.header = header
3940

4041
seq := mem.GetSequential(ZObjectAddress(number, header))
4142

@@ -121,11 +122,19 @@ func (obj *ZObject) SetProperty(propertyId byte, value uint16) {
121122
}
122123
}
123124

124-
func (obj *ZObject) GetProperty(propertyId byte) (uint16, error) {
125+
func (obj *ZObject) GetProperty(propertyId byte) uint16 {
125126
if _, ok := obj.properties[propertyId]; !ok {
126127
// DON'T PANIC, cause the property could be in the
127128
// global default properties table
128-
return 0, errors.New(fmt.Sprintf("property %d not found\n", propertyId))
129+
130+
// v3
131+
if propertyId < 1 || propertyId > 31 {
132+
log.Fatalf("Invalid propertyIndex %d, values range in v3 is [1,31]\n", propertyId)
133+
}
134+
135+
// property table is a sequence of words
136+
addr := uint32(obj.header.objTblPos) + uint32((propertyId-1)*2)
137+
return obj.mem.WordAt(addr)
129138
}
130139

131140
res := uint16(0)
@@ -142,7 +151,7 @@ func (obj *ZObject) GetProperty(propertyId byte) (uint16, error) {
142151
log.Fatal("cannot get property, because its length is > 2 bytes")
143152
}
144153

145-
return res, nil
154+
return res
146155
}
147156

148157
func GetPropertyLen(mem *ZMemory, propertyPos uint32) uint16 {
@@ -164,7 +173,6 @@ func (obj *ZObject) GetPropertyAddr(propertyId byte) uint32 {
164173

165174
for {
166175
size := obj.mem.ByteAt(addr)
167-
addr++
168176

169177
propno := size & 0x1F
170178

@@ -177,6 +185,9 @@ func (obj *ZObject) GetPropertyAddr(propertyId byte) uint32 {
177185
if propno == propertyId {
178186
return addr
179187
}
188+
// skip size
189+
addr++
190+
180191
addr += uint32((size >> 5) + 1)
181192
}
182193
}
@@ -229,6 +240,22 @@ func ZObjectsCount(mem *ZMemory, header *ZHeader) uint8 {
229240
return count - 1
230241
}
231242

243+
func (obj *ZObject) PropertiesIds() []byte {
244+
var keys []int
245+
for k := range obj.properties {
246+
keys = append(keys, int(k))
247+
}
248+
sort.Sort(sort.Reverse(sort.IntSlice(keys)))
249+
250+
ret := make([]byte, len(keys))
251+
252+
for i, v := range keys {
253+
ret[i] = byte(v)
254+
}
255+
256+
return ret
257+
}
258+
232259
func (obj *ZObject) String() string {
233260
ret := ""
234261

@@ -255,16 +282,10 @@ func (obj *ZObject) String() string {
255282

256283
ret += fmt.Sprintln(" Properties:")
257284

258-
var keys []int
259-
for k := range obj.properties {
260-
keys = append(keys, int(k))
261-
}
262-
sort.Sort(sort.Reverse(sort.IntSlice(keys)))
263-
264-
for _, k := range keys {
285+
for _, k := range obj.PropertiesIds() {
265286
ret += fmt.Sprintf(" [%2d] ", k)
266-
for b := range obj.properties[byte(k)] {
267-
ret += fmt.Sprintf("%02X ", obj.properties[byte(k)][b])
287+
for b := range obj.properties[k] {
288+
ret += fmt.Sprintf("%02X ", obj.properties[k][b])
268289
}
269290
ret += fmt.Sprintln("")
270291
}

gork/zobject_test.go

Lines changed: 173 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package gork
22

3-
import "testing"
3+
import (
4+
"encoding/binary"
5+
"testing"
6+
)
47

58
// attributes, parent, sibling, child
69
// DO NOT STORE propPos it will be calculated!
@@ -13,10 +16,13 @@ var zobjectData [][]byte = [][]byte{
1316
// nameLength, optional name, props
1417
var zobjectProps [][]byte = [][]byte{
1518
[]byte{0x00, 0xB2, 0x46, 0xDC, 0x42, 0xC2, 0x42, 0xB4, 0x10, 0x82, 0x00},
16-
[]byte{0x04, 0x7E, 0x97, 0xC0, 0xA5, 0xB2, 0x46, 0xDC, 0x42, 0xC2, 0x42, 0xB4, 0x10, 0x82, 0x00},
17-
[]byte{0x04, 0x23, 0xC8, 0xC6, 0x95, 0xB2, 0x46, 0xDC, 0x42, 0xC2, 0x42, 0xB4, 0x00},
19+
[]byte{0x02, 0x7E, 0x97, 0xC0, 0xA5, 0xB2, 0x46, 0xDC, 0x42, 0xC2, 0x42, 0xB4, 0x30, 0x82, 0x21, 0x00},
20+
[]byte{0x02, 0x23, 0xC8, 0xC6, 0x95, 0xB2, 0x46, 0xDC, 0x42, 0xC2, 0x42, 0xB4, 0x00},
1821
}
1922

23+
const defaultPropByte byte = 0xFF
24+
const defaultPropWord uint16 = uint16(defaultPropByte)<<8 | uint16(defaultPropByte)
25+
2026
// TODO generate automatically propertiesPos
2127
var zobjectExpected []ZObject = []ZObject{
2228
ZObject{
@@ -42,7 +48,7 @@ var zobjectExpected []ZObject = []ZObject{
4248
propertiesPos: 0x0064,
4349
properties: map[byte][]byte{
4450
18: []byte{0x46, 0xDC, 0x42, 0xC2, 0x42, 0xB4},
45-
16: []byte{0x82},
51+
16: []byte{0x82, 0x21},
4652
},
4753
},
4854
ZObject{
@@ -52,7 +58,7 @@ var zobjectExpected []ZObject = []ZObject{
5258
sibling: 2,
5359
child: 0,
5460
name: "cyclop",
55-
propertiesPos: 0x0073,
61+
propertiesPos: 0x0074,
5662
properties: map[byte][]byte{
5763
18: []byte{0x46, 0xDC, 0x42, 0xC2, 0x42, 0xB4},
5864
},
@@ -75,8 +81,8 @@ func createZObjectBuf() []byte {
7581
ret := make([]byte, 31*2)
7682

7783
for i := range ret {
78-
// default properties are all 0s in this case
79-
ret[i] = 0x00
84+
// default properties are all 0xFFs in this case
85+
ret[i] = defaultPropByte
8086
}
8187

8288
firstPropPos := uint16(len(ret)) + uint16(len(zobjectData))*uint16(zobjectSize)
@@ -97,17 +103,28 @@ func createZObjectBuf() []byte {
97103
return ret
98104
}
99105

100-
func TestZObject(t *testing.T) {
106+
func prelude() (*ZMemory, *ZHeader, uint8) {
101107
mem := ZMemory(createZObjectBuf())
102108
header := &ZHeader{objTblPos: 0x00}
103109

104110
count := ZObjectsCount(&mem, header)
111+
112+
return &mem, header, count
113+
}
114+
115+
func TestZObjectCount(t *testing.T) {
116+
_, _, count := prelude()
117+
105118
if count != uint8(len(zobjectExpected)) {
106119
t.Fail()
107120
}
121+
}
122+
123+
func TestZObject(t *testing.T) {
124+
mem, header, count := prelude()
108125

109126
for i := uint8(0); i < count; i++ {
110-
obj := NewZObject(&mem, i+1, header)
127+
obj := NewZObject(mem, i+1, header)
111128
expected := zobjectExpected[i]
112129

113130
if obj.number != expected.number ||
@@ -117,7 +134,7 @@ func TestZObject(t *testing.T) {
117134
obj.child != expected.child ||
118135
obj.name != expected.name ||
119136
obj.propertiesPos != expected.propertiesPos ||
120-
obj.mem != &mem {
137+
obj.mem != mem {
121138
t.Fail()
122139
}
123140

@@ -145,6 +162,152 @@ func TestZObject(t *testing.T) {
145162
}
146163
}
147164

165+
func TestZObjectGetProperty(t *testing.T) {
166+
mem, header, count := prelude()
167+
168+
for i := byte(0); i < count; i++ {
169+
obj := NewZObject(mem, i+1, header)
170+
good := zobjectExpected[i]
171+
172+
for key, prop := range good.properties {
173+
if len(prop) <= 2 {
174+
rProp := obj.GetProperty(key)
175+
176+
if len(prop) == 1 {
177+
if rProp != uint16(prop[0]) {
178+
t.Fail()
179+
}
180+
} else if rProp != binary.BigEndian.Uint16(prop) {
181+
t.Fail()
182+
}
183+
}
184+
}
185+
186+
// should return default property
187+
if _, ok := obj.properties[31]; !ok && obj.GetProperty(31) != defaultPropWord {
188+
t.Fail()
189+
}
190+
}
191+
}
192+
193+
func TestZObjectSetProperty(t *testing.T) {
194+
mem, header, count := prelude()
195+
196+
for i := byte(0); i < count; i++ {
197+
obj := NewZObject(mem, i+1, header)
198+
199+
var expected uint16
200+
201+
for id, prop := range obj.properties {
202+
ok := true
203+
switch len(prop) {
204+
case 1:
205+
expected = uint16(defaultPropByte)
206+
case 2:
207+
expected = defaultPropWord
208+
default:
209+
ok = false
210+
}
211+
212+
if ok {
213+
obj.SetProperty(id, expected)
214+
if obj.GetProperty(id) != expected {
215+
t.Fail()
216+
}
217+
}
218+
}
219+
}
220+
}
221+
222+
func TestZObjectPropertyLen(t *testing.T) {
223+
mem, header, count := prelude()
224+
225+
for i := byte(0); i < count; i++ {
226+
obj := NewZObject(mem, i+1, header)
227+
228+
seq := mem.GetSequential(uint32(obj.propertiesPos))
229+
if seq.ReadByte() != 0 {
230+
// skip name
231+
seq.DecodeZString(header)
232+
}
233+
// skip dataSize
234+
seq.ReadByte()
235+
236+
propertyPos := uint16(seq.pos)
237+
238+
for _, k := range obj.PropertiesIds() {
239+
prop := obj.properties[k]
240+
241+
if GetPropertyLen(mem, uint32(propertyPos)) != uint16(len(prop)) {
242+
t.Fail()
243+
}
244+
245+
// skip propData and next dataSize
246+
propertyPos += uint16(len(prop)) + 1
247+
}
248+
}
249+
}
250+
251+
func TestZObjectGetFirstPropertyAddr(t *testing.T) {
252+
mem, header, count := prelude()
253+
254+
for i := byte(0); i < count; i++ {
255+
obj := NewZObject(mem, i+1, header)
256+
257+
seq := mem.GetSequential(uint32(obj.propertiesPos))
258+
259+
if seq.ReadByte() != 0 {
260+
// skip name
261+
seq.DecodeZString(header)
262+
}
263+
264+
if obj.GetFirstPropertyAddr() != seq.pos {
265+
t.Fail()
266+
}
267+
}
268+
}
269+
270+
func TestZObjectGetPropertyAddr(t *testing.T) {
271+
mem, header, count := prelude()
272+
273+
for i := byte(0); i < count; i++ {
274+
obj := NewZObject(mem, i+1, header)
275+
276+
seq := mem.GetSequential(uint32(obj.propertiesPos))
277+
278+
if seq.ReadByte() != 0 {
279+
// skip name
280+
seq.DecodeZString(header)
281+
}
282+
propPos := seq.pos
283+
284+
keys := obj.PropertiesIds()
285+
286+
if len(keys) > 0 && obj.GetPropertyAddr(keys[0]) != obj.GetFirstPropertyAddr() {
287+
t.Fail()
288+
}
289+
290+
// v3
291+
keyIdx := 0
292+
for propId := byte(31); propId > 0; propId-- {
293+
expected := uint32(0)
294+
if keyIdx < len(keys) && keys[keyIdx] == propId {
295+
expected = propPos
296+
keyIdx++
297+
298+
// skip size
299+
propPos++
300+
propPos += uint32(len(zobjectExpected[i].properties[propId]))
301+
}
302+
303+
if obj.GetPropertyAddr(byte(propId)) != expected {
304+
t.Fail()
305+
}
306+
307+
}
308+
}
309+
}
310+
148311
func TestZObjectId(t *testing.T) {
149312
header := &ZHeader{objTblPos: 0}
150313
for i := byte(0); i < 255; i++ {

gork/zoptable.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -318,13 +318,7 @@ func ZPutProp(zm *ZMachine, args []uint16) {
318318
}
319319

320320
func ZGetProp(zm *ZMachine, objectId uint16, propertyId uint16) {
321-
res, err := zm.objects[objectId-1].GetProperty(byte(propertyId))
322-
323-
if err != nil {
324-
// get default one
325-
res = zm.GetDefaultProperty(byte(propertyId))
326-
}
327-
321+
res := zm.objects[objectId-1].GetProperty(byte(propertyId))
328322
zm.StoreReturn(res)
329323
}
330324

0 commit comments

Comments
 (0)