Skip to content

Commit

Permalink
Add composite types to smoke test
Browse files Browse the repository at this point in the history
  • Loading branch information
fxamacker committed Oct 10, 2023
1 parent 9b14a71 commit 108dc31
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 4 deletions.
121 changes: 119 additions & 2 deletions cmd/stress/typeinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ const (
maxArrayTypeValue = 10
maxMapTypeValue = 10

arrayTypeTagNum = 246
mapTypeTagNum = 245
arrayTypeTagNum = 246
mapTypeTagNum = 245
compositeTypeTagNum = 244
)

type arrayTypeInfo struct {
Expand Down Expand Up @@ -104,6 +105,83 @@ func (i mapTypeInfo) Equal(other atree.TypeInfo) bool {
return ok && i.value == otherMapTypeInfo.value
}

var compositeFieldNames = []string{"a", "b", "c"}

type compositeTypeInfo struct {
fieldStartIndex int // inclusive start index of fieldNames
fieldEndIndex int // exclusive end index of fieldNames
}

var _ atree.TypeInfo = mapTypeInfo{}

// newCompositeTypeInfo creates one of 10 compositeTypeInfo randomly.
// 10 possible composites:
// - ID: composite(0_0), field names: []
// - ID: composite(0_1), field names: ["a"]
// - ID: composite(0_2), field names: ["a", "b"]
// - ID: composite(0_3), field names: ["a", "b", "c"]
// - ID: composite(1_1), field names: []
// - ID: composite(1_2), field names: ["b"]
// - ID: composite(1_3), field names: ["b", "c"]
// - ID: composite(2_2), field names: []
// - ID: composite(2_3), field names: ["c"]
// - ID: composite(3_3), field names: []
func newCompositeTypeInfo() compositeTypeInfo {
// startIndex is [0, 3]
startIndex := r.Intn(len(compositeFieldNames) + 1)

// count is [0, 3]
count := r.Intn(len(compositeFieldNames) - startIndex + 1)

endIndex := startIndex + count
if endIndex > len(compositeFieldNames) {
panic("not reachable")
}

return compositeTypeInfo{fieldStartIndex: startIndex, fieldEndIndex: endIndex}
}

func (i compositeTypeInfo) getFieldNames() []string {
return compositeFieldNames[i.fieldStartIndex:i.fieldEndIndex]
}

func (i compositeTypeInfo) Copy() atree.TypeInfo {
return i
}

func (i compositeTypeInfo) IsComposite() bool {
return true
}

func (i compositeTypeInfo) ID() string {
return fmt.Sprintf("composite(%d_%d)", i.fieldStartIndex, i.fieldEndIndex)
}

func (i compositeTypeInfo) Encode(e *cbor.StreamEncoder) error {
err := e.EncodeTagHead(compositeTypeTagNum)
if err != nil {
return err
}
err = e.EncodeArrayHead(2)
if err != nil {
return err
}
err = e.EncodeInt64(int64(i.fieldStartIndex))
if err != nil {
return err
}
return e.EncodeInt64(int64(i.fieldEndIndex))
}

func (i compositeTypeInfo) Equal(other atree.TypeInfo) bool {
otherCompositeTypeInfo, ok := other.(compositeTypeInfo)
if !ok {
return false
}
return i.fieldStartIndex == otherCompositeTypeInfo.fieldStartIndex &&
i.fieldEndIndex == otherCompositeTypeInfo.fieldEndIndex
}

func decodeTypeInfo(dec *cbor.StreamDecoder) (atree.TypeInfo, error) {
num, err := dec.DecodeTagNumber()
if err != nil {
Expand All @@ -126,6 +204,45 @@ func decodeTypeInfo(dec *cbor.StreamDecoder) (atree.TypeInfo, error) {

return mapTypeInfo{value: int(value)}, nil

case compositeTypeTagNum:
count, err := dec.DecodeArrayHead()
if err != nil {
return nil, err
}
if count != 2 {
return nil, fmt.Errorf(
"failed to decode composite type info: expect 2 elemets, got %d elements",
count,
)
}

startIndex, err := dec.DecodeInt64()
if err != nil {
return nil, err
}

endIndex, err := dec.DecodeInt64()
if err != nil {
return nil, err
}

if endIndex < startIndex {
return nil, fmt.Errorf(
"failed to decode composite type info: endIndex %d < startIndex %d",
endIndex,
startIndex,
)
}

if endIndex > int64(len(compositeFieldNames)) {
return nil, fmt.Errorf(
"failed to decode composite type info: endIndex %d > len(compositeFieldNames) %d",
endIndex,
len(compositeFieldNames))
}

return compositeTypeInfo{fieldStartIndex: int(startIndex), fieldEndIndex: int(endIndex)}, nil

default:
return nil, fmt.Errorf("failed to decode type info with tag number %d", num)
}
Expand Down
48 changes: 48 additions & 0 deletions cmd/stress/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const (
const (
arrayType int = iota
mapType
compositeType
maxContainerValueType
)

Expand Down Expand Up @@ -123,6 +124,9 @@ func generateContainerValue(
length := r.Intn(maxNestedMapSize)
return newMap(storage, address, length, nestedLevels)

case compositeType:
return newComposite(storage, address, nestedLevels)

default:
return nil, nil, fmt.Errorf("unexpected randome container value type %d", valueType)
}
Expand Down Expand Up @@ -385,6 +389,50 @@ func newMap(
return expectedValues, m, nil
}

// newComposite creates atree.OrderedMap with elements of random composite type and nested level
func newComposite(
storage atree.SlabStorage,
address atree.Address,
nestedLevel int,
) (mapValue, *atree.OrderedMap, error) {

compositeType := newCompositeTypeInfo()

m, err := atree.NewMap(storage, address, atree.NewDefaultDigesterBuilder(), compositeType)
if err != nil {
return nil, nil, fmt.Errorf("failed to create new map: %w", err)
}

expectedValues := make(mapValue)

for _, name := range compositeType.getFieldNames() {

expectedKey, key := NewStringValue(name), NewStringValue(name)

expectedValue, value, err := randomValue(storage, address, nestedLevel-1)
if err != nil {
return nil, nil, err
}

expectedValues[expectedKey] = expectedValue

existingStorable, err := m.Set(compare, hashInputProvider, key, value)
if err != nil {
return nil, nil, err
}
if existingStorable != nil {
return nil, nil, fmt.Errorf("failed to create new map of composite type: found duplicate field name %s", name)
}
}

err = checkMapDataLoss(expectedValues, m)
if err != nil {
return nil, nil, err
}

return expectedValues, m, nil
}

type InMemBaseStorage struct {
segments map[atree.SlabID][]byte
storageIndex map[atree.Address]atree.SlabIndex
Expand Down
14 changes: 12 additions & 2 deletions map_debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -1351,8 +1351,18 @@ func mapExtraDataEqual(expected, actual *MapExtraData) error {
return NewFatalError(fmt.Errorf("has extra data is %t, want %t", actual == nil, expected == nil))
}

if !reflect.DeepEqual(*expected, *actual) {
return NewFatalError(fmt.Errorf("extra data %+v is wrong, want %+v", *actual, *expected))
if !reflect.DeepEqual(expected.TypeInfo, actual.TypeInfo) {
return NewFatalError(fmt.Errorf("map extra data type %+v is wrong, want %+v", actual.TypeInfo, expected.TypeInfo))
}

if expected.Count != actual.Count {
return NewFatalError(fmt.Errorf("map extra data count %d is wrong, want %d", actual.Count, expected.Count))
}

if !expected.TypeInfo.IsComposite() {
if expected.Seed != actual.Seed {
return NewFatalError(fmt.Errorf("map extra data seed %d is wrong, want %d", actual.Seed, expected.Seed))
}
}

return nil
Expand Down

0 comments on commit 108dc31

Please sign in to comment.