github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/output/stream_test.go (about) 1 package output 2 3 import ( 4 "bytes" 5 "encoding/csv" 6 "encoding/json" 7 "fmt" 8 "testing" 9 "text/template" 10 11 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base" 12 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger" 13 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types" 14 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/utils" 15 ) 16 17 var input = types.Receipt{ 18 BlockHash: base.HexToHash("0x123"), 19 BlockNumber: 123, 20 ContractAddress: base.HexToAddress("0xdafea492d9c6733ae3d56b7ed1adb60692c98bc5"), 21 CumulativeGasUsed: 500, 22 From: base.HexToAddress("0xfd4536dd5a81ecfd1a4b30111a01d129e7567ff8"), 23 GasUsed: 500, 24 EffectiveGasPrice: 500, 25 Logs: []types.Log{ 26 { 27 Address: base.HexToAddress("0x02ef66278c3c88ff929a5c84c46fbfb83614382e"), 28 LogIndex: 0, 29 BlockNumber: 124, 30 TransactionIndex: 1, 31 }, 32 }, 33 Status: 1, 34 IsError: false, 35 To: base.HexToAddress("0x917e5e52ac55098d8caa1709e33178aadd9d4901"), 36 TransactionHash: base.HexToHash("0x124"), 37 TransactionIndex: 1, 38 } 39 40 func helperStreamFormats(w csv.Writer, outputBuffer *bytes.Buffer, chain, format string, expectKeys bool) error { 41 buffer := new(bytes.Buffer) 42 StreamModel(buffer, input.Model(chain, format, false, nil), OutputOptions{ 43 Format: format, 44 NoHeader: !expectKeys, 45 }) 46 result := buffer.String() 47 48 var expectedItems []string 49 data := input.Model(chain, format, false, nil).Data 50 for _, key := range input.Model(chain, format, false, nil).Order { 51 expectedItems = append(expectedItems, fmt.Sprint(data[key])) 52 } 53 if expectKeys { 54 w.Write(input.Model(chain, format, false, nil).Order) 55 } 56 w.Write(expectedItems) 57 w.Flush() 58 expected := outputBuffer.String() 59 60 if result != expected { 61 return fmt.Errorf("mismatch for format '%s': <%s>", format, result) 62 } 63 return nil 64 } 65 66 func TestStreamFormats(t *testing.T) { 67 chain := utils.GetTestChain() 68 outputBuffer := &bytes.Buffer{} 69 csvWriter := csv.NewWriter(outputBuffer) 70 71 err := helperStreamFormats(*csvWriter, outputBuffer, chain, "csv", false) 72 if err != nil { 73 t.Fatal(err) 74 } 75 76 csvWriter.Comma = '\t' 77 outputBuffer.Reset() 78 err = helperStreamFormats(*csvWriter, outputBuffer, chain, "txt", false) 79 if err != nil { 80 t.Fatal(err) 81 } 82 83 csvWriter.Comma = ':' 84 outputBuffer.Reset() 85 err = helperStreamFormats(*csvWriter, outputBuffer, chain, ":", false) 86 if err != nil { 87 t.Fatal(err) 88 } 89 } 90 91 func TestStreamJson(t *testing.T) { 92 chain := utils.GetTestChain() 93 outputBuffer := &bytes.Buffer{} 94 w := NewJsonWriter(outputBuffer) 95 w.DefaultField = DefaultField{Key: "Data", FieldType: FieldArray} 96 StreamModel(w, input.Model(chain, "json", false, nil), OutputOptions{ 97 Format: "json", 98 JsonIndent: " ", 99 }) 100 w.Close() 101 result := outputBuffer.String() 102 expected, err := json.MarshalIndent(struct { 103 Data []interface{} 104 }{ 105 Data: []interface{}{input.Model(chain, "json", false, nil).Data}, 106 }, "", " ") 107 108 if err != nil { 109 t.Fatal(err) 110 } 111 if result != string(expected) { 112 t.Fatal("mismatch in JSON format") 113 } 114 } 115 116 func TestStreamPrintKeys(t *testing.T) { 117 chain := utils.GetTestChain() 118 outputBuffer := &bytes.Buffer{} 119 csvWriter := csv.NewWriter(outputBuffer) 120 121 err := helperStreamFormats(*csvWriter, outputBuffer, chain, "csv", true) 122 if err != nil { 123 t.Fatal(err) 124 } 125 } 126 127 func TestStreamTemplate(t *testing.T) { 128 chain := utils.GetTestChain() 129 tmpl := template.Must(template.New("").Parse("{{.blockNumber}} used {{.gasUsed}}{{if .Nonexistent}}111{{else}}.{{end}}")) 130 outputBuffer := &bytes.Buffer{} 131 132 err := StreamWithTemplate(outputBuffer, input.Model(chain, "", false, nil), tmpl) 133 if err != nil { 134 t.Fatal(err) 135 } 136 if outputBuffer.String() != "123 used 500." { 137 t.Fatal("mismatched template text:", outputBuffer.String()) 138 } 139 } 140 141 func TestStreamMany(t *testing.T) { 142 buffer := &bytes.Buffer{} 143 jw := NewJsonWriter(buffer) 144 jw.DefaultField = DefaultField{ 145 Key: "data", 146 FieldType: FieldArray, 147 } 148 149 renderData := func(modelChan chan types.Modeler, errorChan chan error) { 150 modelChan <- &types.Receipt{ 151 BlockNumber: 123, 152 TransactionIndex: 1, 153 TransactionHash: base.HexToHash("0xdeadbeef"), 154 GasUsed: 100, 155 Status: 1, 156 IsError: false, 157 } 158 159 modelChan <- &types.Receipt{ 160 BlockNumber: 124, 161 TransactionIndex: 5, 162 TransactionHash: base.HexToHash("0xdeadbeef2"), 163 GasUsed: 200, 164 Status: 1, 165 IsError: false, 166 } 167 } 168 169 // Print the values and try to re-parse them to check if 170 // we get the same data 171 rCtx := NewRenderContext() 172 StreamMany(rCtx, renderData, OutputOptions{ 173 Writer: jw, 174 Format: "json", 175 }) 176 jw.Close() 177 178 type R = struct { 179 Data []types.Receipt `json:"data"` 180 } 181 var result R 182 err := json.Unmarshal(buffer.Bytes(), &result) 183 if err != nil { 184 logger.Error(buffer.String()) 185 t.Fatal(err) 186 } 187 188 if result.Data[0].BlockNumber != 123 { 189 t.Fatal("mismatched data") 190 } 191 if result.Data[1].BlockNumber != 124 { 192 t.Fatal("mismatched data") 193 } 194 } 195 196 func TestApiFormat(t *testing.T) { 197 outputBuffer := &bytes.Buffer{} 198 fetchData := func(modelChan chan types.Modeler, errorChan chan error) { 199 modelChan <- &types.Receipt{ 200 BlockNumber: 123, 201 TransactionIndex: 1, 202 TransactionHash: base.HexToHash("0xdeadbeef"), 203 GasUsed: 100, 204 Status: 1, 205 IsError: false, 206 } 207 } 208 rCtx := NewRenderContext() 209 err := StreamMany(rCtx, fetchData, OutputOptions{ 210 Writer: outputBuffer, 211 Format: "api", 212 }) 213 if err == nil { 214 t.Fatal("Api format is no longer allow. Should error here.") 215 } 216 }