cosmos-sdk/schema/testing/object.go
Aaron Craelius ae40e809b9
refactor(schema)!: rename ObjectType -> StateObjectType (#21691)
Co-authored-by: cool-developer <51834436+cool-develope@users.noreply.github.com>
2024-09-16 08:17:52 +00:00

104 lines
3.1 KiB
Go

package schematesting
import (
"github.com/tidwall/btree"
"pgregory.net/rapid"
"cosmossdk.io/schema"
)
// StateObjectTypeGen generates random StateObjectType's based on the validity criteria of object types.
func StateObjectTypeGen(typeSet schema.TypeSet) *rapid.Generator[schema.StateObjectType] {
keyFieldsGen := rapid.SliceOfNDistinct(KeyFieldGen(typeSet), 1, 6, func(f schema.Field) string {
return f.Name
})
valueFieldsGen := rapid.SliceOfNDistinct(FieldGen(typeSet), 1, 12, func(f schema.Field) string {
return f.Name
})
return rapid.Custom(func(t *rapid.T) schema.StateObjectType {
typ := schema.StateObjectType{
Name: NameGen.Filter(func(s string) bool {
// filter out names that already exist in the schema
_, found := typeSet.LookupType(s)
return !found
}).Draw(t, "name"),
}
typ.KeyFields = keyFieldsGen.Draw(t, "keyFields")
typ.ValueFields = valueFieldsGen.Draw(t, "valueFields")
typ.RetainDeletions = boolGen.Draw(t, "retainDeletions")
return typ
}).Filter(func(typ schema.StateObjectType) bool {
// filter out duplicate field names
fieldNames := map[string]bool{}
if hasDuplicateFieldNames(fieldNames, typ.KeyFields) {
return false
}
if hasDuplicateFieldNames(fieldNames, typ.ValueFields) {
return false
}
return true
})
}
func hasDuplicateFieldNames(typeNames map[string]bool, fields []schema.Field) bool {
for _, field := range fields {
if _, ok := typeNames[field.Name]; ok {
return true
}
typeNames[field.Name] = true
}
return false
}
// StateObjectInsertGen generates object updates that are valid for insertion.
func StateObjectInsertGen(objectType schema.StateObjectType, typeSet schema.TypeSet) *rapid.Generator[schema.StateObjectUpdate] {
return StateObjectUpdateGen(objectType, nil, typeSet)
}
// StateObjectUpdateGen generates object updates that are valid for updates using the provided state map as a source
// of valid existing keys.
func StateObjectUpdateGen(objectType schema.StateObjectType, state *btree.Map[string, schema.StateObjectUpdate], sch schema.TypeSet) *rapid.Generator[schema.StateObjectUpdate] {
keyGen := ObjectKeyGen(objectType.KeyFields, sch).Filter(func(key interface{}) bool {
// filter out keys that exist in the state
if state != nil {
_, exists := state.Get(ObjectKeyString(objectType, key))
return !exists
}
return true
})
insertValueGen := ObjectValueGen(objectType.ValueFields, false, sch)
updateValueGen := ObjectValueGen(objectType.ValueFields, true, sch)
return rapid.Custom(func(t *rapid.T) schema.StateObjectUpdate {
update := schema.StateObjectUpdate{
TypeName: objectType.Name,
}
// 50% of the time use existing key (when there are keys)
n := 0
if state != nil {
n = state.Len()
}
if n > 0 && boolGen.Draw(t, "existingKey") {
i := rapid.IntRange(0, n-1).Draw(t, "index")
update.Key = state.Values()[i].Key
// delete 50% of the time
if boolGen.Draw(t, "delete") {
update.Delete = true
} else {
update.Value = updateValueGen.Draw(t, "value")
}
} else {
update.Key = keyGen.Draw(t, "key")
update.Value = insertValueGen.Draw(t, "value")
}
return update
})
}