// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later package lowmemjson_test import ( "bytes" "fmt" "io" "testing" "github.com/stretchr/testify/assert" "git.lukeshu.com/go/lowmemjson" ) type ShortSum string func (s ShortSum) EncodeJSON(w io.Writer) error { // Test that it's OK to call lowmemjson.Encoder.Encode for the top-level value in a method. return lowmemjson.NewEncoder(w).Encode(string(s)) } type SumRun struct { ChecksumSize int `json:",omitempty"` Addr int64 `json:",omitempty"` Sums ShortSum } type SumRunWithGaps struct { Addr int64 Size int64 Runs []SumRun } func (sg SumRunWithGaps) EncodeJSON(w io.Writer) error { if _, err := fmt.Fprintf(w, `{"Addr":%d,"Size":%d,"Runs":[`, sg.Addr, sg.Size); err != nil { return err } cur := sg.Addr for i, run := range sg.Runs { if i > 0 { if _, err := w.Write([]byte{','}); err != nil { return err } } if run.Addr > cur { if _, err := fmt.Fprintf(w, `{"Gap":%d},`, run.Addr-cur); err != nil { return err } } if err := lowmemjson.NewEncoder(w).Encode(run); err != nil { return err } } end := sg.Addr + sg.Size switch { case end < cur: return fmt.Errorf("invalid %T: addr went backwards: %v < %v", sg, end, cur) case end > cur: if _, err := fmt.Fprintf(w, `,{"Gap":%d}`, end-cur); err != nil { return err } } if _, err := w.Write([]byte("]}")); err != nil { return err } return nil } func (sg *SumRunWithGaps) DecodeJSON(r io.RuneScanner) error { *sg = SumRunWithGaps{} var name string return lowmemjson.DecodeObject(r, func(r io.RuneScanner) error { return lowmemjson.NewDecoder(r).Decode(&name) }, func(r io.RuneScanner) error { switch name { case "Addr": return lowmemjson.NewDecoder(r).Decode(&sg.Addr) case "Size": return lowmemjson.NewDecoder(r).Decode(&sg.Size) case "Runs": return lowmemjson.DecodeArray(r, func(r io.RuneScanner) error { var run SumRun if err := lowmemjson.NewDecoder(r).Decode(&run); err != nil { return err } if run.ChecksumSize > 0 { sg.Runs = append(sg.Runs, run) } return nil }) default: return fmt.Errorf("unknown key %q", name) } }) } func TestMethods(t *testing.T) { in := SumRunWithGaps{ Addr: 13631488, Size: 416033783808, Runs: []SumRun{ { ChecksumSize: 4, Addr: 1095761920, Sums: "c160817cb5c72bbbe", }, }, } var buf bytes.Buffer assert.NoError(t, lowmemjson.NewEncoder(&buf).Encode(in)) assert.Equal(t, `{"Addr":13631488,"Size":416033783808,"Runs":[{"Gap":1082130432},{"ChecksumSize":4,"Addr":1095761920,"Sums":"c160817cb5c72bbbe"},{"Gap":416033783808}]}`, buf.String()) var out SumRunWithGaps assert.NoError(t, lowmemjson.NewDecoder(&buf).Decode(&out)) assert.Equal(t, in, out) }