github.com/philpearl/plenc@v0.0.15/plenccodec/string_test.go (about) 1 package plenccodec_test 2 3 import ( 4 "reflect" 5 "sync" 6 "testing" 7 "unsafe" 8 9 "github.com/google/go-cmp/cmp" 10 "github.com/philpearl/plenc" 11 "github.com/philpearl/plenc/plenccodec" 12 ) 13 14 func TestString(t *testing.T) { 15 tests := []string{ 16 "", 17 "a", 18 "¬πø∆˙©¥å∫˜", 19 "this is a string", 20 "ɚ&d珿ȨDT葚µ噘", 21 "\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00", 22 `¶娋搱ĚoÞB@\贞敠ơƸŜ`, 23 "\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00", 24 } 25 26 for _, test := range tests { 27 t.Run(test, func(t *testing.T) { 28 c, err := plenc.CodecForType(reflect.TypeOf(test)) 29 if err != nil { 30 t.Fatal(err) 31 } 32 33 l := c.Size(unsafe.Pointer(&test), nil) 34 35 data := c.Append(nil, unsafe.Pointer(&test), nil) 36 37 if len(data) != l { 38 t.Errorf("data not expected length. %d %d", l, len(data)) 39 } 40 41 var out string 42 _, err = c.Read(data, unsafe.Pointer(&out), c.WireType()) 43 if err != nil { 44 t.Fatal(err) 45 } 46 47 if diff := cmp.Diff(test, out); diff != "" { 48 t.Fatal(diff) 49 } 50 }) 51 } 52 } 53 54 func TestStringMarshal(t *testing.T) { 55 tests := []string{ 56 "", 57 "a", 58 "¬πø∆˙©¥å∫˜", 59 "this is a string", 60 "ɚ&d珿ȨDT葚µ噘", 61 "\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00", 62 `¶娋搱ĚoÞB@\贞敠ơƸŜ`, 63 "\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00", 64 } 65 66 for _, test := range tests { 67 t.Run(test, func(t *testing.T) { 68 data, err := plenc.Marshal(nil, test) 69 if err != nil { 70 t.Fatal(err) 71 } 72 73 var out string 74 if err := plenc.Unmarshal(data, &out); err != nil { 75 t.Fatal(err) 76 } 77 78 if diff := cmp.Diff(test, out); diff != "" { 79 t.Fatal(diff) 80 } 81 }) 82 } 83 } 84 85 func TestInternedString(t *testing.T) { 86 var c plenccodec.InternedStringCodec 87 88 values := []string{ 89 "hat", "cheese", "elephant", "hat", "hat", "cheese", "elephant", 90 } 91 92 var data []byte 93 allocs := testing.AllocsPerRun(1000, func() { 94 for _, test := range values { 95 l := c.Size(unsafe.Pointer(&test), nil) 96 data = c.Append(data[:0], unsafe.Pointer(&test), nil) 97 98 if len(data) != l { 99 t.Errorf("data not expected length. %d %d", l, len(data)) 100 } 101 102 var out string 103 _, err := c.Read(data, unsafe.Pointer(&out), c.WireType()) 104 if err != nil { 105 t.Fatal(err) 106 } 107 108 if out != test { 109 t.Fatalf("mismatch %q, %q", test, out) 110 } 111 112 } 113 }) 114 115 if allocs > 0.1 { 116 t.Fatal(allocs) 117 } 118 } 119 120 func TestInternedStringParallel(t *testing.T) { 121 type my struct { 122 V string `plenc:"1,intern"` 123 } 124 125 values := []string{ 126 "hat", "cheese", "elephant", "hat", "hat", "cheese", "elephant", 127 } 128 var wg sync.WaitGroup 129 wg.Add(100) 130 for i := 0; i < 100; i++ { 131 go func() { 132 defer wg.Done() 133 var data []byte 134 var val, out my 135 for i := 0; i < 1000; i++ { 136 for _, test := range values { 137 val.V = test 138 data, err := plenc.Marshal(data[:0], &val) 139 if err != nil { 140 t.Error(err) 141 return 142 } 143 144 if err := plenc.Unmarshal(data, &out); err != nil { 145 t.Error(err) 146 return 147 } 148 149 if out.V != test { 150 t.Errorf("mismatch %q, %q", test, out) 151 return 152 } 153 } 154 } 155 }() 156 } 157 wg.Wait() 158 } 159 160 func BenchmarkInternedString(b *testing.B) { 161 type myb struct { 162 V string `plenc:"1,intern"` 163 } 164 165 values := []string{ 166 "hat", "cheese", "elephant", "hat", "hat", "cheese", "elephant", 167 } 168 var data []byte 169 var val, out myb 170 for _, test := range values { 171 val.V = test 172 var err error 173 data, err = plenc.Marshal(data[:0], &val) 174 if err != nil { 175 b.Fatal(err) 176 } 177 178 if err := plenc.Unmarshal(data, &out); err != nil { 179 b.Fatal(err) 180 } 181 182 if out.V != test { 183 b.Fatalf("mismatch %q, %q", test, out) 184 } 185 } 186 187 b.ResetTimer() 188 b.ReportAllocs() 189 for i := 0; i < b.N; i++ { 190 out = myb{} 191 if err := plenc.Unmarshal(data, &out); err != nil { 192 b.Fatal(err) 193 } 194 195 if out.V != "elephant" { 196 b.Fatalf("mismatch %q, %q", "elephant", out) 197 } 198 } 199 } 200 201 func TestStringSlice(t *testing.T) { 202 v := []string{ 203 "M珣X觻%ƾƽ9J9S腸H滩Ýk", 204 "Eŕ漠", 205 "织睱Ħ7õ咖Ê騄", 206 "t沋晛岊ıƭ宋Yȯ¿q&", 207 "Ʊãʙ#訃睩愴émė6Ɍ邔5汚鞗Ƈ", 208 "桏&", 209 "?Ȗ曽Ȯɕ稌!r囮ǯWQ猒÷飹嫗MJ", 210 "", 211 } 212 213 c, err := plenc.CodecForType(reflect.TypeOf(v)) 214 if err != nil { 215 t.Fatal(err) 216 } 217 218 data := c.Append(nil, unsafe.Pointer(&v), nil) 219 220 var out []string 221 _, err = c.Read(data, unsafe.Pointer(&out), c.WireType()) 222 if err != nil { 223 t.Fatal(err) 224 } 225 226 if diff := cmp.Diff(v, out); diff != "" { 227 t.Fatal(diff) 228 } 229 } 230 231 func TestStringSliceCompat(t *testing.T) { 232 type my struct { 233 V []string `plenc:"1"` 234 } 235 v := my{V: []string{ 236 "M珣X觻%ƾƽ9J9S腸H滩Ýk", 237 "Eŕ漠", 238 "织睱Ħ7õ咖Ê騄", 239 "t沋晛岊ıƭ宋Yȯ¿q&", 240 "Ʊãʙ#訃睩愴émė6Ɍ邔5汚鞗Ƈ", 241 "桏&", 242 "?Ȗ曽Ȯɕ稌!r囮ǯWQ猒÷飹嫗MJ", 243 "", 244 "cheese it", 245 "hats", 246 }} 247 248 var pl plenc.Plenc 249 pl.ProtoCompatibleArrays = true 250 pl.RegisterDefaultCodecs() 251 252 data, err := pl.Marshal(nil, v) 253 if err != nil { 254 t.Fatal(err) 255 } 256 257 var out my 258 259 if err := pl.Unmarshal(data, &out); err != nil { 260 t.Fatal(err) 261 } 262 263 if diff := cmp.Diff(v, out); diff != "" { 264 t.Fatal(diff) 265 } 266 }