package models import ( "encoding" "encoding/json" "errors" "testing" "time" "github.com/stretchr/testify/assert" ) // Type assertions var _ encoding.TextMarshaler = Meta{} var _ encoding.TextUnmarshaler = new(Meta) var _ json.Marshaler = Metas{} var _ json.Unmarshaler = new(Metas) var skipMarshalTest = errors.New("skip marshal") func TestMeta(t *testing.T) { when := time.Now() tests := []struct { name string key string value any out string err error newVal any }{ {"int", "num", 42, "@num 42", nil, 42}, {"int64", "num", int64(42), "@num 42", nil, int(42)}, {"float", "num", 42.13, "@num 42.13", nil, 42.13}, {"string", "word", "hello", "@word hello", nil, "hello"}, {"json number", "num", json.Number("42.13"), "@num 42.13", nil, 42.13}, {"true", "b", true, "@b true", nil, true}, {"false", "b", false, "@b false", nil, false}, {"nil", "n", nil, "", nil, ErrorParsing}, {"time", "when", when, "@when " + when.Format(time.RFC3339), nil, when}, {"rune", "char", '@', "@char @", nil, "@"}, {"bytes", "byteme", []byte("yo"), "@byteme yo", nil, "yo"}, {"byte", "byteme", byte(67), "@byteme C", nil, "C"}, {"json-obj", "obj", json.RawMessage(`{"foo":"bar","baz":"quux"}`), `@obj {"foo":"bar","baz":"quux"}`, nil, json.RawMessage(`{"foo":"bar","baz":"quux"}`)}, {"json-arr", "arr", json.RawMessage(`["foo",42,"bar", null,"quux", true]`), `@arr ["foo",42,"bar", null,"quux", true]`, nil, json.RawMessage(`["foo",42,"bar", null,"quux", true]`)}, {"chan", "nope", make(chan bool), "", errors.New("Unsupported type chan bool"), ""}, {"whitespace-key", "no space", "hi", "", errors.New("whitespace is not allowed in key: no space"), ""}, {"empty-mar", "nope", skipMarshalTest, "", nil, ErrorParsing}, {"no-key-mar", "nope", skipMarshalTest, "nope", nil, ErrorParsing}, {"no-value-mar", "nope", skipMarshalTest, "@nope ", nil, ErrorParsing}, {"space-value-mar", "nope", skipMarshalTest, "@nope ", nil, ErrorParsing}, {"space-nl-value-mar", "nope", skipMarshalTest, "@nope \n ", nil, ErrorParsing}, {"null-value-mar", "nope", skipMarshalTest, "@nope null", nil, nil}, {"tilda-value-mar", "nope", skipMarshalTest, "@nope ~", nil, nil}, {"none-value-mar", "nope", skipMarshalTest, "@nope none", nil, nil}, {"nil-value-mar", "nope", skipMarshalTest, "@nope nil", nil, nil}, {"yes-value-mar", "nope", skipMarshalTest, "@nope yes", nil, true}, {"on-value-mar", "nope", skipMarshalTest, "@nope on", nil, true}, {"no-value-mar", "nope", skipMarshalTest, "@nope no", nil, false}, {"off-value-mar", "nope", skipMarshalTest, "@nope off", nil, false}, } for _, tt := range tests { t.Run(tt.name, getMetaTestRunner(tt.key, tt.value, tt.out, tt.err, tt.newVal)) } } func getMetaTestRunner(key string, value any, out string, err error, newVal any) func(*testing.T) { return func(t *testing.T) { st := Meta{key, value} n := &Meta{} var e error if valE, ok := value.(error); !ok || !errors.Is(valE, skipMarshalTest) { var o []byte o, e = st.MarshalText() assert.Equal(t, out, string(o)) assert.Equal(t, err, e) if e != nil { return } e = n.UnmarshalText(o) } else { e = n.UnmarshalText([]byte(out)) } if newE, ok := newVal.(error); ok { assert.ErrorIs(t, e, newE) } else { assert.Equal(t, key, n.Key) if ti, ok := newVal.(time.Time); ok { valT, ok := n.Value.(time.Time) if assert.True(t, ok) { assert.WithinRange(t, valT, ti.Add(-time.Second), ti.Add(time.Second)) } } else { assert.Equal(t, newVal, n.Value) } } } } func TestMetasJson(t *testing.T) { ms := Metas{{"me", 41}, {"you", false}} exp := `{"me":41,"you":false}` o, err := json.Marshal(ms) assert.NoError(t, err) assert.JSONEq(t, exp, string(o)) } func TestMetasJsonUnmarshal(t *testing.T) { ms := Metas{} in := `{"me":"cool","you":false}` err := json.Unmarshal([]byte(in), &ms) assert.NoError(t, err) assert.Len(t, ms, 2) assert.ElementsMatch(t, Metas{ {"me", "cool"}, {"you", false}, }, ms) } func TestMetasJsonError(t *testing.T) { ms := Metas{} in := "not json" err := (&ms).UnmarshalJSON([]byte(in)) assert.Error(t, err) assert.Len(t, ms, 0) } func TestMetasAppend(t *testing.T) { ms := Metas{} ms = ms.Append("foo", 42) assert.Len(t, ms, 1) assert.Equal(t, Meta{"foo", 42}, ms[0]) } func TestMetasAppendTo(t *testing.T) { ms := &Metas{} ms.AppendTo("foo", 42) assert.Len(t, *ms, 1) assert.Equal(t, Meta{"foo", 42}, (*ms)[0]) }