github.com/cosmos/cosmos-sdk@v0.50.10/x/group/internal/orm/primary_key_test.go (about) 1 package orm 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/assert" 7 "github.com/stretchr/testify/require" 8 9 errorsmod "cosmossdk.io/errors" 10 storetypes "cosmossdk.io/store/types" 11 12 "github.com/cosmos/cosmos-sdk/codec" 13 "github.com/cosmos/cosmos-sdk/codec/types" 14 "github.com/cosmos/cosmos-sdk/testutil/testdata" 15 "github.com/cosmos/cosmos-sdk/x/group/errors" 16 ) 17 18 func TestPrimaryKeyTablePrefixScan(t *testing.T) { 19 interfaceRegistry := types.NewInterfaceRegistry() 20 cdc := codec.NewProtoCodec(interfaceRegistry) 21 22 tb, err := NewPrimaryKeyTable(PrimaryKeyTablePrefix, &testdata.TableModel{}, cdc) 23 require.NoError(t, err) 24 25 ctx := NewMockContext() 26 store := ctx.KVStore(storetypes.NewKVStoreKey("test")) 27 28 metadata := []byte("metadata") 29 t1 := testdata.TableModel{ 30 Id: 1, 31 Name: "my test 1", 32 Metadata: metadata, 33 } 34 t2 := testdata.TableModel{ 35 Id: 2, 36 Name: "my test 2", 37 Metadata: metadata, 38 } 39 t3 := testdata.TableModel{ 40 Id: 3, 41 Name: "my test 3", 42 Metadata: metadata, 43 } 44 for _, g := range []testdata.TableModel{t1, t2, t3} { 45 g := g 46 require.NoError(t, tb.Create(store, &g)) 47 } 48 49 specs := map[string]struct { 50 start, end []byte 51 expResult []testdata.TableModel 52 expRowIDs []RowID 53 expError *errorsmod.Error 54 method func(store storetypes.KVStore, start, end []byte) (Iterator, error) 55 }{ 56 "exact match with a single result": { 57 start: EncodeSequence(1), // == PrimaryKey(&t1) 58 end: EncodeSequence(2), // == PrimaryKey(&t2) 59 method: tb.PrefixScan, 60 expResult: []testdata.TableModel{t1}, 61 expRowIDs: []RowID{PrimaryKey(&t1)}, 62 }, 63 "one result by 1st byte": { 64 start: []byte{0}, 65 end: EncodeSequence(2), // == PrimaryKey(&t2) 66 method: tb.PrefixScan, 67 expResult: []testdata.TableModel{t1}, 68 expRowIDs: []RowID{PrimaryKey(&t1)}, 69 }, 70 "open end query": { 71 start: EncodeSequence(3), 72 end: nil, 73 method: tb.PrefixScan, 74 expResult: []testdata.TableModel{t3}, 75 expRowIDs: []RowID{PrimaryKey(&t3)}, 76 }, 77 "open end query with all": { 78 start: EncodeSequence(1), 79 end: nil, 80 method: tb.PrefixScan, 81 expResult: []testdata.TableModel{t1, t2, t3}, 82 expRowIDs: []RowID{PrimaryKey(&t1), PrimaryKey(&t2), PrimaryKey(&t3)}, 83 }, 84 "open start query": { 85 start: nil, 86 end: EncodeSequence(3), 87 method: tb.PrefixScan, 88 expResult: []testdata.TableModel{t1, t2}, 89 expRowIDs: []RowID{PrimaryKey(&t1), PrimaryKey(&t2)}, 90 }, 91 "open start and end query": { 92 start: nil, 93 end: nil, 94 method: tb.PrefixScan, 95 expResult: []testdata.TableModel{t1, t2, t3}, 96 expRowIDs: []RowID{PrimaryKey(&t1), PrimaryKey(&t2), PrimaryKey(&t3)}, 97 }, 98 "all matching 1st byte": { 99 start: []byte{0}, 100 end: nil, 101 method: tb.PrefixScan, 102 expResult: []testdata.TableModel{t1, t2, t3}, 103 expRowIDs: []RowID{PrimaryKey(&t1), PrimaryKey(&t2), PrimaryKey(&t3)}, 104 }, 105 "non matching 1st byte": { 106 start: []byte{1}, 107 end: nil, 108 method: tb.PrefixScan, 109 expResult: []testdata.TableModel{}, 110 }, 111 "start equals end": { 112 start: EncodeSequence(1), 113 end: EncodeSequence(1), 114 method: tb.PrefixScan, 115 expError: errors.ErrORMInvalidArgument, 116 }, 117 "start after end": { 118 start: EncodeSequence(2), 119 end: EncodeSequence(1), 120 method: tb.PrefixScan, 121 expError: errors.ErrORMInvalidArgument, 122 }, 123 "reverse: exact match with a single result": { 124 start: EncodeSequence(1), // == PrimaryKey(&t1) 125 end: EncodeSequence(2), // == PrimaryKey(&t2) 126 method: tb.ReversePrefixScan, 127 expResult: []testdata.TableModel{t1}, 128 expRowIDs: []RowID{PrimaryKey(&t1)}, 129 }, 130 "reverse: one result by 1st byte": { 131 start: []byte{0}, 132 end: EncodeSequence(2), // == PrimaryKey(&t2) 133 method: tb.ReversePrefixScan, 134 expResult: []testdata.TableModel{t1}, 135 expRowIDs: []RowID{PrimaryKey(&t1)}, 136 }, 137 "reverse: open end query": { 138 start: EncodeSequence(3), 139 end: nil, 140 method: tb.ReversePrefixScan, 141 expResult: []testdata.TableModel{t3}, 142 expRowIDs: []RowID{PrimaryKey(&t3)}, 143 }, 144 "reverse: open end query with all": { 145 start: EncodeSequence(1), 146 end: nil, 147 method: tb.ReversePrefixScan, 148 expResult: []testdata.TableModel{t3, t2, t1}, 149 expRowIDs: []RowID{PrimaryKey(&t3), PrimaryKey(&t2), PrimaryKey(&t1)}, 150 }, 151 "reverse: open start query": { 152 start: nil, 153 end: EncodeSequence(3), 154 method: tb.ReversePrefixScan, 155 expResult: []testdata.TableModel{t2, t1}, 156 expRowIDs: []RowID{PrimaryKey(&t2), PrimaryKey(&t1)}, 157 }, 158 "reverse: open start and end query": { 159 start: nil, 160 end: nil, 161 method: tb.ReversePrefixScan, 162 expResult: []testdata.TableModel{t3, t2, t1}, 163 expRowIDs: []RowID{PrimaryKey(&t3), PrimaryKey(&t2), PrimaryKey(&t1)}, 164 }, 165 "reverse: all matching 1st byte": { 166 start: []byte{0}, 167 end: nil, 168 method: tb.ReversePrefixScan, 169 expResult: []testdata.TableModel{t3, t2, t1}, 170 expRowIDs: []RowID{PrimaryKey(&t3), PrimaryKey(&t2), PrimaryKey(&t1)}, 171 }, 172 "reverse: non matching prefix": { 173 start: []byte{1}, 174 end: nil, 175 method: tb.ReversePrefixScan, 176 expResult: []testdata.TableModel{}, 177 }, 178 "reverse: start equals end": { 179 start: EncodeSequence(1), 180 end: EncodeSequence(1), 181 method: tb.ReversePrefixScan, 182 expError: errors.ErrORMInvalidArgument, 183 }, 184 "reverse: start after end": { 185 start: EncodeSequence(2), 186 end: EncodeSequence(1), 187 method: tb.ReversePrefixScan, 188 expError: errors.ErrORMInvalidArgument, 189 }, 190 } 191 for msg, spec := range specs { 192 t.Run(msg, func(t *testing.T) { 193 it, err := spec.method(store, spec.start, spec.end) 194 require.True(t, spec.expError.Is(err), "expected #+v but got #+v", spec.expError, err) 195 if spec.expError != nil { 196 return 197 } 198 var loaded []testdata.TableModel 199 rowIDs, err := ReadAll(it, &loaded) 200 require.NoError(t, err) 201 assert.Equal(t, spec.expResult, loaded) 202 assert.Equal(t, spec.expRowIDs, rowIDs) 203 }) 204 } 205 } 206 207 func TestContains(t *testing.T) { 208 interfaceRegistry := types.NewInterfaceRegistry() 209 cdc := codec.NewProtoCodec(interfaceRegistry) 210 211 ctx := NewMockContext() 212 store := ctx.KVStore(storetypes.NewKVStoreKey("test")) 213 214 tb, err := NewPrimaryKeyTable(PrimaryKeyTablePrefix, &testdata.TableModel{}, cdc) 215 require.NoError(t, err) 216 217 obj := testdata.TableModel{ 218 Id: 1, 219 Name: "Some name", 220 } 221 err = tb.Create(store, &obj) 222 require.NoError(t, err) 223 224 specs := map[string]struct { 225 src PrimaryKeyed 226 exp bool 227 }{ 228 "same object": {src: &obj, exp: true}, 229 "clone": { 230 src: &testdata.TableModel{ 231 Id: 1, 232 Name: "Some name", 233 }, 234 exp: true, 235 }, 236 "different primary key": { 237 src: &testdata.TableModel{ 238 Id: 2, 239 Name: "Some name", 240 }, 241 exp: false, 242 }, 243 "different type, same key": { 244 src: mockPrimaryKeyed{&obj}, 245 exp: false, 246 }, 247 } 248 for msg, spec := range specs { 249 t.Run(msg, func(t *testing.T) { 250 got := tb.Contains(store, spec.src) 251 assert.Equal(t, spec.exp, got) 252 }) 253 } 254 } 255 256 type mockPrimaryKeyed struct { 257 *testdata.TableModel 258 }