2015-03-17 18:25:24 +01:00
|
|
|
-- Expressions unit tests
|
|
|
|
|
|
|
|
context("Rspamd expressions", function()
|
|
|
|
local rspamd_expression = require "rspamd_expression"
|
|
|
|
local rspamd_mempool = require "rspamd_mempool"
|
2015-03-17 23:22:04 +01:00
|
|
|
local rspamd_regexp = require "rspamd_regexp"
|
2015-03-18 00:29:27 +01:00
|
|
|
local split_re = rspamd_regexp.create('/\\s+|\\)|\\(/')
|
2015-12-04 16:54:02 +01:00
|
|
|
|
2015-03-17 18:25:24 +01:00
|
|
|
local function parse_func(str)
|
|
|
|
-- extract token till the first space character
|
2015-03-18 00:29:27 +01:00
|
|
|
local token = str
|
|
|
|
local t = split_re:split(str)
|
|
|
|
if t then
|
|
|
|
token = t[1]
|
|
|
|
end
|
2015-03-17 18:25:24 +01:00
|
|
|
-- Return token name
|
|
|
|
return token
|
|
|
|
end
|
2015-12-04 16:54:02 +01:00
|
|
|
|
2015-03-17 18:25:24 +01:00
|
|
|
test("Expression creation function", function()
|
|
|
|
local function process_func(token, task)
|
|
|
|
-- Do something using token and task
|
|
|
|
end
|
2015-12-04 16:54:02 +01:00
|
|
|
|
2015-03-17 18:25:24 +01:00
|
|
|
local pool = rspamd_mempool.create()
|
2015-12-04 16:54:02 +01:00
|
|
|
|
2015-03-17 18:25:24 +01:00
|
|
|
local cases = {
|
2016-03-31 13:17:32 +02:00
|
|
|
{'A & B | !C', '(C) ! (A) (B) & |'},
|
|
|
|
{'A & (B | !C)', '(A) (B) (C) ! | &'},
|
2015-04-27 16:39:18 +02:00
|
|
|
{'A & B &', nil},
|
2015-03-18 11:54:42 +01:00
|
|
|
-- Unbalanced braces
|
|
|
|
{'(((A))', nil},
|
|
|
|
-- Balanced braces
|
2016-03-31 13:17:32 +02:00
|
|
|
{'(((A)))', '(A)'},
|
2017-06-27 09:44:19 +02:00
|
|
|
-- Plus and comparison operators
|
2016-03-31 13:17:32 +02:00
|
|
|
{'A + B + C + D > 2', '2 (A) (B) (C) (D) +(4) >'},
|
2015-03-18 11:54:42 +01:00
|
|
|
-- Plus and logic operators
|
2016-03-31 13:17:32 +02:00
|
|
|
{'((A + B + C + D) > 2) & D', '(D) 2 (A) (B) (C) (D) +(4) > &'},
|
2015-03-18 11:54:42 +01:00
|
|
|
-- Associativity
|
2016-03-31 13:17:32 +02:00
|
|
|
{'A | B | C & D & E', '(A) (B) (C) (D) (E) &(3) |(3)'},
|
2015-03-18 12:41:38 +01:00
|
|
|
-- More associativity
|
2016-03-31 13:17:32 +02:00
|
|
|
{'1 | 0 & 0 | 0', '(1) (0) (0) (0) & |(3)'},
|
|
|
|
{'(A) & (B) & ((C) | (D) | (E) | (F))', '(A) (B) (C) (D) (E) (F) |(4) &(3)' },
|
2015-03-18 12:41:38 +01:00
|
|
|
-- Extra space
|
2016-03-31 13:17:32 +02:00
|
|
|
{'A & B | ! C', '(C) ! (A) (B) & |'},
|
2015-03-17 18:25:24 +01:00
|
|
|
}
|
|
|
|
for _,c in ipairs(cases) do
|
2015-12-04 16:54:02 +01:00
|
|
|
local expr,err = rspamd_expression.create(c[1],
|
2015-03-17 18:25:24 +01:00
|
|
|
{parse_func, process_func}, pool)
|
2015-12-04 16:54:02 +01:00
|
|
|
|
2015-03-18 00:29:27 +01:00
|
|
|
if not c[2] then
|
|
|
|
assert_nil(expr, "Should not be able to parse " .. c[1])
|
2015-03-17 18:25:24 +01:00
|
|
|
else
|
2015-03-18 00:29:27 +01:00
|
|
|
assert_not_nil(expr, "Cannot parse " .. c[1])
|
2015-03-17 18:25:24 +01:00
|
|
|
assert_equal(expr:to_string(), c[2], string.format("Evaluated expr to '%s', expected: '%s'",
|
|
|
|
expr:to_string(), c[2]))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
-- Expression is destroyed when the corresponding pool is destroyed
|
|
|
|
pool:destroy()
|
|
|
|
end)
|
2015-03-19 14:47:31 +01:00
|
|
|
test("Expression process function", function()
|
|
|
|
local function process_func(token, input)
|
2015-12-04 16:54:02 +01:00
|
|
|
|
2015-03-24 18:30:00 +01:00
|
|
|
--print(token)
|
2015-03-19 14:47:31 +01:00
|
|
|
local t = input[token]
|
2015-12-04 16:54:02 +01:00
|
|
|
|
2015-03-19 14:47:31 +01:00
|
|
|
if t then return 1 end
|
|
|
|
return 0
|
|
|
|
end
|
2015-12-04 16:54:02 +01:00
|
|
|
|
2015-03-19 14:47:31 +01:00
|
|
|
local pool = rspamd_mempool.create()
|
|
|
|
local atoms = {
|
|
|
|
A = true,
|
|
|
|
B = false,
|
|
|
|
C = true,
|
|
|
|
D = false,
|
|
|
|
E = true,
|
|
|
|
F = false,
|
2016-03-31 13:17:32 +02:00
|
|
|
G = false,
|
|
|
|
H = false,
|
|
|
|
I = false,
|
|
|
|
J = false,
|
|
|
|
K = false,
|
2015-03-19 14:47:31 +01:00
|
|
|
}
|
|
|
|
local cases = {
|
|
|
|
{'A & B | !C', 0},
|
|
|
|
{'A & (!B | C)', 1},
|
|
|
|
{'A + B + C + D + E + F >= 2', 1},
|
|
|
|
{'((A + B + C + D) > 1) & F', 0},
|
2015-03-24 18:30:00 +01:00
|
|
|
{'(A + B + C + D) > 1 && F || E', 1},
|
|
|
|
{'(A + B + C + D) > 100 && F || !E', 0},
|
2015-03-25 19:24:58 +01:00
|
|
|
{'F && ((A + B + C + D) > 1)', 0},
|
2015-04-30 16:57:47 +02:00
|
|
|
{'(E) && ((B + B + B + B) >= 1)', 0},
|
2015-03-19 14:47:31 +01:00
|
|
|
{'!!C', 1},
|
2016-06-16 13:07:08 +02:00
|
|
|
{'(B) & (D) & ((G) | (H) | (I) | (A))', 0},
|
|
|
|
{'A & C & (!D || !C || !E)', 1},
|
|
|
|
{'A & C & !(D || C || E)', 0},
|
2015-03-19 14:47:31 +01:00
|
|
|
}
|
|
|
|
for _,c in ipairs(cases) do
|
2015-12-04 16:54:02 +01:00
|
|
|
local expr,err = rspamd_expression.create(c[1],
|
2015-03-19 14:47:31 +01:00
|
|
|
{parse_func, process_func}, pool)
|
|
|
|
|
|
|
|
assert_not_nil(expr, "Cannot parse " .. c[1])
|
2015-03-25 19:24:58 +01:00
|
|
|
--print(expr)
|
2015-03-19 14:47:31 +01:00
|
|
|
res = expr:process(atoms)
|
2016-06-16 13:07:08 +02:00
|
|
|
assert_equal(res, c[2], string.format("Processed expr '%s'{%s} returned '%d', expected: '%d'",
|
|
|
|
expr:to_string(), c[1], res, c[2]))
|
2015-03-19 14:47:31 +01:00
|
|
|
end
|
2015-12-04 16:54:02 +01:00
|
|
|
|
2015-03-19 14:47:31 +01:00
|
|
|
pool:destroy()
|
|
|
|
end)
|
2015-12-04 16:54:02 +01:00
|
|
|
end)
|