arithmetic_functions_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. package engine
  2. import (
  3. "testing"
  4. "github.com/seaweedfs/seaweedfs/weed/pb/schema_pb"
  5. )
  6. func TestArithmeticOperations(t *testing.T) {
  7. engine := NewTestSQLEngine()
  8. tests := []struct {
  9. name string
  10. left *schema_pb.Value
  11. right *schema_pb.Value
  12. operator ArithmeticOperator
  13. expected *schema_pb.Value
  14. expectErr bool
  15. }{
  16. // Addition tests
  17. {
  18. name: "Add two integers",
  19. left: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 10}},
  20. right: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 5}},
  21. operator: OpAdd,
  22. expected: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 15}},
  23. expectErr: false,
  24. },
  25. {
  26. name: "Add integer and float",
  27. left: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 10}},
  28. right: &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: 5.5}},
  29. operator: OpAdd,
  30. expected: &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: 15.5}},
  31. expectErr: false,
  32. },
  33. // Subtraction tests
  34. {
  35. name: "Subtract two integers",
  36. left: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 10}},
  37. right: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 3}},
  38. operator: OpSub,
  39. expected: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 7}},
  40. expectErr: false,
  41. },
  42. // Multiplication tests
  43. {
  44. name: "Multiply two integers",
  45. left: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 6}},
  46. right: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 7}},
  47. operator: OpMul,
  48. expected: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 42}},
  49. expectErr: false,
  50. },
  51. {
  52. name: "Multiply with float",
  53. left: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 5}},
  54. right: &schema_pb.Value{Kind: &schema_pb.Value_FloatValue{FloatValue: 2.5}},
  55. operator: OpMul,
  56. expected: &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: 12.5}},
  57. expectErr: false,
  58. },
  59. // Division tests
  60. {
  61. name: "Divide two integers",
  62. left: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 20}},
  63. right: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 4}},
  64. operator: OpDiv,
  65. expected: &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: 5.0}},
  66. expectErr: false,
  67. },
  68. {
  69. name: "Division by zero",
  70. left: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 10}},
  71. right: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 0}},
  72. operator: OpDiv,
  73. expected: nil,
  74. expectErr: true,
  75. },
  76. // Modulo tests
  77. {
  78. name: "Modulo operation",
  79. left: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 17}},
  80. right: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 5}},
  81. operator: OpMod,
  82. expected: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 2}},
  83. expectErr: false,
  84. },
  85. {
  86. name: "Modulo by zero",
  87. left: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 10}},
  88. right: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 0}},
  89. operator: OpMod,
  90. expected: nil,
  91. expectErr: true,
  92. },
  93. // String conversion tests
  94. {
  95. name: "Add string number to integer",
  96. left: &schema_pb.Value{Kind: &schema_pb.Value_StringValue{StringValue: "15"}},
  97. right: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 5}},
  98. operator: OpAdd,
  99. expected: &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: 20.0}},
  100. expectErr: false,
  101. },
  102. {
  103. name: "Invalid string conversion",
  104. left: &schema_pb.Value{Kind: &schema_pb.Value_StringValue{StringValue: "not_a_number"}},
  105. right: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 5}},
  106. operator: OpAdd,
  107. expected: nil,
  108. expectErr: true,
  109. },
  110. // Boolean conversion tests
  111. {
  112. name: "Add boolean to integer",
  113. left: &schema_pb.Value{Kind: &schema_pb.Value_BoolValue{BoolValue: true}},
  114. right: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 5}},
  115. operator: OpAdd,
  116. expected: &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: 6.0}},
  117. expectErr: false,
  118. },
  119. // Null value tests
  120. {
  121. name: "Add with null left operand",
  122. left: nil,
  123. right: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 5}},
  124. operator: OpAdd,
  125. expected: nil,
  126. expectErr: true,
  127. },
  128. {
  129. name: "Add with null right operand",
  130. left: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 5}},
  131. right: nil,
  132. operator: OpAdd,
  133. expected: nil,
  134. expectErr: true,
  135. },
  136. }
  137. for _, tt := range tests {
  138. t.Run(tt.name, func(t *testing.T) {
  139. result, err := engine.EvaluateArithmeticExpression(tt.left, tt.right, tt.operator)
  140. if tt.expectErr {
  141. if err == nil {
  142. t.Errorf("Expected error but got none")
  143. }
  144. return
  145. }
  146. if err != nil {
  147. t.Errorf("Unexpected error: %v", err)
  148. return
  149. }
  150. if !valuesEqual(result, tt.expected) {
  151. t.Errorf("Expected %v, got %v", tt.expected, result)
  152. }
  153. })
  154. }
  155. }
  156. func TestIndividualArithmeticFunctions(t *testing.T) {
  157. engine := NewTestSQLEngine()
  158. left := &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 10}}
  159. right := &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 3}}
  160. // Test Add function
  161. result, err := engine.Add(left, right)
  162. if err != nil {
  163. t.Errorf("Add function failed: %v", err)
  164. }
  165. expected := &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 13}}
  166. if !valuesEqual(result, expected) {
  167. t.Errorf("Add: Expected %v, got %v", expected, result)
  168. }
  169. // Test Subtract function
  170. result, err = engine.Subtract(left, right)
  171. if err != nil {
  172. t.Errorf("Subtract function failed: %v", err)
  173. }
  174. expected = &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 7}}
  175. if !valuesEqual(result, expected) {
  176. t.Errorf("Subtract: Expected %v, got %v", expected, result)
  177. }
  178. // Test Multiply function
  179. result, err = engine.Multiply(left, right)
  180. if err != nil {
  181. t.Errorf("Multiply function failed: %v", err)
  182. }
  183. expected = &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 30}}
  184. if !valuesEqual(result, expected) {
  185. t.Errorf("Multiply: Expected %v, got %v", expected, result)
  186. }
  187. // Test Divide function
  188. result, err = engine.Divide(left, right)
  189. if err != nil {
  190. t.Errorf("Divide function failed: %v", err)
  191. }
  192. expected = &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: 10.0 / 3.0}}
  193. if !valuesEqual(result, expected) {
  194. t.Errorf("Divide: Expected %v, got %v", expected, result)
  195. }
  196. // Test Modulo function
  197. result, err = engine.Modulo(left, right)
  198. if err != nil {
  199. t.Errorf("Modulo function failed: %v", err)
  200. }
  201. expected = &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 1}}
  202. if !valuesEqual(result, expected) {
  203. t.Errorf("Modulo: Expected %v, got %v", expected, result)
  204. }
  205. }
  206. func TestMathematicalFunctions(t *testing.T) {
  207. engine := NewTestSQLEngine()
  208. t.Run("ROUND function tests", func(t *testing.T) {
  209. tests := []struct {
  210. name string
  211. value *schema_pb.Value
  212. precision *schema_pb.Value
  213. expected *schema_pb.Value
  214. expectErr bool
  215. }{
  216. {
  217. name: "Round float to integer",
  218. value: &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: 3.7}},
  219. precision: nil,
  220. expected: &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: 4.0}},
  221. expectErr: false,
  222. },
  223. {
  224. name: "Round integer stays integer",
  225. value: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 5}},
  226. precision: nil,
  227. expected: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 5}},
  228. expectErr: false,
  229. },
  230. {
  231. name: "Round with precision 2",
  232. value: &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: 3.14159}},
  233. precision: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 2}},
  234. expected: &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: 3.14}},
  235. expectErr: false,
  236. },
  237. {
  238. name: "Round negative number",
  239. value: &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: -3.7}},
  240. precision: nil,
  241. expected: &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: -4.0}},
  242. expectErr: false,
  243. },
  244. {
  245. name: "Round null value",
  246. value: nil,
  247. precision: nil,
  248. expected: nil,
  249. expectErr: true,
  250. },
  251. }
  252. for _, tt := range tests {
  253. t.Run(tt.name, func(t *testing.T) {
  254. var result *schema_pb.Value
  255. var err error
  256. if tt.precision != nil {
  257. result, err = engine.Round(tt.value, tt.precision)
  258. } else {
  259. result, err = engine.Round(tt.value)
  260. }
  261. if tt.expectErr {
  262. if err == nil {
  263. t.Errorf("Expected error but got none")
  264. }
  265. return
  266. }
  267. if err != nil {
  268. t.Errorf("Unexpected error: %v", err)
  269. return
  270. }
  271. if !valuesEqual(result, tt.expected) {
  272. t.Errorf("Expected %v, got %v", tt.expected, result)
  273. }
  274. })
  275. }
  276. })
  277. t.Run("CEIL function tests", func(t *testing.T) {
  278. tests := []struct {
  279. name string
  280. value *schema_pb.Value
  281. expected *schema_pb.Value
  282. expectErr bool
  283. }{
  284. {
  285. name: "Ceil positive decimal",
  286. value: &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: 3.2}},
  287. expected: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 4}},
  288. expectErr: false,
  289. },
  290. {
  291. name: "Ceil negative decimal",
  292. value: &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: -3.2}},
  293. expected: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: -3}},
  294. expectErr: false,
  295. },
  296. {
  297. name: "Ceil integer",
  298. value: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 5}},
  299. expected: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 5}},
  300. expectErr: false,
  301. },
  302. {
  303. name: "Ceil null value",
  304. value: nil,
  305. expected: nil,
  306. expectErr: true,
  307. },
  308. }
  309. for _, tt := range tests {
  310. t.Run(tt.name, func(t *testing.T) {
  311. result, err := engine.Ceil(tt.value)
  312. if tt.expectErr {
  313. if err == nil {
  314. t.Errorf("Expected error but got none")
  315. }
  316. return
  317. }
  318. if err != nil {
  319. t.Errorf("Unexpected error: %v", err)
  320. return
  321. }
  322. if !valuesEqual(result, tt.expected) {
  323. t.Errorf("Expected %v, got %v", tt.expected, result)
  324. }
  325. })
  326. }
  327. })
  328. t.Run("FLOOR function tests", func(t *testing.T) {
  329. tests := []struct {
  330. name string
  331. value *schema_pb.Value
  332. expected *schema_pb.Value
  333. expectErr bool
  334. }{
  335. {
  336. name: "Floor positive decimal",
  337. value: &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: 3.8}},
  338. expected: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 3}},
  339. expectErr: false,
  340. },
  341. {
  342. name: "Floor negative decimal",
  343. value: &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: -3.2}},
  344. expected: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: -4}},
  345. expectErr: false,
  346. },
  347. {
  348. name: "Floor integer",
  349. value: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 5}},
  350. expected: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 5}},
  351. expectErr: false,
  352. },
  353. {
  354. name: "Floor null value",
  355. value: nil,
  356. expected: nil,
  357. expectErr: true,
  358. },
  359. }
  360. for _, tt := range tests {
  361. t.Run(tt.name, func(t *testing.T) {
  362. result, err := engine.Floor(tt.value)
  363. if tt.expectErr {
  364. if err == nil {
  365. t.Errorf("Expected error but got none")
  366. }
  367. return
  368. }
  369. if err != nil {
  370. t.Errorf("Unexpected error: %v", err)
  371. return
  372. }
  373. if !valuesEqual(result, tt.expected) {
  374. t.Errorf("Expected %v, got %v", tt.expected, result)
  375. }
  376. })
  377. }
  378. })
  379. t.Run("ABS function tests", func(t *testing.T) {
  380. tests := []struct {
  381. name string
  382. value *schema_pb.Value
  383. expected *schema_pb.Value
  384. expectErr bool
  385. }{
  386. {
  387. name: "Abs positive integer",
  388. value: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 5}},
  389. expected: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 5}},
  390. expectErr: false,
  391. },
  392. {
  393. name: "Abs negative integer",
  394. value: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: -5}},
  395. expected: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 5}},
  396. expectErr: false,
  397. },
  398. {
  399. name: "Abs positive double",
  400. value: &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: 3.14}},
  401. expected: &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: 3.14}},
  402. expectErr: false,
  403. },
  404. {
  405. name: "Abs negative double",
  406. value: &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: -3.14}},
  407. expected: &schema_pb.Value{Kind: &schema_pb.Value_DoubleValue{DoubleValue: 3.14}},
  408. expectErr: false,
  409. },
  410. {
  411. name: "Abs positive float",
  412. value: &schema_pb.Value{Kind: &schema_pb.Value_FloatValue{FloatValue: 2.5}},
  413. expected: &schema_pb.Value{Kind: &schema_pb.Value_FloatValue{FloatValue: 2.5}},
  414. expectErr: false,
  415. },
  416. {
  417. name: "Abs negative float",
  418. value: &schema_pb.Value{Kind: &schema_pb.Value_FloatValue{FloatValue: -2.5}},
  419. expected: &schema_pb.Value{Kind: &schema_pb.Value_FloatValue{FloatValue: 2.5}},
  420. expectErr: false,
  421. },
  422. {
  423. name: "Abs zero",
  424. value: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 0}},
  425. expected: &schema_pb.Value{Kind: &schema_pb.Value_Int64Value{Int64Value: 0}},
  426. expectErr: false,
  427. },
  428. {
  429. name: "Abs null value",
  430. value: nil,
  431. expected: nil,
  432. expectErr: true,
  433. },
  434. }
  435. for _, tt := range tests {
  436. t.Run(tt.name, func(t *testing.T) {
  437. result, err := engine.Abs(tt.value)
  438. if tt.expectErr {
  439. if err == nil {
  440. t.Errorf("Expected error but got none")
  441. }
  442. return
  443. }
  444. if err != nil {
  445. t.Errorf("Unexpected error: %v", err)
  446. return
  447. }
  448. if !valuesEqual(result, tt.expected) {
  449. t.Errorf("Expected %v, got %v", tt.expected, result)
  450. }
  451. })
  452. }
  453. })
  454. }
  455. // Helper function to compare two schema_pb.Value objects
  456. func valuesEqual(v1, v2 *schema_pb.Value) bool {
  457. if v1 == nil && v2 == nil {
  458. return true
  459. }
  460. if v1 == nil || v2 == nil {
  461. return false
  462. }
  463. switch v1Kind := v1.Kind.(type) {
  464. case *schema_pb.Value_Int32Value:
  465. if v2Kind, ok := v2.Kind.(*schema_pb.Value_Int32Value); ok {
  466. return v1Kind.Int32Value == v2Kind.Int32Value
  467. }
  468. case *schema_pb.Value_Int64Value:
  469. if v2Kind, ok := v2.Kind.(*schema_pb.Value_Int64Value); ok {
  470. return v1Kind.Int64Value == v2Kind.Int64Value
  471. }
  472. case *schema_pb.Value_FloatValue:
  473. if v2Kind, ok := v2.Kind.(*schema_pb.Value_FloatValue); ok {
  474. return v1Kind.FloatValue == v2Kind.FloatValue
  475. }
  476. case *schema_pb.Value_DoubleValue:
  477. if v2Kind, ok := v2.Kind.(*schema_pb.Value_DoubleValue); ok {
  478. return v1Kind.DoubleValue == v2Kind.DoubleValue
  479. }
  480. case *schema_pb.Value_StringValue:
  481. if v2Kind, ok := v2.Kind.(*schema_pb.Value_StringValue); ok {
  482. return v1Kind.StringValue == v2Kind.StringValue
  483. }
  484. case *schema_pb.Value_BoolValue:
  485. if v2Kind, ok := v2.Kind.(*schema_pb.Value_BoolValue); ok {
  486. return v1Kind.BoolValue == v2Kind.BoolValue
  487. }
  488. }
  489. return false
  490. }