github.com/cosmos/cosmos-sdk@v0.50.10/x/group/internal/orm/primary_key_property_test.go (about) 1 package orm 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/require" 7 "pgregory.net/rapid" 8 9 storetypes "cosmossdk.io/store/types" 10 11 "github.com/cosmos/cosmos-sdk/codec" 12 "github.com/cosmos/cosmos-sdk/codec/types" 13 "github.com/cosmos/cosmos-sdk/testutil/testdata" 14 ) 15 16 func TestPrimaryKeyTable(t *testing.T) { 17 rapid.Check(t, testPrimaryKeyMachine) 18 } 19 20 func testPrimaryKeyMachine(t *rapid.T) { 21 // Init creates a new instance of the state machine model by building the real 22 // table and making the empty model map 23 // Create context 24 ctx := NewMockContext() 25 store := ctx.KVStore(storetypes.NewKVStoreKey("test")) 26 27 // Create primary key table 28 interfaceRegistry := types.NewInterfaceRegistry() 29 cdc := codec.NewProtoCodec(interfaceRegistry) 30 table, err := NewPrimaryKeyTable( 31 [2]byte{0x1}, 32 &testdata.TableModel{}, 33 cdc, 34 ) 35 require.NoError(t, err) 36 37 // Create model state 38 state := make(map[string]*testdata.TableModel) 39 40 t.Repeat(map[string]func(*rapid.T){ 41 // Create is one of the model commands. It adds an object to the table, creating 42 // an error if it already exists. 43 "Create": func(t *rapid.T) { 44 g := genTableModel.Draw(t, "g") 45 pk := string(PrimaryKey(g)) 46 47 t.Logf("pk: %v", pk) 48 t.Logf("state: %v", state) 49 50 err := table.Create(store, g) 51 52 if state[pk] != nil { 53 require.Error(t, err) 54 } else { 55 require.NoError(t, err) 56 state[pk] = g 57 } 58 }, 59 60 // Update is one of the model commands. It updates the value at a given primary 61 // key and fails if that primary key doesn't already exist in the table. 62 "Update": func(t *rapid.T) { 63 tm := generateTableModel(state).Draw(t, "tm") 64 65 newName := rapid.StringN(1, 100, 150).Draw(t, "newName") 66 tm.Name = newName 67 68 // Perform the real Update 69 err := table.Update(store, tm) 70 71 if state[string(PrimaryKey(tm))] == nil { 72 // If there's no value in the model, we expect an error 73 require.Error(t, err) 74 } else { 75 // If we have a value in the model, expect no error 76 require.NoError(t, err) 77 78 // Update the model with the new value 79 state[string(PrimaryKey(tm))] = tm 80 } 81 }, 82 83 // Set is one of the model commands. It sets the value at a key in the table 84 // whether it exists or not. 85 "Set": func(t *rapid.T) { 86 g := genTableModel.Draw(t, "g") 87 pk := string(PrimaryKey(g)) 88 89 err := table.Set(store, g) 90 91 require.NoError(t, err) 92 state[pk] = g 93 }, 94 95 // Delete is one of the model commands. It removes the object with the given 96 // primary key from the table and returns an error if that primary key doesn't 97 // already exist in the table. 98 "Delete": func(t *rapid.T) { 99 tm := generateTableModel(state).Draw(t, "tm") 100 101 // Perform the real Delete 102 err := table.Delete(store, tm) 103 104 if state[string(PrimaryKey(tm))] == nil { 105 // If there's no value in the model, we expect an error 106 require.Error(t, err) 107 } else { 108 // If we have a value in the model, expect no error 109 require.NoError(t, err) 110 111 // Delete the value from the model 112 delete(state, string(PrimaryKey(tm))) 113 } 114 }, 115 116 // Has is one of the model commands. It checks whether a key already exists in 117 // the table. 118 "Has": func(t *rapid.T) { 119 pk := PrimaryKey(generateTableModel(state).Draw(t, "g")) 120 121 realHas := table.Has(store, pk) 122 modelHas := state[string(pk)] != nil 123 124 require.Equal(t, realHas, modelHas) 125 }, 126 127 // GetOne is one of the model commands. It fetches an object from the table by 128 // its primary key and returns an error if that primary key isn't in the table. 129 "GetOne": func(t *rapid.T) { 130 pk := PrimaryKey(generateTableModel(state).Draw(t, "tm")) 131 132 var tm testdata.TableModel 133 134 err := table.GetOne(store, pk, &tm) 135 t.Logf("tm: %v", tm) 136 137 if state[string(pk)] == nil { 138 require.Error(t, err) 139 } else { 140 require.NoError(t, err) 141 require.Equal(t, *state[string(pk)], tm) 142 } 143 }, 144 145 // Check that the real values match the state values. 146 "": func(t *rapid.T) { 147 for i := range state { 148 has := table.Has(store, []byte(i)) 149 require.Equal(t, true, has) 150 } 151 }, 152 }) 153 } 154 155 // stateKeys gets all the keys in the model map 156 func stateKeys(state map[string]*testdata.TableModel) []string { 157 keys := make([]string, len(state)) 158 159 i := 0 160 for k := range state { 161 keys[i] = k 162 i++ 163 } 164 165 return keys 166 } 167 168 // generateTableModel a TableModel that has a 50% chance of being a part of the existing 169 // state 170 func generateTableModel(state map[string]*testdata.TableModel) *rapid.Generator[*testdata.TableModel] { 171 genStateTableModel := rapid.Custom(func(t *rapid.T) *testdata.TableModel { 172 pk := rapid.SampledFrom(stateKeys(state)).Draw(t, "key") 173 return state[pk] 174 }) 175 176 if len(stateKeys(state)) == 0 { 177 return genTableModel 178 } 179 return rapid.OneOf(genTableModel, genStateTableModel) 180 }