github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/model/flow/identifier_test.go (about) 1 package flow_test 2 3 import ( 4 "crypto/rand" 5 "encoding/binary" 6 "encoding/json" 7 "fmt" 8 "testing" 9 10 blocks "github.com/ipfs/go-block-format" 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 14 "github.com/onflow/flow-go/model/flow" 15 "github.com/onflow/flow-go/storage/merkle" 16 "github.com/onflow/flow-go/utils/unittest" 17 ) 18 19 func TestIdentifierFormat(t *testing.T) { 20 id := unittest.IdentifierFixture() 21 22 // should print hex representation with %x formatting verb 23 t.Run("%x", func(t *testing.T) { 24 formatted := fmt.Sprintf("%x", id) 25 assert.Equal(t, id.String(), formatted) 26 }) 27 28 // should print hex representation with %s formatting verb 29 t.Run("%s", func(t *testing.T) { 30 formatted := fmt.Sprintf("%s", id) //nolint:gosimple 31 assert.Equal(t, id.String(), formatted) 32 }) 33 34 // should print hex representation with default formatting verb 35 t.Run("%v", func(t *testing.T) { 36 formatted := fmt.Sprintf("%v", id) 37 assert.Equal(t, id.String(), formatted) 38 }) 39 40 // should handle unsupported verbs 41 t.Run("unsupported formatting verb", func(t *testing.T) { 42 formatted := fmt.Sprintf("%d", id) 43 expected := fmt.Sprintf("%%!d(flow.Identifier=%s)", id) 44 assert.Equal(t, expected, formatted) 45 }) 46 } 47 48 func TestIdentifierJSON(t *testing.T) { 49 id := unittest.IdentifierFixture() 50 bz, err := json.Marshal(id) 51 assert.NoError(t, err) 52 assert.Equal(t, fmt.Sprintf("\"%v\"", id), string(bz)) 53 var actual flow.Identifier 54 err = json.Unmarshal(bz, &actual) 55 assert.NoError(t, err) 56 assert.Equal(t, id, actual) 57 } 58 59 func TestIdentifierSample(t *testing.T) { 60 61 total := 10 62 ids := make([]flow.Identifier, total) 63 for i := range ids { 64 ids[i] = unittest.IdentifierFixture() 65 } 66 67 t.Run("Sample creates a random sample", func(t *testing.T) { 68 sampleSize := uint(5) 69 sample, err := flow.Sample(sampleSize, ids...) 70 require.NoError(t, err) 71 require.Len(t, sample, int(sampleSize)) 72 require.NotEqual(t, sample, ids[:sampleSize]) 73 }) 74 75 t.Run("sample size greater than total size results in the original list", func(t *testing.T) { 76 sampleSize := uint(len(ids) + 1) 77 sample, err := flow.Sample(sampleSize, ids...) 78 require.NoError(t, err) 79 require.Equal(t, sample, ids) 80 }) 81 82 t.Run("sample size of zero results in an empty list", func(t *testing.T) { 83 sampleSize := uint(0) 84 sample, err := flow.Sample(sampleSize, ids...) 85 require.NoError(t, err) 86 require.Empty(t, sample) 87 }) 88 } 89 90 func TestMerkleRoot(t *testing.T) { 91 total := 10 92 ids := make([]flow.Identifier, total) 93 for i := range ids { 94 ids[i] = unittest.IdentifierFixture() 95 } 96 97 idsBad := make([]flow.Identifier, total) 98 for i := range idsBad { 99 idsBad[i] = ids[len(ids)-1] 100 } 101 fmt.Println(ids) 102 fmt.Println(idsBad) 103 104 require.NotEqual(t, flow.MerkleRoot(ids...), flow.MerkleRoot(idsBad...)) 105 require.Equal(t, referenceMerkleRoot(t, ids...), flow.MerkleRoot(ids...)) 106 } 107 108 // We should ideally replace this with a completely different reference implementation 109 // Possibly written in another language, such as python, similar to the Ledger Trie Implementation 110 func referenceMerkleRoot(t *testing.T, ids ...flow.Identifier) flow.Identifier { 111 var root flow.Identifier 112 tree, err := merkle.NewTree(flow.IdentifierLen) 113 assert.NoError(t, err) 114 for idx, id := range ids { 115 idxVal := make([]byte, 8) 116 binary.BigEndian.PutUint64(idxVal, uint64(idx)) 117 _, err := tree.Put(id[:], idxVal) 118 assert.NoError(t, err) 119 } 120 hash := tree.Hash() 121 copy(root[:], hash) 122 return root 123 } 124 125 // TestCIDConversion tests that the CID conversion functions are working as expected 126 // It generates Flow ID / CID fixtures and converts them back and forth to check that 127 // the conversion is correct. 128 func TestCIDConversion(t *testing.T) { 129 id := unittest.IdentifierFixture() 130 cid := flow.IdToCid(id) 131 id2, err := flow.CidToId(cid) 132 assert.NoError(t, err) 133 assert.Equal(t, id, id2) 134 135 // generate random CID 136 data := make([]byte, 4) 137 _, err = rand.Read(data) 138 require.NoError(t, err) 139 cid = blocks.NewBlock(data).Cid() 140 141 id, err = flow.CidToId(cid) 142 cid2 := flow.IdToCid(id) 143 assert.NoError(t, err) 144 assert.Equal(t, cid, cid2) 145 } 146 147 // TestByteConversionRoundTrip evaluates the round trip of conversion of identifiers to bytes, and back. 148 // The original identifiers must be recovered from the converted bytes. 149 func TestByteConversionRoundTrip(t *testing.T) { 150 ids := unittest.IdentifierListFixture(10) 151 152 converted, err := flow.ByteSlicesToIds(flow.IdsToBytes(ids)) 153 require.NoError(t, err) 154 155 require.Equal(t, len(ids), len(converted)) 156 require.ElementsMatch(t, ids, converted) 157 }