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  }