package orderedmap import ( "encoding/json" "fmt" "math/rand" "strconv" "sync" "testing" "time" "github.com/spf13/cast" ) func TestOrderedMap(t *testing.T) { o := New() // number o.Set("number", 3) v, _ := o.Get("number") if v.(int) != 3 { t.Error("Set number") } // string o.Set("string", "x") v, _ = o.Get("string") if v.(string) != "x" { t.Error("Set string") } // string slice o.Set("strings", []string{ "t", "u", }) v, _ = o.Get("strings") if v.([]string)[0] != "t" { t.Error("Set strings first index") } if v.([]string)[1] != "u" { t.Error("Set strings second index") } // mixed slice o.Set("mixed", []interface{}{ 1, "1", }) v, _ = o.Get("mixed") if v.([]interface{})[0].(int) != 1 { t.Error("Set mixed int") } if v.([]interface{})[1].(string) != "1" { t.Error("Set mixed string") } // overriding existing key o.Set("number", 4) v, _ = o.Get("number") if v.(int) != 4 { t.Error("Override existing key") } // Keys method keys := o.Keys() expectedKeys := []string{ "number", "string", "strings", "mixed", } for i := range keys { if keys[i] != expectedKeys[i] { t.Error("Keys method", keys[i], "!=", expectedKeys[i]) } } for i := range expectedKeys { if keys[i] != expectedKeys[i] { t.Error("Keys method", keys[i], "!=", expectedKeys[i]) } } // delete o.Delete("strings") o.Delete("not a key being used") if len(o.Keys()) != 3 { t.Error("Delete method") } _, ok := o.Get("strings") if ok { t.Error("Delete did not remove 'strings' key") } } func TestBlankMarshalJSON(t *testing.T) { o := New() // blank map b, err := json.Marshal(o) if err != nil { t.Error("Marshalling blank map to json", err) } s := string(b) // check json is correctly ordered if s != `{}` { t.Error("JSON Marshaling blank map value is incorrect", s) } // convert to indented json bi, err := json.MarshalIndent(o, "", " ") if err != nil { t.Error("Marshalling indented json for blank map", err) } si := string(bi) ei := `{}` if si != ei { fmt.Println(ei) fmt.Println(si) t.Error("JSON MarshalIndent blank map value is incorrect", si) } } func TestMarshalJSON(t *testing.T) { o := New() // number o.Set("number", 3) // string o.Set("string", "x") // new value keeps key in old position o.Set("number", 4) // keys not sorted alphabetically o.Set("z", 1) o.Set("a", 2) o.Set("b", 3) // slice o.Set("slice", []interface{}{ "1", 1, }) // orderedmap v := New() v.Set("e", 1) v.Set("a", 2) o.Set("orderedmap", v) // double quote in key o.Set(`test"ing`, 9) // convert to json b, err := json.Marshal(o) if err != nil { t.Error("Marshalling json", err) } s := string(b) // check json is correctly ordered if s != `{"number":4,"string":"x","z":1,"a":2,"b":3,"slice":["1",1],"orderedmap":{"e":1,"a":2},"test\"ing":9}` { t.Error("JSON Marshal value is incorrect", s) } // convert to indented json bi, err := json.MarshalIndent(o, "", " ") if err != nil { t.Error("Marshalling indented json", err) } si := string(bi) ei := `{ "number": 4, "string": "x", "z": 1, "a": 2, "b": 3, "slice": [ "1", 1 ], "orderedmap": { "e": 1, "a": 2 }, "test\"ing": 9 }` if si != ei { fmt.Println(ei) fmt.Println(si) t.Error("JSON MarshalIndent value is incorrect", si) } } func TestUnmarshalJSON(t *testing.T) { s := `{ "number": 4, "string": "x", "z": 1, "a": "should not break with unclosed { character in value", "b": 3, "slice": [ "1", 1 ], "orderedmap": { "e": 1, "a { nested key with brace": "with a }}}} }} {{{ brace value", "after": { "link": "test {{{ with even deeper nested braces }" } }, "test\"ing": 9, "after": 1, "multitype_array": [ "test", 1, { "map": "obj", "it" : 5, ":colon in key": "colon: in value" } ], "should not break with { character in key": 1 }` o := New() err := json.Unmarshal([]byte(s), &o) if err != nil { t.Error("JSON Unmarshal error", err) } // Check the root keys expectedKeys := []string{ "number", "string", "z", "a", "b", "slice", "orderedmap", "test\"ing", "after", "multitype_array", "should not break with { character in key", } k := o.Keys() for i := range k { if k[i] != expectedKeys[i] { t.Error("Unmarshal root key order", i, k[i], "!=", expectedKeys[i]) } } // Check nested maps are converted to orderedmaps // nested 1 level deep expectedKeys = []string{ "e", "a { nested key with brace", "after", } vi, ok := o.Get("orderedmap") if !ok { t.Error("Missing key for nested map 1 deep") } v := vi.(*Map) k = v.Keys() for i := range k { if k[i] != expectedKeys[i] { t.Error("Key order for nested map 1 deep ", i, k[i], "!=", expectedKeys[i]) } } // nested 2 levels deep expectedKeys = []string{ "link", } vi, ok = v.Get("after") if !ok { t.Error("Missing key for nested map 2 deep") } v = vi.(*Map) k = v.Keys() for i := range k { if k[i] != expectedKeys[i] { t.Error("Key order for nested map 2 deep", i, k[i], "!=", expectedKeys[i]) } } // multitype array expectedKeys = []string{ "map", "it", ":colon in key", } vislice, ok := o.Get("multitype_array") if !ok { t.Error("Missing key for multitype array") } vslice := vislice.([]interface{}) vmap := vslice[2].(*Map) k = vmap.Keys() for i := range k { if k[i] != expectedKeys[i] { t.Error("Key order for nested map 2 deep", i, k[i], "!=", expectedKeys[i]) } } } func TestUnmarshalJSONSpecialChars(t *testing.T) { s := `{ " \\\\\\\\\\\\ " : { "\\\\\\" : "\\\\\"\\" }, "\\": " \\\\ test " }` o := New() err := json.Unmarshal([]byte(s), &o) if err != nil { t.Error("JSON Unmarshal error with special chars", err) } } func TestUnmarshalJSONArrayOfMaps(t *testing.T) { s := ` { "name": "test", "percent": 6, "breakdown": [ { "name": "a", "percent": 0.9 }, { "name": "b", "percent": 0.9 }, { "name": "d", "percent": 0.4 }, { "name": "e", "percent": 2.7 } ] } ` o := New() err := json.Unmarshal([]byte(s), &o) if err != nil { t.Error("JSON Unmarshal error", err) } // Check the root keys expectedKeys := []string{ "name", "percent", "breakdown", } k := o.Keys() for i := range k { if k[i] != expectedKeys[i] { t.Error("Unmarshal root key order", i, k[i], "!=", expectedKeys[i]) } } // Check nested maps are converted to orderedmaps // nested 1 level deep expectedKeys = []string{ "name", "percent", } vi, ok := o.Get("breakdown") if !ok { t.Error("Missing key for nested map 1 deep") } vs := vi.([]interface{}) for _, vInterface := range vs { v := vInterface.(*Map) k = v.Keys() for i := range k { if k[i] != expectedKeys[i] { t.Error("Key order for nested map 1 deep ", i, k[i], "!=", expectedKeys[i]) } } } } func TestInsertAt(t *testing.T) { om := New() om.Set("zero", 0) om.Set("one", 1) om.Set("two", 2) err := om.InsertAt("TEST", 10000, 4) //3 is this added one in size of map if err == nil { t.Error("expected insert at greater position than size of map to produce error") } err = om.InsertAt("A", 100, 2) if err != nil { t.Error(err) } // Test it's at end if om.values[om.keys[2]] != 100 { t.Error("expected entry A to be at position 2", om.keys) } if om.values[om.keys[3]] != 2 { t.Error("expected two to be in position 1", om.keys) } err = om.InsertAt("B", 200, 0) if err != nil { t.Error(err) } if om.values[om.keys[0]] != 200 { t.Error("expected B to be position 0", om.keys) } err = om.InsertAt("C", 300, -1) if err != nil { t.Error(err) } // Should show up at the end if om.values[om.keys[len(om.keys)-1]] != 300 { t.Error(fmt.Sprintf("expected C to be in position %d", len(om.keys)-1), om.keys) } err = om.InsertAt("D", 400, 1) if err != nil { t.Error(err) } if om.values[om.keys[1]] != 400 { t.Error("expceted D to be position 1", om.keys) } err = om.InsertAt("F", 600, -8) if err != nil { t.Error(err) } if om.values[om.keys[0]] != 600 { t.Error("expected F to be in position 0", om.keys) } } func TestConcurrency(t *testing.T) { wg := sync.WaitGroup{} type concurrency struct { a string b int c time.Time d bool } //Starting Map m := New() m.Set("A", concurrency{"string", 10, time.Now(), true}) m.Set("B", concurrency{"string", 10, time.Now(), true}) m.Set("C", concurrency{"string", 10, time.Now(), true}) m.Set("D", concurrency{"string", 10, time.Now(), true}) m.Set("E", concurrency{"string", 10, time.Now(), true}) m.Set("F", concurrency{"string", 10, time.Now(), true}) m.Set("G", concurrency{"string", 10, time.Now(), true}) m.Set("H", concurrency{"string", 10, time.Now(), true}) //Inserts wg.Add(1) go func() { defer wg.Done() for i := 0; i < 50; i++ { wg.Add(1) go func(index int) { defer wg.Done() m.Set("New"+strconv.Itoa(index), concurrency{"string", index, time.Now(), cast.ToBool(index % 2)}) }(i) } }() //Reads wg.Add(1) go func() { defer wg.Done() for i := 0; i < 50; i++ { wg.Add(1) go func(index int) { defer wg.Done() _, _ = m.Get("New" + strconv.Itoa(rand.Intn(99))) }(i) } }() //Marshalling like endpoint wg.Add(1) go func() { defer wg.Done() for i := 0; i < 50; i++ { wg.Add(1) go func(index int) { defer wg.Done() _, err := m.MarshalJSON() if err != nil { t.Error(err) } }(i) } }() wg.Wait() }