github.com/Schaudge/grailbase@v0.0.0-20240223061707-44c758a471c0/eventlog/internal/marshal/marshal_test.go (about) 1 // Copyright 2020 GRAIL, Inc. All rights reserved. 2 // Use of this source code is governed by the Apache 2.0 3 // license that can be found in the LICENSE file. 4 5 package marshal 6 7 import ( 8 "encoding/json" 9 "strings" 10 "testing" 11 ) 12 13 // TestMarshal verifies that Marshal behaves properly in both success and 14 // failure cases. For success cases, it roundtrips the marshaled string and 15 // verifies the result. For failure cases, it checks for expected error 16 // messages. 17 func TestMarshal(t *testing.T) { 18 for _, c := range []struct { 19 name string 20 fieldPairs []interface{} 21 // errNeedle is "" if we expect no error. Otherwise, it is a string that 22 // we expect to see in the resulting err.Error(). 23 errNeedle string 24 }{ 25 { 26 "no fields", 27 []interface{}{}, 28 "", 29 }, 30 { 31 "simple", 32 []interface{}{"k0", "v0"}, 33 "", 34 }, 35 { 36 "mixed value types", 37 // Numeric types turn into float64s in JSON. 38 []interface{}{"k0", "v0", "k1", float64(1), "k2", true}, 39 "", 40 }, 41 { 42 "odd field pairs", 43 []interface{}{"k0", "v0", "k1"}, 44 "even", 45 }, 46 { 47 "non-string key", 48 []interface{}{0, "v0"}, 49 "string", 50 }, 51 { 52 "duplicate keys", 53 []interface{}{"k0", "v0", "k0", "v1"}, 54 "duplicate", 55 }, 56 } { 57 t.Run(c.name, func(t *testing.T) { 58 marshalOK := c.errNeedle == "" 59 s, err := Marshal(c.name, c.fieldPairs) 60 if got, want := err == nil, marshalOK; got != want { 61 t.Fatalf("got %v, want %v", got, want) 62 } 63 if !marshalOK { 64 if !strings.Contains(err.Error(), c.errNeedle) { 65 t.Errorf("error %q does not contain expected substring %q", err.Error(), c.errNeedle) 66 } 67 return 68 } 69 var m map[string]interface{} 70 err = json.Unmarshal([]byte(s), &m) 71 if err != nil { 72 t.Fatalf("unmarshaling failed: %v", err) 73 } 74 // The +1 is for the eventType. 75 if got, want := len(m), (len(c.fieldPairs)/2)+1; got != want { 76 t.Errorf("got %v, want %v", got, want) 77 } 78 typ, ok := m[eventTypeFieldKey] 79 if ok { 80 if got, want := typ, c.name; got != want { 81 t.Errorf("got %v, want %v", got, want) 82 } 83 } else { 84 t.Errorf("eventType field not marshaled") 85 } 86 for i := 0; i < len(c.fieldPairs); i++ { 87 key := c.fieldPairs[i].(string) 88 i++ 89 value := c.fieldPairs[i] 90 mvalue, ok := m[key] 91 if !ok { 92 t.Errorf("field with key %q not marshaled", key) 93 continue 94 } 95 if got, want := mvalue, value; got != want { 96 t.Errorf("got %v(%T), want %v(%T)", got, got, want, want) 97 } 98 } 99 }) 100 } 101 }