idnamemap_test.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. package collections
  2. import (
  3. "errors"
  4. "testing"
  5. )
  6. type testItem struct {
  7. id string
  8. name string
  9. value int
  10. }
  11. func (t testItem) Id() string {
  12. return t.id
  13. }
  14. func (t testItem) Name() string {
  15. return t.name
  16. }
  17. func TestNewIdNameMap(t *testing.T) {
  18. m := NewIdNameMap[testItem]()
  19. if m == nil {
  20. t.Fatal("NewIdNameMap returned nil")
  21. }
  22. if m.m == nil {
  23. t.Fatal("internal id map is nil")
  24. }
  25. if m.r == nil {
  26. t.Fatal("internal name map is nil")
  27. }
  28. }
  29. func TestIdNameMap_Insert(t *testing.T) {
  30. m := NewIdNameMap[testItem]()
  31. item := testItem{id: "id1", name: "name1"}
  32. m.Insert(item)
  33. // Verify item can be retrieved by id
  34. retrieved, ok := m.ById("id1")
  35. if !ok {
  36. t.Fatal("item not found by id after insert")
  37. }
  38. if retrieved.Id() != "id1" || retrieved.Name() != "name1" {
  39. t.Errorf("retrieved item mismatch: got %+v, want %+v", retrieved, item)
  40. }
  41. // Verify item can be retrieved by name
  42. retrieved, ok = m.ByName("name1")
  43. if !ok {
  44. t.Fatal("item not found by name after insert")
  45. }
  46. if retrieved.Id() != "id1" || retrieved.Name() != "name1" {
  47. t.Errorf("retrieved item mismatch: got %+v, want %+v", retrieved, item)
  48. }
  49. }
  50. func TestIdNameMap_InsertEmptyIdAndName(t *testing.T) {
  51. m := NewIdNameMap[testItem]()
  52. item1 := testItem{id: "", name: "name1"}
  53. item2 := testItem{id: "id1", name: ""}
  54. err := m.Insert(item1)
  55. if err == nil {
  56. t.Fatalf("Expected insertion failure, but succeeded!")
  57. }
  58. if !errors.Is(err, ErrEmptyID) {
  59. t.Fatalf("Expected ErrEmptyID, but instead got: %s", err.Error())
  60. }
  61. err = m.Insert(item2)
  62. if err == nil {
  63. t.Fatalf("Expected insertion failure, but succeeded!")
  64. }
  65. if !errors.Is(err, ErrEmptyName) {
  66. t.Fatalf("Expected ErrEmptyName, but instead got: %s", err.Error())
  67. }
  68. }
  69. func TestIdNameMap_InsertDuplicateId(t *testing.T) {
  70. m := NewIdNameMap[testItem]()
  71. item1 := testItem{id: "id1", name: "name1"}
  72. item2 := testItem{id: "id1", name: "name2"}
  73. item3 := testItem{id: "id1", name: "name1", value: 10}
  74. err := m.Insert(item1)
  75. if err != nil {
  76. t.Fatalf("%s", err.Error())
  77. return
  78. }
  79. // should fail
  80. err = m.Insert(item2)
  81. if err == nil {
  82. t.Fatalf("Expected insertion to fail, but it succeeded!")
  83. } else {
  84. t.Logf("%s", err.Error())
  85. }
  86. err = m.Insert(item3)
  87. if err != nil {
  88. t.Fatalf("%s", err.Error())
  89. }
  90. // Verify second item overwrote the first
  91. retrieved, ok := m.ById("id1")
  92. if !ok {
  93. t.Fatal("item not found by id")
  94. }
  95. if retrieved.Name() != "name1" {
  96. t.Errorf("expected name1, got %s", retrieved.Name())
  97. }
  98. // Failed name should not exist
  99. _, ok = m.ByName("name2")
  100. if ok {
  101. t.Error("old name should not exist after overwrite")
  102. }
  103. // Second name should exist
  104. retrieved, ok = m.ByName("name1")
  105. if !ok {
  106. t.Fatal("new name not found")
  107. }
  108. if retrieved.Id() != "id1" {
  109. t.Errorf("expected id1, got %s", retrieved.Id())
  110. }
  111. if retrieved.value != 10 {
  112. t.Errorf("expected 10, got: %d", retrieved.value)
  113. }
  114. }
  115. func TestIdNameMap_InsertDuplicateName(t *testing.T) {
  116. m := NewIdNameMap[testItem]()
  117. item1 := testItem{id: "id1", name: "name1"}
  118. item2 := testItem{id: "id2", name: "name1"}
  119. item3 := testItem{id: "id1", name: "name1", value: 10}
  120. err := m.Insert(item1)
  121. if err != nil {
  122. t.Fatalf("%s", err.Error())
  123. return
  124. }
  125. // expect error
  126. err = m.Insert(item2)
  127. if err == nil {
  128. t.Fatalf("Expected insertion to fail, but it succeeded!")
  129. } else {
  130. t.Log(err)
  131. }
  132. // overwrite
  133. err = m.Insert(item3)
  134. if err != nil {
  135. t.Fatal(err)
  136. }
  137. // Verify second item overwrote the first by name
  138. retrieved, ok := m.ByName("name1")
  139. if !ok {
  140. t.Fatal("item not found by name")
  141. }
  142. if retrieved.Id() != "id1" {
  143. t.Errorf("expected id1, got %s", retrieved.Id())
  144. }
  145. // id2 shouldn't exist
  146. _, ok = m.ById("id2")
  147. if ok {
  148. t.Error("id2 failed to insert, so should not exist")
  149. }
  150. retrieved, ok = m.ById("id1")
  151. if !ok {
  152. t.Fatal("id1 not found")
  153. }
  154. if retrieved.Name() != "name1" {
  155. t.Errorf("expected name1, got %s", retrieved.Name())
  156. }
  157. if retrieved.value != 10 {
  158. t.Errorf("expected value: 10, got %d", retrieved.value)
  159. }
  160. }
  161. func TestIdNameMap_InsertTrickyPartialOverwrites(t *testing.T) {
  162. m := NewIdNameMap[testItem]()
  163. // 2 unique items
  164. item1 := testItem{id: "id1", name: "foo"}
  165. item2 := testItem{id: "id2", name: "bar"}
  166. // item overlaps id from previous entry, and name from another previous entry
  167. item3 := testItem{id: "id1", name: "bar"}
  168. err := m.Insert(item1)
  169. if err != nil {
  170. t.Fatal(err)
  171. }
  172. err = m.Insert(item2)
  173. if err != nil {
  174. t.Fatal(err)
  175. }
  176. err = m.Insert(item3)
  177. if err == nil {
  178. t.Fatalf("Expected to fail, but insert succeeded!")
  179. } else {
  180. t.Log(err)
  181. }
  182. if !m.RemoveById("id1") {
  183. t.Fatalf("Expected to remove entry with id: 'id1', but failed")
  184. }
  185. // this will _still_ be a partial insert, so expect failure
  186. err = m.Insert(item3)
  187. if err == nil {
  188. t.Fatalf("Expected to fail, but insert succeeded!")
  189. } else {
  190. t.Log(err)
  191. }
  192. if !m.RemoveByName("bar") {
  193. t.Fatalf("Expected to remove entry with name: 'bar', but failed")
  194. }
  195. // this should now succeed!
  196. err = m.Insert(item3)
  197. if err != nil {
  198. t.Fatal(err)
  199. }
  200. }
  201. func TestIdNameMap_ByIdNotFound(t *testing.T) {
  202. m := NewIdNameMap[testItem]()
  203. _, ok := m.ById("nonexistent")
  204. if ok {
  205. t.Error("expected false for nonexistent id")
  206. }
  207. }
  208. func TestIdNameMap_ByNameNotFound(t *testing.T) {
  209. m := NewIdNameMap[testItem]()
  210. _, ok := m.ByName("nonexistent")
  211. if ok {
  212. t.Error("expected false for nonexistent name")
  213. }
  214. }
  215. func TestIdNameMap_RemoveById(t *testing.T) {
  216. m := NewIdNameMap[testItem]()
  217. item := testItem{id: "id1", name: "name1"}
  218. m.Insert(item)
  219. // Verify item exists
  220. _, ok := m.ById("id1")
  221. if !ok {
  222. t.Fatal("item should exist before removal")
  223. }
  224. _, ok = m.ByName("name1")
  225. if !ok {
  226. t.Fatal("item should exist before removal")
  227. }
  228. // Remove by id
  229. removed := m.RemoveById("id1")
  230. if !removed {
  231. t.Error("RemoveById should return true for existing item")
  232. }
  233. // Verify item no longer exists
  234. _, ok = m.ById("id1")
  235. if ok {
  236. t.Error("item should not exist after removal by id")
  237. }
  238. _, ok = m.ByName("name1")
  239. if ok {
  240. t.Error("item should not exist after removal by id")
  241. }
  242. }
  243. func TestIdNameMap_RemoveByIdNotFound(t *testing.T) {
  244. m := NewIdNameMap[testItem]()
  245. removed := m.RemoveById("nonexistent")
  246. if removed {
  247. t.Error("RemoveById should return false for nonexistent item")
  248. }
  249. }
  250. func TestIdNameMap_RemoveByName(t *testing.T) {
  251. m := NewIdNameMap[testItem]()
  252. item := testItem{id: "id1", name: "name1"}
  253. m.Insert(item)
  254. // Verify item exists
  255. _, ok := m.ById("id1")
  256. if !ok {
  257. t.Fatal("item should exist before removal")
  258. }
  259. _, ok = m.ByName("name1")
  260. if !ok {
  261. t.Fatal("item should exist before removal")
  262. }
  263. // Remove by name
  264. removed := m.RemoveByName("name1")
  265. if !removed {
  266. t.Error("RemoveByName should return true for existing item")
  267. }
  268. // Verify item no longer exists
  269. _, ok = m.ById("id1")
  270. if ok {
  271. t.Error("item should not exist after removal by name")
  272. }
  273. _, ok = m.ByName("name1")
  274. if ok {
  275. t.Error("item should not exist after removal by name")
  276. }
  277. }
  278. func TestIdNameMap_RemoveByNameNotFound(t *testing.T) {
  279. m := NewIdNameMap[testItem]()
  280. removed := m.RemoveByName("nonexistent")
  281. if removed {
  282. t.Error("RemoveByName should return false for nonexistent item")
  283. }
  284. }
  285. func TestIdNameMap_Keys(t *testing.T) {
  286. m := NewIdNameMap[testItem]()
  287. items := []testItem{
  288. {id: "id1", name: "name1"},
  289. {id: "id2", name: "name2"},
  290. {id: "id3", name: "name3"},
  291. }
  292. for _, item := range items {
  293. m.Insert(item)
  294. }
  295. keys := make(map[string]string)
  296. for id, name := range m.Keys() {
  297. keys[id] = name
  298. }
  299. if len(keys) != 3 {
  300. t.Errorf("expected 3 keys, got %d", len(keys))
  301. }
  302. for _, item := range items {
  303. name, ok := keys[item.id]
  304. if !ok {
  305. t.Errorf("missing key for id %s", item.id)
  306. }
  307. if name != item.name {
  308. t.Errorf("wrong name for id %s: got %s, want %s", item.id, name, item.name)
  309. }
  310. }
  311. }
  312. func TestIdNameMap_Values(t *testing.T) {
  313. m := NewIdNameMap[testItem]()
  314. items := []testItem{
  315. {id: "id1", name: "name1"},
  316. {id: "id2", name: "name2"},
  317. {id: "id3", name: "name3"},
  318. }
  319. for _, item := range items {
  320. m.Insert(item)
  321. }
  322. values := make(map[string]testItem)
  323. for value := range m.Values() {
  324. values[value.Id()] = value
  325. }
  326. if len(values) != 3 {
  327. t.Errorf("expected 3 values, got %d", len(values))
  328. }
  329. for _, item := range items {
  330. value, ok := values[item.id]
  331. if !ok {
  332. t.Errorf("missing value for id %s", item.id)
  333. }
  334. if value.Id() != item.id || value.Name() != item.name {
  335. t.Errorf("wrong value for id %s: got %+v, want %+v", item.id, value, item)
  336. }
  337. }
  338. }
  339. func TestIdNameMap_EmptyIterators(t *testing.T) {
  340. m := NewIdNameMap[testItem]()
  341. // Test empty Keys iterator
  342. count := 0
  343. for range m.Keys() {
  344. count++
  345. }
  346. if count != 0 {
  347. t.Errorf("expected 0 keys in empty map, got %d", count)
  348. }
  349. // Test empty Values iterator
  350. count = 0
  351. for range m.Values() {
  352. count++
  353. }
  354. if count != 0 {
  355. t.Errorf("expected 0 values in empty map, got %d", count)
  356. }
  357. }
  358. func TestIdNameMap_IteratorEarlyBreak(t *testing.T) {
  359. m := NewIdNameMap[testItem]()
  360. items := []testItem{
  361. {id: "id1", name: "name1"},
  362. {id: "id2", name: "name2"},
  363. {id: "id3", name: "name3"},
  364. }
  365. for _, item := range items {
  366. m.Insert(item)
  367. }
  368. // Test early break in Keys iterator
  369. count := 0
  370. for range m.Keys() {
  371. count++
  372. if count == 1 {
  373. break
  374. }
  375. }
  376. if count != 1 {
  377. t.Errorf("expected early break to work in Keys iterator, got count %d", count)
  378. }
  379. // Test early break in Values iterator
  380. count = 0
  381. for range m.Values() {
  382. count++
  383. if count == 1 {
  384. break
  385. }
  386. }
  387. if count != 1 {
  388. t.Errorf("expected early break to work in Values iterator, got count %d", count)
  389. }
  390. }