func TestInvalidSyncMapKeys(t *testing.T) {
	testInvalidSyncMapKeys(t, true)
	testInvalidSyncMapKeys(t, false)
}
TestInvalidSyncMapKeys tests that marshaling a
sync.Map with unsupported key types returns an
error.
package jettison
import (
	"bytes"
	"context"
	"crypto/rand"
	"encoding/json"
	"errors"
	"fmt"
	"math"
	"math/big"
	"net"
	"reflect"
	"regexp"
	"strconv"
	"sync"
	"testing"
	"time"
)
type (
	jmr string
	jmv []string
)
func (*jmr) MarshalJSON() ([]byte, error) { return []byte(`"XYZ"`), nil }
func (jmv) MarshalJSON() ([]byte, error)  { return []byte(`"ZYX"`), nil }
type (
	mapss struct {
		M map[string]string
	}
	inner struct {
		M map[string]string
	}
	outer struct {
		M map[string]inner
	}
	z struct {
		S []byte
	}
	y struct {
		P float64 `json:"p,omitempty"`
		Q uint64  `json:"q,omitempty"`
		R uint8
	}
	x struct {
		A  *string `json:"a,string"`
		B1 int64   `json:"b1,string"`
		B2 uint16  `json:"b2"`
		C  *bool   `json:"c,string"`
		D  float32
		E1 *[]int
		E2 []string
		E3 []jmr
		F1 [4]string
		F2 [1]jmr
		F3 *[1]jmr
		G1 map[int]*string
		G2 map[string]*map[string]string
		G3 map[int]map[string]map[int]string
		G4 map[string]mapss
		G5 outer
		G6 map[int]jmr
		G7 map[int]*jmr
		G8 map[int]bool `json:",omitempty"`
		H1 jmr
		H2 *jmr
		H3 jmv
		H4 *jmv
		I  time.Time
		J  time.Duration
		K  json.Number
		L  json.RawMessage
		M1 interface{}
		M2 interface{}
		N  struct{}
		X  *x
		*y
		z `json:"z"`
	}
)
var (
	s  = "Loreum"
	b  = true
	m  = map[string]string{"b": "c"}
	xx = x{
		A:  &s,
		B1: -42,
		B2: 42,
		C:  &b,
		D:  math.MaxFloat32,
		E1: &[]int{1, 2, 3},
		E2: []string{"x", "y", "z"},
		E3: []jmr{"1"},
		F1: [4]string{"a", "b", "c", "d"},
		F2: [1]jmr{"1"},
		F3: &[1]jmr{"1"},
		G1: map[int]*string{2: &s, 3: new(string)},
		G2: map[string]*map[string]string{"a": &m},
		G3: map[int]map[string]map[int]string{1: {"a": {2: "b"}}},
		G4: map[string]mapss{"1": {M: map[string]string{"2": "3"}}},
		G5: outer{map[string]inner{"outer": {map[string]string{"key": "val"}}}},
		G6: map[int]jmr{1: "jmr"},
		G7: map[int]*jmr{1: new(jmr)},
		G8: map[int]bool{},
		H1: "jmp",
		H2: nil,
		H3: nil,
		H4: nil,
		I:  time.Now(),
		J:  3 * time.Minute,
		K:  "3.14",
		L:  []byte(`{ "a":"b" }`),
		M1: uint32(255),
		M2: &s,
		X:  &x{H1: "jmv"},
		y:  &y{R: math.MaxUint8},
		z:  z{S: []byte("Loreum")},
	}
)
func marshalCompare(t *testing.T, v interface{}, name string) {
	jb1, err := Marshal(v)
	if err != nil {
		t.Fatal(err)
	}
	jb2, err := MarshalOpts(v)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(jb1, jb2) {
		t.Error("non-equal outputs for Marshal and MarshalOpts")
	}
	jb3, err := Append([]byte(nil), v)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(jb1, jb3) {
		t.Error("non-equal outputs for Marshal and Append")
	}
	sb, err := json.Marshal(v)
	if err != nil {
		t.Fatal(err)
	}
	t.Logf("standard: %s", string(sb))
	t.Logf("jettison: %s", string(jb1))
	if !bytes.Equal(jb1, sb) {
		t.Errorf("%s: non-equal outputs", name)
	}
}
func marshalCompareError(t *testing.T, v interface{}, name string) {
	_, errj := Marshal(v)
	if errj == nil {
		t.Fatalf("expected non-nil error")
	}
	_, errs := json.Marshal(v)
	if errs == nil {
		t.Fatalf("expected non-nil error")
	}
	t.Logf("standard: %s", errs)
	t.Logf("jettison: %s", errj)
	if errs.Error() != errj.Error() {
		t.Errorf("%s: non-equal outputs", name)
	}
}
func TestAll(t *testing.T) {
	marshalCompare(t, nil, "nil")
	marshalCompare(t, xx, "non-pointer")
	marshalCompare(t, &xx, "pointer")
}
func TestInvalidEncodeOpts(t *testing.T) {
	for _, opt := range []Option{
		TimeLayout(""),
		DurationFormat(DurationFmt(-1)),
		DurationFormat(DurationFmt(6)),
		WithContext(nil),  
	} {
		_, err1 := MarshalOpts(struct{}{}, opt)
		_, err2 := AppendOpts([]byte(nil), struct{}{}, opt)
		for _, err := range []error{err1, err2} {
			if err != nil {
				e, ok := err.(*InvalidOptionError)
				if !ok {
					t.Errorf("got %T, want InvalidOptionError", err)
				}
				if e.Error() == "" {
					t.Errorf("expected non-empty error message")
				}
			} else {
				t.Error("expected non-nil error")
			}
		}
	}
}
func TestBasicTypes(t *testing.T) {
	testdata := []interface{}{
		true,
		false,
		"Loreum",
		int8(math.MaxInt8),
		int16(math.MaxInt16),
		int32(math.MaxInt32),
		int64(math.MaxInt64),
		uint8(math.MaxUint8),
		uint16(math.MaxUint16),
		uint32(math.MaxUint32),
		uint64(math.MaxUint64),
		uintptr(0xBEEF),
		(*bool)(nil),
		(*int)(nil),
		(*string)(nil),
	}
	for _, v := range testdata {
		marshalCompare(t, v, "")
	}
}
func TestCompositeTypes(t *testing.T) {
	var (
		jmref = jmr("jmr")
		jmval = jmv([]string{"a", "b", "c"})
	)
	testdata := []interface{}{
		[]uint{},
		[]int{1, 2, 3},
		[]int(nil),
		(*[]int)(nil),
		[]string{"a", "b", "c"},
		[2]bool{true, false},
		(*[4]string)(nil),
		map[string]int{"a": 1, "b": 2},
		&map[int]string{1: "a", 2: "b"},
		(map[string]int)(nil),
		time.Now(),
		3*time.Minute + 35*time.Second,
		jmref,
		&jmref,
		jmval,
		&jmval,
	}
	for _, v := range testdata {
		marshalCompare(t, v, "")
	}
}
func TestUnsupportedTypes(t *testing.T) {
	testdata := []interface{}{
		make(chan int),
		func() {},
		complex64(0),
		complex128(0),
		make([]chan int, 1),
		[1]complex64{},
		&[1]complex128{},
		map[int]chan bool{1: make(chan bool)},
		struct{ F func() }{func() {}},
		&struct{ C complex64 }{0},
	}
	for _, v := range testdata {
		marshalCompareError(t, v, "")
	}
}
func TestInvalidFloatValues(t *testing.T) {
	for _, v := range []float64{
		math.NaN(),
		math.Inf(-1),
		math.Inf(1),
	} {
		_, err := Marshal(v)
		if err != nil {
			if _, ok := err.(*UnsupportedValueError); !ok {
				t.Errorf("got %T, want UnsupportedValueError", err)
			}
		} else {
			t.Error("got nil, want non-nil error")
		}
		marshalCompareError(t, v, "")
	}
}
func TestJSONNumber(t *testing.T) {
	valid := []json.Number{
		"42",
		"-42",
		"24.42",
		"-666.66",
		"3.14",
		"-3.14",
		"1e3",
		"1E-6",
		"1E+42",
		"",
	}
	for _, v := range valid {
		marshalCompare(t, v, "valid")
	}
	invalid := []json.Number{
		"1E+4.0",
		"084",
		"-03.14",
		"-",
		"invalid",
	}
	for _, v := range invalid {
		marshalCompareError(t, v, "invalid")
	}
}
func TestInvalidTime(t *testing.T) {
	for _, tm := range []time.Time{
		time.Date(-1, time.January, 1, 0, 0, 0, 0, time.UTC),
		time.Date(10000, time.January, 1, 0, 0, 0, 0, time.UTC),
	} {
		_, err := Marshal(tm)
		if err != nil {
			want := "time: year outside of range [0,9999]"
			if err.Error() != want {
				t.Errorf("got %q, want %q", err.Error(), want)
			}
		} else {
			t.Error("got nil, want non-nil error")
		}
	}
}
func TestRenamedByteSlice(t *testing.T) {
	type (
		b  byte
		b1 []byte
		b2 []b
	)
	testdata := []interface{}{
		b1("byte slice 1"),
		b2("byte slice 2"),
	}
	for _, v := range testdata {
		marshalCompare(t, v, "")
	}
}
func TestByteSliceSizes(t *testing.T) {
	makeSlice := func(size int) []byte {
		b := make([]byte, size)
		if _, err := rand.Read(b); err != nil {
			t.Fatal(err)
		}
		return b
	}
	for _, v := range []interface{}{
		makeSlice(0),
		makeSlice(1024),
		makeSlice(2048),
		makeSlice(4096),
		makeSlice(8192),
	} {
		marshalCompare(t, v, "")
	}
}
func TestSortedSyncMap(t *testing.T) {
	var sm sync.Map
	sm.Store(1, "one")
	sm.Store("a", 42)
	sm.Store("b", false)
	sm.Store(mkvstrMarshaler("c"), -42)
	sm.Store(mkrstrMarshaler("d"), true)
	sm.Store(mkvintMarshaler(42), 1)
	sm.Store(mkrintMarshaler(42), 2)
	b, err := Marshal(&sm)
	if err != nil {
		t.Fatal(err)
	}
	want := `{"1":"one","42":2,"MKVINT":1,"a":42,"b":false,"c":-42,"d":true}`
	if !bytes.Equal(b, []byte(want)) {
		t.Errorf("got %#q, want %#q", b, want)
	}
}
func TestUnsortedSyncMap(t *testing.T) {
	entries := map[string]struct {
		key interface{}
		val interface{}
	}{
		"1":      {1, "one"},
		"a":      {"a", 42},
		"b":      {"b", false},
		"c":      {mkvstrMarshaler("c"), -42},
		"d":      {mkrstrMarshaler("d"), true},
		"MKVINT": {mkvintMarshaler(42), 1},
		"42":     {mkrintMarshaler(42), 2},
	}
	var sm sync.Map
	for _, e := range entries {
		sm.Store(e.key, e.val)
	}
	bts, err := MarshalOpts(&sm, UnsortedMap())
	if err != nil {
		t.Fatal(err)
	}
	m := make(map[string]interface{})
	if err := json.Unmarshal(bts, &m); err != nil {
		t.Fatal(err)
	}
	if g, w := len(m), len(entries); g != w {
		t.Errorf("invalid lengths: got %d, want %d", g, w)
	}
	for k, v := range m {
		b1, err1 := json.Marshal(v)
		b2, err2 := json.Marshal(entries[k].val)
		if err1 != nil {
			t.Fatal(err)
		}
		if err2 != nil {
			t.Fatal(err2)
		}
		if !bytes.Equal(b1, b2) {
			t.Errorf("for key %s: got %v, want %v", k, b1, b2)
		}
	}
}