options_test.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. package options
  2. import (
  3. "testing"
  4. "github.com/stretchr/testify/suite"
  5. )
  6. type OptionsTestSuite struct {
  7. suite.Suite
  8. }
  9. func (s *OptionsTestSuite) TestGet() {
  10. o := New()
  11. o.Set("string_key", "string_value")
  12. o.Set("bool_key", true)
  13. // Existing keys
  14. s.Require().Equal("string_value", Get(o, "string_key", "default_value"))
  15. s.Require().True(Get(o, "bool_key", false))
  16. // Non-existing keys
  17. s.Require().Equal("default_value", Get(o, "non_existing_key", "default_value"))
  18. s.Require().False(Get(o, "another_non_existing_key", false))
  19. // Type mismatch
  20. s.Require().Panics(func() {
  21. _ = Get(o, "string_key", 42)
  22. })
  23. s.Require().Panics(func() {
  24. _ = Get(o, "bool_key", "not_a_bool")
  25. })
  26. }
  27. func (s *OptionsTestSuite) TestAppendToSlice() {
  28. o := New()
  29. o.Set("slice", []int{1, 2, 3})
  30. // Append to existing slice
  31. AppendToSlice(o, "slice", 4, 5)
  32. s.Require().Equal([]int{1, 2, 3, 4, 5}, Get(o, "slice", []int{}))
  33. // Append to non-existing slice
  34. AppendToSlice(o, "new_slice", 10, 20)
  35. s.Require().Equal([]int{10, 20}, Get(o, "new_slice", []int{}))
  36. // Type mismatch
  37. s.Require().Panics(func() {
  38. AppendToSlice(o, "slice", "not_an_int")
  39. })
  40. }
  41. func (s *OptionsTestSuite) TestSliceContains() {
  42. o := New()
  43. o.Set("slice", []string{"apple", "banana", "cherry"})
  44. // Existing values
  45. s.Require().True(SliceContains(o, "slice", "banana"))
  46. s.Require().False(SliceContains(o, "slice", "date"))
  47. // Non-existing slice
  48. s.Require().False(SliceContains(o, "non_existing_slice", "anything"))
  49. // Type mismatch
  50. s.Require().Panics(func() {
  51. SliceContains(o, "slice", 42)
  52. })
  53. }
  54. func (s *OptionsTestSuite) TestPropagate() {
  55. o := New()
  56. o.Set("key1", "value1")
  57. o.Set("key2", 100)
  58. o.Set("key3", false)
  59. child := o.AddChild()
  60. child.Set("key1", "child_value1")
  61. child.Set("key3", true)
  62. grandChild := child.AddChild()
  63. grandChild.Set("key2", 300)
  64. o.Propagate("key1")
  65. o.Propagate("key2")
  66. s.Require().Equal("value1", Get(child, "key1", ""))
  67. s.Require().Equal(100, Get(child, "key2", 0))
  68. s.Require().True(Get(child, "key3", false))
  69. s.Require().Equal("value1", Get(grandChild, "key1", ""))
  70. s.Require().Equal(100, Get(grandChild, "key2", 0))
  71. s.Require().False(grandChild.Has("key3"))
  72. }
  73. func (s *OptionsTestSuite) TestDeleteFromDescendants() {
  74. o := New()
  75. o.Set("key1", "value1")
  76. child := o.AddChild()
  77. child.Set("key1", "child_value1")
  78. child.Set("key2", 200)
  79. grandChild := child.AddChild()
  80. grandChild.Set("key1", "grandchild_value1")
  81. grandChild.Set("key2", 300)
  82. o.DeleteFromDescendants("key1")
  83. s.Require().Equal("value1", Get(o, "key1", ""))
  84. s.Require().False(child.Has("key1"))
  85. s.Require().Equal(200, Get(child, "key2", 0))
  86. s.Require().False(grandChild.Has("key1"))
  87. s.Require().Equal(300, Get(grandChild, "key2", 0))
  88. }
  89. func (s *OptionsTestSuite) TestCopyValue() {
  90. o := New()
  91. o.Set("key1", 100)
  92. o.Set("key2", 200)
  93. o.Set("key3", 200)
  94. // Existing to existing
  95. o.CopyValue("key1", "key2")
  96. s.Require().Equal(100, Get(o, "key2", 0))
  97. // Existing to new
  98. o.CopyValue("key1", "key4")
  99. s.Require().Equal(100, Get(o, "key4", 0))
  100. // Non-existing to new
  101. o.CopyValue("non_existing_key", "key5")
  102. s.Require().False(o.Has("key5"))
  103. // Non-existing to existing
  104. o.CopyValue("another_non_existing_key", "key3")
  105. s.Require().Equal(200, Get(o, "key3", 0))
  106. }
  107. func (s *OptionsTestSuite) TestGetInt() {
  108. o := New()
  109. o.Set("int", 42)
  110. o.Set("int32", int32(32))
  111. o.Set("int16", int16(16))
  112. o.Set("int8", int8(8))
  113. o.Set("float", 3.14)
  114. o.Set("string", "not_an_int")
  115. // Integer types
  116. s.Require().Equal(42, o.GetInt("int", 0))
  117. s.Require().Equal(32, o.GetInt("int32", 0))
  118. s.Require().Equal(16, o.GetInt("int16", 0))
  119. s.Require().Equal(8, o.GetInt("int8", 0))
  120. // Non-existing key
  121. s.Require().Equal(100, o.GetInt("non_existing_key", 100))
  122. // Type mismatch
  123. s.Require().Panics(func() {
  124. o.GetInt("float", 0)
  125. })
  126. s.Require().Panics(func() {
  127. o.GetInt("string", 0)
  128. })
  129. }
  130. func (s *OptionsTestSuite) TestGetFloat() {
  131. o := New()
  132. o.Set("float64", 3.14)
  133. o.Set("float32", float32(2.71))
  134. o.Set("int", 42)
  135. o.Set("int16", int16(16))
  136. o.Set("string", "not_a_float")
  137. // Float types
  138. s.Require().InDelta(3.14, o.GetFloat("float64", 0.0), 0.000001)
  139. s.Require().InDelta(2.71, o.GetFloat("float32", 0.0), 0.000001)
  140. // Integer types
  141. s.Require().InDelta(42.0, o.GetFloat("int", 0.0), 0.000001)
  142. s.Require().InDelta(16.0, o.GetFloat("int16", 0.0), 0.000001)
  143. // Non-existing key
  144. s.Require().InDelta(1.618, o.GetFloat("non_existing_key", 1.618), 0.000001)
  145. // Type mismatch
  146. s.Require().Panics(func() {
  147. o.GetFloat("string", 0.0)
  148. })
  149. }
  150. func testOptions() *Options {
  151. o := New()
  152. o.Set("string_key", "string_value")
  153. o.Set("int_key", 42)
  154. o.Set("float_key", 3.14)
  155. o.Set("bool_key", true)
  156. o.Set("group1.key1", "value1")
  157. o.Set("group1.key2", 100)
  158. o.Set("group2.key1", false)
  159. o.Set("group2.key2", 2.71)
  160. o.Set("group2.subgroup.key", "subvalue")
  161. o.Set("group2.subgroup.num", 256)
  162. return o
  163. }
  164. func testNestedOptions() *Options {
  165. o := testOptions()
  166. child := o.AddChild()
  167. child.Set("string_key", "child_string_value")
  168. child.Set("int_key", 84)
  169. child.Set("child_only_key", "only_in_child")
  170. grandChild := child.AddChild()
  171. grandChild.Set("string_key", "grandchild_string_value")
  172. grandChild.Set("int_key", 168)
  173. grandChild.Set("grandchild_only_key", "only_in_grandchild")
  174. return o
  175. }
  176. func (s *OptionsTestSuite) TestDepth() {
  177. o := testNestedOptions()
  178. s.Require().Equal(0, o.Depth())
  179. s.Require().Equal(1, o.Child().Depth())
  180. s.Require().Equal(2, o.Child().Child().Depth())
  181. }
  182. func (s *OptionsTestSuite) TestMap() {
  183. s.Run("WithoutChildren", func() {
  184. o := testOptions()
  185. expected := map[string]any{
  186. "string_key": "string_value",
  187. "int_key": 42,
  188. "float_key": 3.14,
  189. "bool_key": true,
  190. "group1.key1": "value1",
  191. "group1.key2": 100,
  192. "group2.key1": false,
  193. "group2.key2": 2.71,
  194. "group2.subgroup.key": "subvalue",
  195. "group2.subgroup.num": 256,
  196. }
  197. s.Require().Equal(expected, o.Map())
  198. })
  199. s.Run("WithChildren", func() {
  200. o := testNestedOptions()
  201. expected := map[string]any{
  202. "0.string_key": "string_value",
  203. "0.int_key": 42,
  204. "0.float_key": 3.14,
  205. "0.bool_key": true,
  206. "0.group1.key1": "value1",
  207. "0.group1.key2": 100,
  208. "0.group2.key1": false,
  209. "0.group2.key2": 2.71,
  210. "0.group2.subgroup.key": "subvalue",
  211. "0.group2.subgroup.num": 256,
  212. "1.string_key": "child_string_value",
  213. "1.int_key": 84,
  214. "1.child_only_key": "only_in_child",
  215. "2.string_key": "grandchild_string_value",
  216. "2.int_key": 168,
  217. "2.grandchild_only_key": "only_in_grandchild",
  218. }
  219. s.Require().Equal(expected, o.Map())
  220. })
  221. }
  222. func (s *OptionsTestSuite) TestNestedMap() {
  223. s.Run("WithoutChildren", func() {
  224. o := testOptions()
  225. expected := map[string]any{
  226. "string_key": "string_value",
  227. "int_key": 42,
  228. "float_key": 3.14,
  229. "bool_key": true,
  230. "group1": map[string]any{
  231. "key1": "value1",
  232. "key2": 100,
  233. },
  234. "group2": map[string]any{
  235. "key1": false,
  236. "key2": 2.71,
  237. "subgroup": map[string]any{
  238. "key": "subvalue",
  239. "num": 256,
  240. },
  241. },
  242. }
  243. s.Require().Equal(expected, o.NestedMap())
  244. })
  245. s.Run("WithChildren", func() {
  246. o := testNestedOptions()
  247. expected := map[string]any{
  248. "0": map[string]any{
  249. "string_key": "string_value",
  250. "int_key": 42,
  251. "float_key": 3.14,
  252. "bool_key": true,
  253. "group1": map[string]any{
  254. "key1": "value1",
  255. "key2": 100,
  256. },
  257. "group2": map[string]any{
  258. "key1": false,
  259. "key2": 2.71,
  260. "subgroup": map[string]any{
  261. "key": "subvalue",
  262. "num": 256,
  263. },
  264. },
  265. },
  266. "1": map[string]any{
  267. "string_key": "child_string_value",
  268. "int_key": 84,
  269. "child_only_key": "only_in_child",
  270. },
  271. "2": map[string]any{
  272. "string_key": "grandchild_string_value",
  273. "int_key": 168,
  274. "grandchild_only_key": "only_in_grandchild",
  275. },
  276. }
  277. s.Require().Equal(expected, o.NestedMap())
  278. })
  279. }
  280. func TestOptions(t *testing.T) {
  281. suite.Run(t, new(OptionsTestSuite))
  282. }
  283. func BenchmarkLogValue(b *testing.B) {
  284. o := testNestedOptions()
  285. b.ResetTimer()
  286. for i := 0; i < b.N; i++ {
  287. _ = o.LogValue()
  288. }
  289. }
  290. func BenchmarkNestedMap(b *testing.B) {
  291. o := testNestedOptions()
  292. b.ResetTimer()
  293. for i := 0; i < b.N; i++ {
  294. _ = o.NestedMap()
  295. }
  296. }
  297. func BenchmarkMap(b *testing.B) {
  298. o := testNestedOptions()
  299. b.ResetTimer()
  300. for i := 0; i < b.N; i++ {
  301. _ = o.Map()
  302. }
  303. }