You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

serder_test.go 8.0 kB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. package serder
  2. import (
  3. "fmt"
  4. "reflect"
  5. "testing"
  6. . "github.com/smartystreets/goconvey/convey"
  7. "gitlink.org.cn/cloudream/common/pkgs/types"
  8. myreflect "gitlink.org.cn/cloudream/common/utils/reflect"
  9. )
  10. type FromAnyString struct {
  11. Str string
  12. }
  13. func (a *FromAnyString) FromAny(val any) (bool, error) {
  14. if str, ok := val.(string); ok {
  15. a.Str = "@" + str
  16. return true, nil
  17. }
  18. return false, nil
  19. }
  20. type ToAnyString struct {
  21. Str string
  22. }
  23. func (a *ToAnyString) ToAny(typ reflect.Type) (val any, ok bool, err error) {
  24. if typ == myreflect.TypeOf[map[string]any]() {
  25. return map[string]any{
  26. "str": "@" + a.Str,
  27. }, true, nil
  28. }
  29. return nil, false, nil
  30. }
  31. type FromAnySt struct {
  32. Value string
  33. }
  34. func (a *FromAnySt) FromAny(val any) (bool, error) {
  35. if st, ok := val.(ToAnySt); ok {
  36. a.Value = "From:" + st.Value
  37. return true, nil
  38. }
  39. return false, nil
  40. }
  41. type ToAnySt struct {
  42. Value string
  43. }
  44. func (a *ToAnySt) ToAny(typ reflect.Type) (val any, ok bool, err error) {
  45. if typ == myreflect.TypeOf[FromAnySt]() {
  46. return FromAnySt{
  47. Value: "To:" + a.Value,
  48. }, true, nil
  49. }
  50. return nil, false, nil
  51. }
  52. type DirToAnySt struct {
  53. Value string
  54. }
  55. func (a DirToAnySt) ToAny(typ reflect.Type) (val any, ok bool, err error) {
  56. if typ == myreflect.TypeOf[FromAnySt]() {
  57. return FromAnySt{
  58. Value: "DirTo:" + a.Value,
  59. }, true, nil
  60. }
  61. return nil, false, nil
  62. }
  63. func Test_AnyToAny(t *testing.T) {
  64. Convey("包含用字符串保存的int数据", t, func() {
  65. type Struct struct {
  66. A string `json:"a"`
  67. B int `json:"b"`
  68. C int64 `json:"c,string"`
  69. }
  70. mp := map[string]any{
  71. "a": "a",
  72. "b": 1,
  73. "c": "1234",
  74. }
  75. var st Struct
  76. err := AnyToAny(mp, &st)
  77. So(err, ShouldBeNil)
  78. So(st.A, ShouldEqual, "a")
  79. So(st.B, ShouldEqual, 1)
  80. So(st.C, ShouldEqual, 1234)
  81. })
  82. Convey("只有FromAny", t, func() {
  83. type Struct struct {
  84. Special FromAnyString `json:"str"`
  85. }
  86. mp := map[string]any{
  87. "str": "test",
  88. }
  89. var ret Struct
  90. err := AnyToAny(mp, &ret)
  91. So(err, ShouldBeNil)
  92. So(ret.Special.Str, ShouldEqual, "@test")
  93. })
  94. Convey("字段类型直接实现了FromAny", t, func() {
  95. type Struct struct {
  96. Special *FromAnyString `json:"str"`
  97. }
  98. mp := map[string]any{
  99. "str": "test",
  100. }
  101. var ret Struct
  102. err := AnyToAny(mp, &ret)
  103. So(err, ShouldBeNil)
  104. So(ret.Special.Str, ShouldEqual, "@test")
  105. })
  106. Convey("只有ToAny", t, func() {
  107. st := struct {
  108. Special ToAnyString `json:"str"`
  109. }{
  110. Special: ToAnyString{
  111. Str: "test",
  112. },
  113. }
  114. ret := map[string]any{}
  115. err := AnyToAny(st, &ret)
  116. So(err, ShouldBeNil)
  117. So(ret["str"].(map[string]any)["str"], ShouldEqual, "@test")
  118. })
  119. Convey("优先使用ToAny", t, func() {
  120. st1 := ToAnySt{
  121. Value: "test",
  122. }
  123. st2 := FromAnySt{}
  124. err := AnyToAny(st1, &st2)
  125. So(err, ShouldBeNil)
  126. So(st2.Value, ShouldEqual, "To:test")
  127. })
  128. Convey("使用Convertor", t, func() {
  129. type Struct1 struct {
  130. Value string
  131. }
  132. type Struct2 struct {
  133. Value string
  134. }
  135. st1 := Struct1{
  136. Value: "test",
  137. }
  138. st2 := Struct2{}
  139. err := AnyToAny(st1, &st2, AnyToAnyOption{
  140. Converters: []Converter{func(from reflect.Value, to reflect.Value) (interface{}, error) {
  141. if from.Type() == myreflect.TypeOf[Struct1]() && to.Type() == myreflect.TypeOf[Struct2]() {
  142. s1 := from.Interface().(Struct1)
  143. return Struct2{
  144. Value: "@" + s1.Value,
  145. }, nil
  146. }
  147. return nil, fmt.Errorf("should not arrive here!")
  148. }},
  149. })
  150. So(err, ShouldBeNil)
  151. So(st2.Value, ShouldEqual, "@test")
  152. })
  153. }
  154. func Test_MapToObject(t *testing.T) {
  155. type Base struct {
  156. Int int
  157. Bool bool
  158. String string
  159. Float float32
  160. }
  161. type ArraryStruct struct {
  162. IntArr []int
  163. StArr []Base
  164. ArrArr [][]int
  165. Nil []Base
  166. }
  167. type MapStruct struct {
  168. StrMap map[string]string
  169. StMap map[string]Base
  170. MapMap map[string]map[string]string
  171. Nil map[string]Base
  172. }
  173. type Top struct {
  174. ArrSt ArraryStruct
  175. MapSt *MapStruct
  176. BaseIf any
  177. NilPtr *Base
  178. }
  179. Convey("结构体递归转换成map[string]any", t, func() {
  180. val := Top{
  181. ArrSt: ArraryStruct{
  182. IntArr: []int{1, 2, 3},
  183. StArr: []Base{
  184. {
  185. Int: 1,
  186. Bool: true,
  187. String: "test",
  188. Float: 1,
  189. },
  190. {
  191. Int: 2,
  192. Bool: false,
  193. String: "test2",
  194. Float: 2,
  195. },
  196. },
  197. ArrArr: [][]int{
  198. {1, 2, 3},
  199. {},
  200. nil,
  201. },
  202. Nil: nil,
  203. },
  204. MapSt: &MapStruct{
  205. StrMap: map[string]string{
  206. "a": "1",
  207. "b": "2",
  208. },
  209. StMap: map[string]Base{
  210. "a": {
  211. Int: 1,
  212. Bool: true,
  213. String: "test",
  214. Float: 1,
  215. },
  216. "b": {
  217. Int: 2,
  218. Bool: false,
  219. String: "test2",
  220. Float: 2,
  221. },
  222. },
  223. MapMap: map[string]map[string]string{
  224. "a": {
  225. "a": "1",
  226. "b": "2",
  227. },
  228. "b": nil,
  229. },
  230. Nil: nil,
  231. },
  232. BaseIf: Base{
  233. Int: 1,
  234. Bool: true,
  235. String: "test",
  236. Float: 1,
  237. },
  238. NilPtr: nil,
  239. }
  240. retMp, err := ObjectToMap(val)
  241. So(err, ShouldBeNil)
  242. exceptMap := map[string]any{
  243. "ArrSt": map[string]any{
  244. "IntArr": []any{1, 2, 3},
  245. "StArr": []any{
  246. map[string]any{
  247. "Int": 1,
  248. "Bool": true,
  249. "String": "test",
  250. "Float": 1,
  251. },
  252. map[string]any{
  253. "Int": 2,
  254. "Bool": false,
  255. "String": "test2",
  256. "Float": 2,
  257. },
  258. },
  259. "ArrArr": []any{
  260. []any{1, 2, 3},
  261. []any{},
  262. []int(nil),
  263. },
  264. "Nil": []Base(nil),
  265. },
  266. "MapSt": map[string]any{
  267. "StrMap": map[string]any{
  268. "a": "1",
  269. "b": "2",
  270. },
  271. "StMap": map[string]any{
  272. "a": map[string]any{
  273. "Int": 1,
  274. "Bool": true,
  275. "String": "test",
  276. "Float": 1,
  277. },
  278. "b": map[string]any{
  279. "Int": 2,
  280. "Bool": false,
  281. "String": "test2",
  282. "Float": 2,
  283. },
  284. },
  285. "MapMap": map[string]any{
  286. "a": map[string]any{
  287. "a": "1",
  288. "b": "2",
  289. },
  290. "b": map[string]string(nil),
  291. },
  292. "Nil": map[string]Base(nil),
  293. },
  294. "BaseIf": map[string]any{
  295. "Int": 1,
  296. "Bool": true,
  297. "String": "test",
  298. "Float": 1,
  299. },
  300. "NilPtr": (*Base)(nil),
  301. }
  302. mpRetJson, err := ObjectToJSON(retMp)
  303. So(err, ShouldBeNil)
  304. exceptMapJson, err := ObjectToJSON(exceptMap)
  305. So(err, ShouldBeNil)
  306. So(string(mpRetJson), ShouldEqualJSON, string(exceptMapJson))
  307. })
  308. Convey("包含UnionType", t, func() {
  309. type UnionType interface{}
  310. type EleType1 struct {
  311. Type string `json:"type" union:"1"`
  312. Value1 string `json:"value1"`
  313. }
  314. type EleType2 struct {
  315. Type string `json:"type" union:"2"`
  316. Value2 int `json:"value2"`
  317. }
  318. type St struct {
  319. Us []UnionType `json:"us"`
  320. }
  321. mp := map[string]any{
  322. "us": []map[string]any{
  323. {
  324. "type": "1",
  325. "value1": "1",
  326. },
  327. {
  328. "type": "2",
  329. "value2": 2,
  330. },
  331. },
  332. }
  333. var ret St
  334. err := MapToObject(mp, &ret, MapToObjectOption{
  335. UnionTypes: []TaggedUnionType{
  336. NewTaggedTypeUnion(types.NewTypeUnion[UnionType](
  337. myreflect.TypeOf[EleType1](),
  338. myreflect.TypeOf[EleType2](),
  339. ),
  340. "Type",
  341. "type",
  342. ),
  343. },
  344. })
  345. So(err, ShouldBeNil)
  346. So(ret.Us, ShouldResemble, []UnionType{
  347. &EleType1{Type: "1", Value1: "1"},
  348. &EleType2{Type: "2", Value2: 2},
  349. })
  350. })
  351. Convey("要转换到的结构体就是一个UnionType", t, func() {
  352. type UnionType interface{}
  353. type EleType1 struct {
  354. Type string `json:"type" union:"1"`
  355. Value1 string `json:"value1"`
  356. }
  357. type EleType2 struct {
  358. Type string `json:"type" union:"2"`
  359. Value2 int `json:"value2"`
  360. }
  361. mp := map[string]any{
  362. "type": "1",
  363. "value1": "1",
  364. }
  365. var ret UnionType
  366. err := MapToObject(mp, &ret, MapToObjectOption{
  367. UnionTypes: []TaggedUnionType{
  368. NewTaggedTypeUnion(types.NewTypeUnion[UnionType](
  369. myreflect.TypeOf[EleType1](),
  370. myreflect.TypeOf[EleType2](),
  371. ),
  372. "Type",
  373. "type",
  374. ),
  375. },
  376. })
  377. So(err, ShouldBeNil)
  378. So(ret, ShouldResemble, &EleType1{Type: "1", Value1: "1"})
  379. })
  380. }