github.com/philpearl/plenc@v0.0.15/plenccodec/struct_test.go (about) 1 package plenccodec_test 2 3 import ( 4 "fmt" 5 "reflect" 6 "testing" 7 8 "github.com/google/go-cmp/cmp" 9 "github.com/philpearl/plenc" 10 "github.com/philpearl/plenc/plenccodec" 11 ) 12 13 func TestFieldRemoval(t *testing.T) { 14 type S1 struct { 15 A int `plenc:"1"` 16 B int `plenc:"2"` 17 C string `plenc:"3"` 18 D float32 `plenc:"4"` 19 E float64 `plenc:"5"` 20 } 21 type S2 struct { 22 B int `plenc:"2"` 23 } 24 25 in := S1{A: 1, B: 2, C: "3", D: 4, E: 5} 26 data, err := plenc.Marshal(nil, &in) 27 if err != nil { 28 t.Fatal(err) 29 } 30 31 var out S2 32 if err := plenc.Unmarshal(data, &out); err != nil { 33 t.Fatal(err) 34 } 35 36 if out.B != 2 { 37 t.Fatalf("Unmarshal unexpected value for B. %d", out.B) 38 } 39 } 40 41 func TestRecursiveStruct(t *testing.T) { 42 type s0 struct { 43 A []s0 `plenc:"1"` 44 B int `plenc:"2"` 45 } 46 47 a := s0{ 48 A: []s0{{A: []s0{{B: 1}}}, {A: []s0{{B: 1}}, B: 3}}, 49 } 50 51 data, err := plenc.Marshal(nil, &a) 52 if err != nil { 53 t.Fatal(err) 54 } 55 56 var out s0 57 if err := plenc.Unmarshal(data, &out); err != nil { 58 t.Fatal(err) 59 } 60 61 if diff := cmp.Diff(a, out); diff != "" { 62 t.Fatalf("Not as expected. %s\n%x", diff, data) 63 } 64 } 65 66 func TestSliceStructPtr(t *testing.T) { 67 type S2 struct { 68 A int `plenc:"1"` 69 } 70 type S1 struct { 71 A []*S2 `plenc:"1"` 72 } 73 74 tests := []S1{ 75 {}, 76 {A: []*S2{ 77 {A: 1}, 78 {A: 2}, 79 }}, 80 {A: []*S2{ 81 {A: 1}, 82 {}, 83 {A: 2}, 84 }}, 85 } 86 87 /* 88 00001011 89 0b 03 90 02 0802 91 00 92 02 0804 93 */ 94 for _, test := range tests { 95 t.Run(fmt.Sprintf("%#v", test), func(t *testing.T) { 96 data, err := plenc.Marshal(nil, &test) 97 if err != nil { 98 t.Fatal(err) 99 } 100 101 var out S1 102 if err := plenc.Unmarshal(data, &out); err != nil { 103 t.Fatal(err) 104 } 105 106 if diff := cmp.Diff(test, out); diff != "" { 107 t.Fatalf("Not as expected. %s\n%x", diff, data) 108 } 109 }) 110 } 111 } 112 113 func TestSliceStructPtrNil(t *testing.T) { 114 type S2 struct { 115 A int `plenc:"1"` 116 } 117 type S1 struct { 118 A []*S2 `plenc:"1"` 119 } 120 121 in := S1{A: []*S2{ 122 {A: 1}, 123 nil, 124 {A: 2}, 125 }} 126 127 exp := S1{A: []*S2{ 128 {A: 1}, 129 {}, 130 {A: 2}, 131 }} 132 133 data, err := plenc.Marshal(nil, &in) 134 if err != nil { 135 t.Fatal(err) 136 } 137 138 var out S1 139 if err := plenc.Unmarshal(data, &out); err != nil { 140 t.Fatal(err) 141 } 142 143 if diff := cmp.Diff(exp, out); diff != "" { 144 t.Fatalf("Not as expected. %s\n%x", diff, data) 145 } 146 } 147 148 func TestZeroReuseSlice(t *testing.T) { 149 type s1 struct { 150 A int `plenc:"1"` 151 B int `plenc:"2"` 152 } 153 v := []s1{{A: 1}, {A: 2}} 154 v = v[:0] 155 156 w := []s1{{B: 3}, {B: 4}} 157 data, err := plenc.Marshal(nil, w) 158 if err != nil { 159 t.Fatal(err) 160 } 161 162 if err := plenc.Unmarshal(data, &v); err != nil { 163 t.Fatal(err) 164 } 165 if diff := cmp.Diff(w, v); diff != "" { 166 t.Fatal(diff) 167 } 168 } 169 170 func TestZeroReuse(t *testing.T) { 171 type s1 struct { 172 A int `plenc:"1"` 173 B int `plenc:"2"` 174 } 175 v := s1{A: 37, B: 42} 176 177 w := s1{A: 0, B: 3} 178 data, err := plenc.Marshal(nil, w) 179 if err != nil { 180 t.Fatal(err) 181 } 182 183 // We expect this to update v and not zero fields that aren't in the output. 184 // Note that plenc is implicitly omitempty for some field types, so zero 185 // ints in the data we're unmarshalling won't overwrite anything. 186 if err := plenc.Unmarshal(data, &v); err != nil { 187 t.Fatal(err) 188 } 189 if diff := cmp.Diff(s1{A: 37, B: 3}, v); diff != "" { 190 t.Fatal(diff) 191 } 192 } 193 194 func TestStructDescriptor(t *testing.T) { 195 type s2 struct { 196 A string `plenc:"1"` 197 } 198 type s1 struct { 199 A int `plenc:"1,flat"` 200 B int `plenc:"2"` 201 C s2 `plenc:"3"` 202 } 203 204 c, err := plenc.CodecForType(reflect.TypeOf(s1{})) 205 if err != nil { 206 t.Fatal(err) 207 } 208 209 if diff := cmp.Diff(plenccodec.Descriptor{ 210 TypeName: "s1", 211 Type: plenccodec.FieldTypeStruct, 212 Elements: []plenccodec.Descriptor{ 213 {Index: 1, Name: "A", Type: plenccodec.FieldTypeFlatInt}, 214 {Index: 2, Name: "B", Type: plenccodec.FieldTypeInt}, 215 { 216 Index: 3, 217 Name: "C", 218 Type: plenccodec.FieldTypeStruct, 219 TypeName: "s2", 220 Elements: []plenccodec.Descriptor{ 221 {Index: 1, Name: "A", Type: plenccodec.FieldTypeString}, 222 }, 223 }, 224 }, 225 }, c.Descriptor()); diff != "" { 226 t.Fatal(diff) 227 } 228 }