/vendor/github.com/Knetic/govaluate/evaluationFailure_test.go

https://github.com/kevin-hf/education · Go · 484 lines · 381 code · 92 blank · 11 comment · 23 complexity · 9935891dbde16f20cc24a39122ac5e8e MD5 · raw file

  1. package govaluate
  2. /*
  3. Tests to make sure evaluation fails in the expected ways.
  4. */
  5. import (
  6. "errors"
  7. "fmt"
  8. "strings"
  9. "testing"
  10. )
  11. type DebugStruct struct {
  12. x int
  13. }
  14. /*
  15. Represents a test for parsing failures
  16. */
  17. type EvaluationFailureTest struct {
  18. Name string
  19. Input string
  20. Functions map[string]ExpressionFunction
  21. Parameters map[string]interface{}
  22. Expected string
  23. }
  24. const (
  25. INVALID_MODIFIER_TYPES string = "cannot be used with the modifier"
  26. INVALID_COMPARATOR_TYPES = "cannot be used with the comparator"
  27. INVALID_LOGICALOP_TYPES = "cannot be used with the logical operator"
  28. INVALID_TERNARY_TYPES = "cannot be used with the ternary operator"
  29. ABSENT_PARAMETER = "No parameter"
  30. INVALID_REGEX = "Unable to compile regexp pattern"
  31. )
  32. // preset parameter map of types that can be used in an evaluation failure test to check typing.
  33. var EVALUATION_FAILURE_PARAMETERS = map[string]interface{}{
  34. "number": 1,
  35. "string": "foo",
  36. "bool": true,
  37. }
  38. func TestComplexParameter(test *testing.T) {
  39. var expression *EvaluableExpression
  40. var err error
  41. var v interface{}
  42. parameters := map[string]interface{}{
  43. "complex64": complex64(0),
  44. "complex128": complex128(0),
  45. }
  46. expression, _ = NewEvaluableExpression("complex64")
  47. v, err = expression.Evaluate(parameters)
  48. if err != nil {
  49. test.Errorf("Expected no error, but have %s", err)
  50. }
  51. if v.(complex64) != complex64(0) {
  52. test.Errorf("Expected %v == %v", v, complex64(0))
  53. }
  54. expression, _ = NewEvaluableExpression("complex128")
  55. v, err = expression.Evaluate(parameters)
  56. if err != nil {
  57. test.Errorf("Expected no error, but have %s", err)
  58. }
  59. if v.(complex128) != complex128(0) {
  60. test.Errorf("Expected %v == %v", v, complex128(0))
  61. }
  62. }
  63. func TestStructParameter(t *testing.T) {
  64. expected := DebugStruct{}
  65. expression, _ := NewEvaluableExpression("foo")
  66. parameters := map[string]interface{}{"foo": expected}
  67. v, err := expression.Evaluate(parameters)
  68. if err != nil {
  69. t.Errorf("Expected no error, but have %s", err)
  70. } else if v.(DebugStruct) != expected {
  71. t.Errorf("Values mismatch: %v != %v", expected, v)
  72. }
  73. }
  74. func TestNilParameterUsage(test *testing.T) {
  75. evaluationTests := []EvaluationFailureTest{
  76. EvaluationFailureTest{
  77. Name: "Absent parameter used",
  78. Input: "foo > 1",
  79. Expected: ABSENT_PARAMETER,
  80. },
  81. }
  82. runEvaluationFailureTests(evaluationTests, test)
  83. }
  84. func TestModifierTyping(test *testing.T) {
  85. evaluationTests := []EvaluationFailureTest{
  86. EvaluationFailureTest{
  87. Name: "PLUS literal number to literal bool",
  88. Input: "1 + true",
  89. Expected: INVALID_MODIFIER_TYPES,
  90. },
  91. EvaluationFailureTest{
  92. Name: "PLUS number to bool",
  93. Input: "number + bool",
  94. Expected: INVALID_MODIFIER_TYPES,
  95. },
  96. EvaluationFailureTest{
  97. Name: "MINUS number to bool",
  98. Input: "number - bool",
  99. Expected: INVALID_MODIFIER_TYPES,
  100. },
  101. EvaluationFailureTest{
  102. Name: "MINUS number to bool",
  103. Input: "number - bool",
  104. Expected: INVALID_MODIFIER_TYPES,
  105. },
  106. EvaluationFailureTest{
  107. Name: "MULTIPLY number to bool",
  108. Input: "number * bool",
  109. Expected: INVALID_MODIFIER_TYPES,
  110. },
  111. EvaluationFailureTest{
  112. Name: "DIVIDE number to bool",
  113. Input: "number / bool",
  114. Expected: INVALID_MODIFIER_TYPES,
  115. },
  116. EvaluationFailureTest{
  117. Name: "EXPONENT number to bool",
  118. Input: "number ** bool",
  119. Expected: INVALID_MODIFIER_TYPES,
  120. },
  121. EvaluationFailureTest{
  122. Name: "MODULUS number to bool",
  123. Input: "number % bool",
  124. Expected: INVALID_MODIFIER_TYPES,
  125. },
  126. EvaluationFailureTest{
  127. Name: "XOR number to bool",
  128. Input: "number % bool",
  129. Expected: INVALID_MODIFIER_TYPES,
  130. },
  131. EvaluationFailureTest{
  132. Name: "BITWISE_OR number to bool",
  133. Input: "number | bool",
  134. Expected: INVALID_MODIFIER_TYPES,
  135. },
  136. EvaluationFailureTest{
  137. Name: "BITWISE_AND number to bool",
  138. Input: "number & bool",
  139. Expected: INVALID_MODIFIER_TYPES,
  140. },
  141. EvaluationFailureTest{
  142. Name: "BITWISE_XOR number to bool",
  143. Input: "number ^ bool",
  144. Expected: INVALID_MODIFIER_TYPES,
  145. },
  146. EvaluationFailureTest{
  147. Name: "BITWISE_LSHIFT number to bool",
  148. Input: "number << bool",
  149. Expected: INVALID_MODIFIER_TYPES,
  150. },
  151. EvaluationFailureTest{
  152. Name: "BITWISE_RSHIFT number to bool",
  153. Input: "number >> bool",
  154. Expected: INVALID_MODIFIER_TYPES,
  155. },
  156. }
  157. runEvaluationFailureTests(evaluationTests, test)
  158. }
  159. func TestLogicalOperatorTyping(test *testing.T) {
  160. evaluationTests := []EvaluationFailureTest{
  161. EvaluationFailureTest{
  162. Name: "AND number to number",
  163. Input: "number && number",
  164. Expected: INVALID_LOGICALOP_TYPES,
  165. },
  166. EvaluationFailureTest{
  167. Name: "OR number to number",
  168. Input: "number || number",
  169. Expected: INVALID_LOGICALOP_TYPES,
  170. },
  171. EvaluationFailureTest{
  172. Name: "AND string to string",
  173. Input: "string && string",
  174. Expected: INVALID_LOGICALOP_TYPES,
  175. },
  176. EvaluationFailureTest{
  177. Name: "OR string to string",
  178. Input: "string || string",
  179. Expected: INVALID_LOGICALOP_TYPES,
  180. },
  181. EvaluationFailureTest{
  182. Name: "AND number to string",
  183. Input: "number && string",
  184. Expected: INVALID_LOGICALOP_TYPES,
  185. },
  186. EvaluationFailureTest{
  187. Name: "OR number to string",
  188. Input: "number || string",
  189. Expected: INVALID_LOGICALOP_TYPES,
  190. },
  191. EvaluationFailureTest{
  192. Name: "AND bool to string",
  193. Input: "bool && string",
  194. Expected: INVALID_LOGICALOP_TYPES,
  195. },
  196. EvaluationFailureTest{
  197. Name: "OR string to bool",
  198. Input: "string || bool",
  199. Expected: INVALID_LOGICALOP_TYPES,
  200. },
  201. }
  202. runEvaluationFailureTests(evaluationTests, test)
  203. }
  204. /*
  205. While there is type-safe transitions checked at parse-time, tested in the "parsing_test" and "parsingFailure_test" files,
  206. we also need to make sure that we receive type mismatch errors during evaluation.
  207. */
  208. func TestComparatorTyping(test *testing.T) {
  209. evaluationTests := []EvaluationFailureTest{
  210. EvaluationFailureTest{
  211. Name: "GT literal bool to literal bool",
  212. Input: "true > true",
  213. Expected: INVALID_COMPARATOR_TYPES,
  214. },
  215. EvaluationFailureTest{
  216. Name: "GT bool to bool",
  217. Input: "bool > bool",
  218. Expected: INVALID_COMPARATOR_TYPES,
  219. },
  220. EvaluationFailureTest{
  221. Name: "GTE bool to bool",
  222. Input: "bool >= bool",
  223. Expected: INVALID_COMPARATOR_TYPES,
  224. },
  225. EvaluationFailureTest{
  226. Name: "LT bool to bool",
  227. Input: "bool < bool",
  228. Expected: INVALID_COMPARATOR_TYPES,
  229. },
  230. EvaluationFailureTest{
  231. Name: "LTE bool to bool",
  232. Input: "bool <= bool",
  233. Expected: INVALID_COMPARATOR_TYPES,
  234. },
  235. EvaluationFailureTest{
  236. Name: "GT number to string",
  237. Input: "number > string",
  238. Expected: INVALID_COMPARATOR_TYPES,
  239. },
  240. EvaluationFailureTest{
  241. Name: "GTE number to string",
  242. Input: "number >= string",
  243. Expected: INVALID_COMPARATOR_TYPES,
  244. },
  245. EvaluationFailureTest{
  246. Name: "LT number to string",
  247. Input: "number < string",
  248. Expected: INVALID_COMPARATOR_TYPES,
  249. },
  250. EvaluationFailureTest{
  251. Name: "REQ number to string",
  252. Input: "number =~ string",
  253. Expected: INVALID_COMPARATOR_TYPES,
  254. },
  255. EvaluationFailureTest{
  256. Name: "REQ number to bool",
  257. Input: "number =~ bool",
  258. Expected: INVALID_COMPARATOR_TYPES,
  259. },
  260. EvaluationFailureTest{
  261. Name: "REQ bool to number",
  262. Input: "bool =~ number",
  263. Expected: INVALID_COMPARATOR_TYPES,
  264. },
  265. EvaluationFailureTest{
  266. Name: "REQ bool to string",
  267. Input: "bool =~ string",
  268. Expected: INVALID_COMPARATOR_TYPES,
  269. },
  270. EvaluationFailureTest{
  271. Name: "NREQ number to string",
  272. Input: "number !~ string",
  273. Expected: INVALID_COMPARATOR_TYPES,
  274. },
  275. EvaluationFailureTest{
  276. Name: "NREQ number to bool",
  277. Input: "number !~ bool",
  278. Expected: INVALID_COMPARATOR_TYPES,
  279. },
  280. EvaluationFailureTest{
  281. Name: "NREQ bool to number",
  282. Input: "bool !~ number",
  283. Expected: INVALID_COMPARATOR_TYPES,
  284. },
  285. EvaluationFailureTest{
  286. Name: "NREQ bool to string",
  287. Input: "bool !~ string",
  288. Expected: INVALID_COMPARATOR_TYPES,
  289. },
  290. EvaluationFailureTest{
  291. Name: "IN non-array numeric",
  292. Input: "1 in 2",
  293. Expected: INVALID_COMPARATOR_TYPES,
  294. },
  295. EvaluationFailureTest{
  296. Name: "IN non-array string",
  297. Input: "1 in 'foo'",
  298. Expected: INVALID_COMPARATOR_TYPES,
  299. },
  300. EvaluationFailureTest{
  301. Name: "IN non-array boolean",
  302. Input: "1 in true",
  303. Expected: INVALID_COMPARATOR_TYPES,
  304. },
  305. }
  306. runEvaluationFailureTests(evaluationTests, test)
  307. }
  308. func TestTernaryTyping(test *testing.T) {
  309. evaluationTests := []EvaluationFailureTest{
  310. EvaluationFailureTest{
  311. Name: "Ternary with number",
  312. Input: "10 ? true",
  313. Expected: INVALID_TERNARY_TYPES,
  314. },
  315. EvaluationFailureTest{
  316. Name: "Ternary with string",
  317. Input: "'foo' ? true",
  318. Expected: INVALID_TERNARY_TYPES,
  319. },
  320. }
  321. runEvaluationFailureTests(evaluationTests, test)
  322. }
  323. func TestRegexParameterCompilation(test *testing.T) {
  324. evaluationTests := []EvaluationFailureTest{
  325. EvaluationFailureTest{
  326. Name: "Regex equality runtime parsing",
  327. Input: "'foo' =~ foo",
  328. Parameters: map[string]interface{}{
  329. "foo": "[foo",
  330. },
  331. Expected: INVALID_REGEX,
  332. },
  333. EvaluationFailureTest{
  334. Name: "Regex inequality runtime parsing",
  335. Input: "'foo' =~ foo",
  336. Parameters: map[string]interface{}{
  337. "foo": "[foo",
  338. },
  339. Expected: INVALID_REGEX,
  340. },
  341. }
  342. runEvaluationFailureTests(evaluationTests, test)
  343. }
  344. func TestFunctionExecution(test *testing.T) {
  345. evaluationTests := []EvaluationFailureTest{
  346. EvaluationFailureTest{
  347. Name: "Function error bubbling",
  348. Input: "error()",
  349. Functions: map[string]ExpressionFunction{
  350. "error": func(arguments ...interface{}) (interface{}, error) {
  351. return nil, errors.New("Huge problems")
  352. },
  353. },
  354. Expected: "Huge problems",
  355. },
  356. }
  357. runEvaluationFailureTests(evaluationTests, test)
  358. }
  359. func runEvaluationFailureTests(evaluationTests []EvaluationFailureTest, test *testing.T) {
  360. var expression *EvaluableExpression
  361. var err error
  362. fmt.Printf("Running %d negative parsing test cases...\n", len(evaluationTests))
  363. for _, testCase := range evaluationTests {
  364. if len(testCase.Functions) > 0 {
  365. expression, err = NewEvaluableExpressionWithFunctions(testCase.Input, testCase.Functions)
  366. } else {
  367. expression, err = NewEvaluableExpression(testCase.Input)
  368. }
  369. if err != nil {
  370. test.Logf("Test '%s' failed", testCase.Name)
  371. test.Logf("Expected evaluation error, but got parsing error: '%s'", err)
  372. test.Fail()
  373. continue
  374. }
  375. if testCase.Parameters == nil {
  376. testCase.Parameters = EVALUATION_FAILURE_PARAMETERS
  377. }
  378. _, err = expression.Evaluate(testCase.Parameters)
  379. if err == nil {
  380. test.Logf("Test '%s' failed", testCase.Name)
  381. test.Logf("Expected error, received none.")
  382. test.Fail()
  383. continue
  384. }
  385. if !strings.Contains(err.Error(), testCase.Expected) {
  386. test.Logf("Test '%s' failed", testCase.Name)
  387. test.Logf("Got error: '%s', expected '%s'", err.Error(), testCase.Expected)
  388. test.Fail()
  389. continue
  390. }
  391. }
  392. }