/* Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments Copyright (C) ITsysCOM GmbH This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ package utils import ( "crypto/rand" "reflect" "testing" "github.com/google/go-cmp/cmp" ) func TestOrderedMapSetGetDelete(t *testing.T) { testCases := []struct { key string value string }{ {"shortKey", "shortValue"}, {"longKeylongKeylongKeylongKeylongKeylongKey", "longValuelongValuelongValuelongValuelongValue"}, {"keyWithSpecialCharacters!@#$%^&*()", "valueWithSpecialCharacters!@#$%^&*()"}, {"", ""}, } for _, tc := range testCases { // Initialize a new OrderedMap for each test case om := NewOrderedMap[string, string]() // Perform a set and a get for the initial key-value pair om.Set(tc.key, tc.value) val, ok := om.Get(tc.key) if !ok || val != tc.value { t.Errorf("Set key-value pair did not match Get result: expected %s, got %s", tc.value, val) } // Update the value newValue := tc.value + "updated" om.Set(tc.key, newValue) val, ok = om.Get(tc.key) if !ok || val != newValue { t.Errorf("Updated key-value pair did not match Get result: expected %s, got %s", newValue, val) } // Delete the key om.Delete(tc.key) _, ok = om.Get(tc.key) if ok { t.Errorf("Deleted key was still found in map") } // Try to get a non-existent key _, ok = om.Get("non-existent key") if ok { t.Errorf("Non-existent key was found in map") } } } func TestOrderedMapKeysValues(t *testing.T) { // Initialize a new OrderedMap om := NewOrderedMap[string, string]() // Set multiple key-value pairs om.Set("key1", "value1") om.Set("key2", "value2") om.Set("key3", "value3") // Get the keys and values keys := om.Keys() values := om.Values() // Check the keys expectedKeys := []string{"key1", "key2", "key3"} if !reflect.DeepEqual(keys, expectedKeys) { t.Errorf("Keys do not match expected keys: expected %v, received %v", expectedKeys, keys) } // Check the values expectedValues := []string{"value1", "value2", "value3"} if !reflect.DeepEqual(values, expectedValues) { t.Errorf("Values do not match expected values: expected %v, received %v", expectedValues, values) } } func TestOrderedMapMap(t *testing.T) { // Initialize a new OrderedMap nm := NewOrderedMap[string, []string]() // Set multiple key-value pairs nm.Set("key1", []string{"value1", "value21"}) nm.Set("key2", []string{"value2", "value22"}) nm.Set("key3", []string{"value3", "value23"}) // Return a deep copy of the ordered map's key-value pairs. val := nm.Map() expected := map[string][]string{ "key1": {"value1", "value21"}, "key2": {"value2", "value22"}, "key3": {"value3", "value23"}} // Compare the enerated map if diff := cmp.Diff(expected, val); diff != "" { t.Errorf("OrderedMap.Map() returned an unexpected value(-want +got): \n%s", diff) } } func TestOrderMapGetByIndex(t *testing.T) { testcases := []struct { index int value string key string received bool }{ { index: 0, value: "value1", key: "key1", received: true, }, { index: 1, received: false, }, } nom := NewOrderedMap[string, string]() nom.Set("key1", "value1") for _, tc := range testcases { key, val, has := nom.GetByIndex(tc.index) if tc.received != has { t.Errorf("index is out of bounds") return } if key != tc.key { t.Errorf(" expected key %v, received %v", tc.key, key) } if val != tc.value { t.Errorf(" expected value %v, received %v", tc.value, val) } } } // Benchmark that emphasizes the difference in performance for simple values between // OrderedNavigableMap and the generic OrderedMap. // Sample usage: go test -bench=. -run=Benchmark_NavigableMaps -benchtime=5s -count 3 -benchmem func BenchmarkOrderedMaps(b *testing.B) { letterBytes := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" // Function to generate a random string of `strLen` length randomString := func(strLen int) string { byt := make([]byte, strLen) rand.Read(byt) for i := range byt { byt[i] = letterBytes[byt[i]%byte(len(letterBytes))] } return string(byt) } // Function to generate a slice of n random strings generateStringSlice := func(n int) []string { randStrings := make([]string, n) for i := range randStrings { randStrings[i] = randomString(10) } return randStrings } keys := generateStringSlice(100000) values := generateStringSlice(100000) b.Run("Generic ordered map - Set", func(b *testing.B) { genericOm := NewOrderedMap[string, string]() b.ResetTimer() for i := 0; i < b.N; i++ { genericOm.Set(keys[i%len(keys)], values[i%len(values)]) } }) b.Run("Generic ordered map - Get", func(b *testing.B) { genericOm := NewOrderedMap[string, string]() for i := 0; i < len(keys); i++ { genericOm.Set(keys[i], values[i]) } b.ResetTimer() for i := 0; i < b.N; i++ { _, _ = genericOm.Get(keys[i%len(keys)]) } }) b.Run("OrderedNavigableMap - Set", func(b *testing.B) { onm := NewOrderedNavigableMap() b.ResetTimer() for i := 0; i < b.N; i++ { onm.Set(&FullPath{ Path: keys[i%len(keys)], PathSlice: []string{keys[i%len(keys)]}, }, NewLeafNode(values[i%len(values)])) } }) b.Run("OrderedNavigableMap - Field+String", func(b *testing.B) { onm := NewOrderedNavigableMap() for i := 0; i < len(keys); i++ { onm.Set(&FullPath{ Path: keys[i], PathSlice: []string{keys[i]}, }, NewLeafNode(values[i%len(values)])) } b.ResetTimer() for i := 0; i < b.N; i++ { val, _ := onm.Field([]string{keys[i%len(keys)]}) _ = val.String() } }) }