From 133a45c109da5310add55824db21af5239951f93 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 10 Apr 2024 23:30:40 +0200 Subject: Adding upstream version 3.8.1. Signed-off-by: Daniel Baumann --- test/lua/unit/addr.lua | 46 +++ test/lua/unit/base32.lua | 55 +++ test/lua/unit/base64.lua | 194 ++++++++++ test/lua/unit/compression.lua | 58 +++ test/lua/unit/expressions.lua | 111 ++++++ test/lua/unit/folding.lua | 66 ++++ test/lua/unit/fpconv.lua | 97 +++++ test/lua/unit/html.lua | 113 ++++++ test/lua/unit/kann.lua | 46 +++ test/lua/unit/logger.lua | 27 ++ test/lua/unit/lua_mime.message_to_ucl.lua | 330 ++++++++++++++++ test/lua/unit/lua_util.extract_specific_urls.lua | 345 +++++++++++++++++ test/lua/unit/lua_util.misc.lua | 61 +++ test/lua/unit/mempool.lua | 47 +++ test/lua/unit/quoted_printable.lua | 164 ++++++++ test/lua/unit/regxep.lua | 90 +++++ test/lua/unit/rfc2047.lua | 92 +++++ test/lua/unit/rsa.lua | 50 +++ test/lua/unit/rspamd_resolver.lua | 31 ++ test/lua/unit/rspamd_text.lua | 79 ++++ test/lua/unit/rspamd_util.lua | 136 +++++++ test/lua/unit/selectors.combined.lua | 130 +++++++ test/lua/unit/selectors.custom.lua | 81 ++++ test/lua/unit/selectors.lua | 472 +++++++++++++++++++++++ test/lua/unit/selectors.negative.lua | 113 ++++++ test/lua/unit/smtp_addr.lua | 110 ++++++ test/lua/unit/smtp_date.lua | 58 +++ test/lua/unit/sqlite3.lua | 50 +++ test/lua/unit/task.lua | 162 ++++++++ test/lua/unit/test.data | 10 + test/lua/unit/test_tld.dat | 20 + test/lua/unit/testkey.pub | 9 + test/lua/unit/testkey.sec | 27 ++ test/lua/unit/tokenizer.lua | 81 ++++ test/lua/unit/trie.lua | 81 ++++ test/lua/unit/url.lua | 253 ++++++++++++ test/lua/unit/utf.lua | 207 ++++++++++ 37 files changed, 4102 insertions(+) create mode 100644 test/lua/unit/addr.lua create mode 100644 test/lua/unit/base32.lua create mode 100644 test/lua/unit/base64.lua create mode 100644 test/lua/unit/compression.lua create mode 100644 test/lua/unit/expressions.lua create mode 100644 test/lua/unit/folding.lua create mode 100644 test/lua/unit/fpconv.lua create mode 100644 test/lua/unit/html.lua create mode 100644 test/lua/unit/kann.lua create mode 100644 test/lua/unit/logger.lua create mode 100644 test/lua/unit/lua_mime.message_to_ucl.lua create mode 100644 test/lua/unit/lua_util.extract_specific_urls.lua create mode 100644 test/lua/unit/lua_util.misc.lua create mode 100644 test/lua/unit/mempool.lua create mode 100644 test/lua/unit/quoted_printable.lua create mode 100644 test/lua/unit/regxep.lua create mode 100644 test/lua/unit/rfc2047.lua create mode 100644 test/lua/unit/rsa.lua create mode 100644 test/lua/unit/rspamd_resolver.lua create mode 100644 test/lua/unit/rspamd_text.lua create mode 100644 test/lua/unit/rspamd_util.lua create mode 100644 test/lua/unit/selectors.combined.lua create mode 100644 test/lua/unit/selectors.custom.lua create mode 100644 test/lua/unit/selectors.lua create mode 100644 test/lua/unit/selectors.negative.lua create mode 100644 test/lua/unit/smtp_addr.lua create mode 100644 test/lua/unit/smtp_date.lua create mode 100644 test/lua/unit/sqlite3.lua create mode 100644 test/lua/unit/task.lua create mode 100644 test/lua/unit/test.data create mode 100644 test/lua/unit/test_tld.dat create mode 100644 test/lua/unit/testkey.pub create mode 100644 test/lua/unit/testkey.sec create mode 100644 test/lua/unit/tokenizer.lua create mode 100644 test/lua/unit/trie.lua create mode 100644 test/lua/unit/url.lua create mode 100644 test/lua/unit/utf.lua (limited to 'test/lua/unit') diff --git a/test/lua/unit/addr.lua b/test/lua/unit/addr.lua new file mode 100644 index 0000000..6da72d3 --- /dev/null +++ b/test/lua/unit/addr.lua @@ -0,0 +1,46 @@ +-- inet addr tests + +context("Inet addr check functions", function() + local ffi = require("ffi") + + ffi.cdef[[ + typedef struct rspamd_inet_addr_s rspamd_inet_addr_t; + bool rspamd_parse_inet_address (rspamd_inet_addr_t **target, + const char *src, size_t len); + void rspamd_inet_address_free (rspamd_inet_addr_t *addr); + ]] + + local cases = { + {'192.168.1.1', true}, + {'2a01:4f8:190:43b5::99', true}, + {'256.1.1.1', false}, + {'/tmp/socket', true}, + {'./socket', true}, + {'[fe80::f919:8b26:ff93:3092%5]', true}, + {'[fe80::f919:8b26:ff93:3092]', true}, + {'IPv6:::1', true}, + {'IPv6:[::1]', true}, + {'IPv6[:::1]', false}, + {'[::]', true}, + {'[1::]', true}, + {'[000:01:02:003:004:5:6:007]', true}, -- leading zeros + {'[A:b:c:DE:fF:0:1:aC]', true}, -- mixed case + {'[::192.168.0.1]', true}, -- embedded ipv4 + {'[1:2:192.168.0.1:5:6]', false}, -- poor octets + {'[::ffff:192.1.2]', false}, -- ipv4 without last octet (maybe should be true?) + {'[0:0::0:0:8]', true}, -- bogus zeros + {'[::192.168.0.0.1]', false}, -- invalid mapping + } + + for i,c in ipairs(cases) do + test("Create inet addr from string " .. c[1] .. '; expect ' .. tostring(c[2]), function() + local ip = ffi.new("rspamd_inet_addr_t* [1]"); + local res = ffi.C.rspamd_parse_inet_address(ip, c[1], #c[1]) + assert_equal(res, c[2], "Expect " .. tostring(c[2]) .. " while parsing " .. c[1]) + if res then + ffi.C.rspamd_inet_address_free(ip[0]) + end + end) + + end +end) \ No newline at end of file diff --git a/test/lua/unit/base32.lua b/test/lua/unit/base32.lua new file mode 100644 index 0000000..eb582f5 --- /dev/null +++ b/test/lua/unit/base32.lua @@ -0,0 +1,55 @@ +-- Test zbase32 encoding/decoding + +context("Base32 encodning", function() + local ffi = require("ffi") + ffi.cdef[[ + void ottery_rand_bytes(void *buf, size_t n); + unsigned ottery_rand_unsigned(void); + unsigned char* rspamd_decode_base32 (const char *in, size_t inlen, size_t *outlen, int how); + char * rspamd_encode_base32 (const unsigned char *in, size_t inlen, int how); + void g_free(void *ptr); + int memcmp(const void *a1, const void *a2, size_t len); + ]] + + local function random_buf(max_size) + local l = ffi.C.ottery_rand_unsigned() % max_size + 1 + local buf = ffi.new("unsigned char[?]", l) + ffi.C.ottery_rand_bytes(buf, l) + + return buf, l + end + + test("Base32 encode test", function() + local cases = { + {'test123', 'wm3g84fg13cy'}, + {'hello', 'em3ags7p'} + } + + for _,c in ipairs(cases) do + local b = ffi.C.rspamd_encode_base32(c[1], #c[1], 0) + local s = ffi.string(b) + ffi.C.g_free(b) + assert_equal(s, c[2], s .. " not equal " .. c[2]) + end + end) + + if os.getenv("RSPAMD_LUA_EXPENSIVE_TESTS") then + test("Base32 fuzz test: zbase32", function() + for i = 1,1000 do + local b, l = random_buf(4096) + local how = math.floor(math.random(3) - 1) + local ben = ffi.C.rspamd_encode_base32(b, l, how) + local bs = ffi.string(ben) + local nl = ffi.new("size_t [1]") + local nb = ffi.C.rspamd_decode_base32(bs, #bs, nl, how) + + assert_equal(tonumber(nl[0]), l, + string.format("invalid size reported: %d reported vs %d expected", tonumber(nl[0]), l)) + local cmp = ffi.C.memcmp(b, nb, l) + ffi.C.g_free(ben) + ffi.C.g_free(nb) + assert_equal(cmp, 0, "fuzz test failed for length: " .. tostring(l)) + end + end) + end +end) \ No newline at end of file diff --git a/test/lua/unit/base64.lua b/test/lua/unit/base64.lua new file mode 100644 index 0000000..02948e2 --- /dev/null +++ b/test/lua/unit/base64.lua @@ -0,0 +1,194 @@ +context("Base64 encoding", function() + local ffi = require("ffi") + local util = require("rspamd_util") + local logger = require "rspamd_logger" + ffi.cdef[[ + void rspamd_cryptobox_init (void); + void ottery_rand_bytes(void *buf, size_t n); + unsigned ottery_rand_unsigned(void); + unsigned char* g_base64_decode (const char *in, size_t *outlen); + char * rspamd_encode_base64 (const unsigned char *in, size_t inlen, + size_t str_len, size_t *outlen); + void g_free(void *ptr); + int memcmp(const void *a1, const void *a2, size_t len); + double base64_test (bool generic, size_t niters, size_t len, size_t str_len); + double rspamd_get_ticks (int); + ]] + + ffi.C.rspamd_cryptobox_init() + + local function random_buf(max_size) + local l = ffi.C.ottery_rand_unsigned() % max_size + 1 + local buf = ffi.new("unsigned char[?]", l) + ffi.C.ottery_rand_bytes(buf, l) + + return buf, l + end + + local function random_safe_buf(max_size) + local l = ffi.C.ottery_rand_unsigned() % max_size + 1 + local buf = ffi.new("unsigned char[?]", l) + + for i = 0,l-1 do + buf[i] = ffi.C.ottery_rand_unsigned() % 20 + string.byte('A') + end + + buf[l - 1] = 0; + + return buf, l + end + + test("Base64 encode test", function() + local cases = { + {"", ""}, + {"f", "Zg=="}, + {"fo", "Zm8="}, + {"foo", "Zm9v"}, + {"foob", "Zm9vYg=="}, + {"fooba", "Zm9vYmE="}, + {"foobar", "Zm9vYmFy"}, + } + + local nl = ffi.new("size_t [1]") + for _,c in ipairs(cases) do + local b = ffi.C.rspamd_encode_base64(c[1], #c[1], 0, nl) + local s = ffi.string(b) + ffi.C.g_free(b) + assert_equal(s, c[2], s .. " not equal " .. c[2]) + end + end) + + test("Base64 decode test", function() + local cases = { + {"", ""}, + {"f", "Zg=="}, + {"fo", "Zm8="}, + {"foo", "Zm9v"}, + {"foob", "Zm9vYg=="}, + {"fooba", "Zm9vYmE="}, + {"foobar", "Zm9vYmFy"}, + } + + for _,c in ipairs(cases) do + local b = tostring(util.decode_base64(c[2])) + assert_equal(b, c[1], b .. " not equal " .. c[1]) + end + end) + + test("Base64 line split encode test", function() + local text = [[ +Man is distinguished, not only by his reason, but by this singular passion from +other animals, which is a lust of the mind, that by a perseverance of delight +in the continued and indefatigable generation of knowledge, exceeds the short +vehemence of any carnal pleasure.]] + local b64 = "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz\r\nIHNpbmd1bGFyIHBhc3Npb24gZnJvbQpvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg\r\ndGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodAppbiB0aGUgY29udGlu\r\ndWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo\r\nZSBzaG9ydAp2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=" + local nl = ffi.new("size_t [1]") + local b = ffi.C.rspamd_encode_base64(text, #text, 76, nl) + local cmp = ffi.C.memcmp(b, b64, nl[0]) + ffi.C.g_free(b) + assert_equal(cmp, 0) + end) + + if os.getenv("RSPAMD_LUA_EXPENSIVE_TESTS") then + test("Base64 fuzz test", function() + for i = 1,1000 do + local b, l = random_safe_buf(4096) + local lim = ffi.C.ottery_rand_unsigned() % 64 + 10 + local orig = ffi.string(b) + local ben = util.encode_base64(orig, lim) + local dec = util.decode_base64(ben) + assert_equal(orig, tostring(dec), "fuzz test failed for length: " .. #orig) + end + end) + test("Base64 fuzz test (ffi)", function() + for i = 1,1000 do + local b, l = random_buf(4096) + local nl = ffi.new("size_t [1]") + local lim = ffi.C.ottery_rand_unsigned() % 64 + 10 + local ben = ffi.C.rspamd_encode_base64(b, l, lim, nl) + local bs = ffi.string(ben) + local ol = ffi.new("size_t [1]") + local nb = ffi.C.g_base64_decode(ben, ol) + + local cmp = ffi.C.memcmp(b, nb, l) + ffi.C.g_free(ben) + ffi.C.g_free(nb) + assert_equal(cmp, 0, "fuzz test failed for length: " .. tostring(l)) + end + end) + + local speed_iters = 10000 + + local function perform_base64_speed_test(chunk, is_reference, line_len) + local ticks = ffi.C.base64_test(is_reference, speed_iters, chunk, line_len) + local what = 'Optimized' + if is_reference then + what = 'Reference' + end + logger.messagex("%s base64 %s chunk (%s line len): %s ticks per iter, %s ticks per byte", + what, chunk, line_len, + ticks / speed_iters, ticks / speed_iters / chunk) + + return 1 + end + test("Base64 test reference vectors 78", function() + local res = perform_base64_speed_test(78, true, 0) + assert_not_equal(res, 0) + end) + test("Base64 test optimized vectors 78", function() + local res = perform_base64_speed_test(78, false, 0) + assert_not_equal(res, 0) + end) + + test("Base64 test reference vectors 512", function() + local res = perform_base64_speed_test(512, true, 0) + assert_not_equal(res, 0) + end) + test("Base64 test optimized vectors 512", function() + local res = perform_base64_speed_test(512, false, 0) + assert_not_equal(res, 0) + end) + test("Base64 test reference vectors 512 (78 line len)", function() + local res = perform_base64_speed_test(512, true, 78) + assert_not_equal(res, 0) + end) + test("Base64 test optimized vectors 512 (78 line len)", function() + local res = perform_base64_speed_test(512, false, 78) + assert_not_equal(res, 0) + end) + + test("Base64 test reference vectors 1K", function() + local res = perform_base64_speed_test(1024, true, 0) + assert_not_equal(res, 0) + end) + test("Base64 test optimized vectors 1K", function() + local res = perform_base64_speed_test(1024, false, 0) + assert_not_equal(res, 0) + end) + test("Base64 test reference vectors 1K (78 line len)", function() + local res = perform_base64_speed_test(1024, true, 78) + assert_not_equal(res, 0) + end) + test("Base64 test optimized vectors 1K (78 line len)", function() + local res = perform_base64_speed_test(1024, false, 78) + assert_not_equal(res, 0) + end) + + test("Base64 test reference vectors 10K", function() + local res = perform_base64_speed_test(10 * 1024, true, 0) + assert_not_equal(res, 0) + end) + test("Base64 test optimized vectors 10K", function() + local res = perform_base64_speed_test(10 * 1024, false, 0) + assert_not_equal(res, 0) + end) + test("Base64 test reference vectors 10K (78 line len)", function() + local res = perform_base64_speed_test(10 * 1024, true, 78) + assert_not_equal(res, 0) + end) + test("Base64 test optimized vectors 10K (78 line len)", function() + local res = perform_base64_speed_test(10 * 1024, false, 78) + assert_not_equal(res, 0) + end) + end +end) diff --git a/test/lua/unit/compression.lua b/test/lua/unit/compression.lua new file mode 100644 index 0000000..d5c682c --- /dev/null +++ b/test/lua/unit/compression.lua @@ -0,0 +1,58 @@ +-- Compression unit tests + +context("Rspamd compression", function() + local rspamd_zstd = require "rspamd_zstd" + local rspamd_text = require "rspamd_text" + + test("Compressed can be decompressed", function() + local str = 'test' + local cctx = rspamd_zstd.compress_ctx() + local dctx = rspamd_zstd.decompress_ctx() + assert_rspamd_eq({actual = dctx:stream(cctx:stream(str, 'end')), + expect = rspamd_text.fromstring(str)}) + end) + test("Compressed concatenation can be decompressed", function() + local str = 'test' + local cctx = rspamd_zstd.compress_ctx() + local dctx = rspamd_zstd.decompress_ctx() + assert_rspamd_eq({actual = dctx:stream(cctx:stream(str) .. cctx:stream(str, 'end')), + expect = rspamd_text.fromstring(str .. str)}) + end) + + if os.getenv("RSPAMD_LUA_EXPENSIVE_TESTS") then + local sizes = {10, 100, 1000, 10000} + for _,sz in ipairs(sizes) do + test("Compressed fuzz size: " .. tostring(sz), function() + for _=1,1000 do + local rnd = rspamd_text.randombytes(sz) + local cctx = rspamd_zstd.compress_ctx() + local dctx = rspamd_zstd.decompress_ctx() + assert_rspamd_eq({actual = dctx:stream(cctx:stream(rnd, 'end')), + expect = rnd}) + end + end) + end + end + + test("Compressed chunks", function() + local cctx = rspamd_zstd.compress_ctx() + local tin = {} + local tout = {} + for i=1,1000 do + local rnd = rspamd_text.randombytes(i) + tin[#tin + 1] = rnd + end + for i=1,1000 do + local o + if i == 1000 then + o = cctx:stream(tin[i], 'end') + else + o = cctx:stream(tin[i]) + end + tout[#tout + 1] = o + end + local dctx = rspamd_zstd.decompress_ctx() + assert_rspamd_eq({actual = dctx:stream(rspamd_text.fromtable(tout)), + expect = rspamd_text.fromtable(tin)}) + end) +end) \ No newline at end of file diff --git a/test/lua/unit/expressions.lua b/test/lua/unit/expressions.lua new file mode 100644 index 0000000..3d05685 --- /dev/null +++ b/test/lua/unit/expressions.lua @@ -0,0 +1,111 @@ +-- Expressions unit tests + +context("Rspamd expressions", function() + local rspamd_expression = require "rspamd_expression" + local rspamd_mempool = require "rspamd_mempool" + local rspamd_regexp = require "rspamd_regexp" + local split_re = rspamd_regexp.create('/\\s+|\\)|\\(/') + + local function parse_func(str) + -- extract token till the first space character + local token = str + local t = split_re:split(str) + if t then + token = t[1] + end + -- Return token name + return token + end + + local atoms = { + A = 1.0, + B = 0, + C = 1, + D = 0, + E = 1, + F = 0, + G = 0, + H = 0, + I = 0, + J = 0, + K = 0, + } + local function process_func(token, input) + + --print(token) + local t = input[token] + + return t + end + + local pool = rspamd_mempool.create() + + local cases = { + {'A & (!B | C)', '(A) (B) ! (C) | &'}, + {'A & B | !C', '(C) ! (A) (B) & |'}, + {'A & (B | !C)', '(A) (B) (C) ! | &'}, + {'A & B &', nil}, + -- Unbalanced braces + {'(((A))', nil}, + -- Balanced braces + {'(((A)))', '(A)'}, + -- Plus and comparison operators + {'A + B + C + D > 2', '(A) (B) (C) (D) +(4) 2 >'}, + -- Plus and logic operators + {'((A + B + C + D) > 2) & D', '(D) (A) (B) (C) (D) +(4) 2 > &'}, + -- Associativity + {'A | B | C & D & E', '(A) (B) (C) (D) (E) &(3) |(3)'}, + -- More associativity + {'1 | 0 & 0 | 0', '(1) (0) (0) (0) & |(3)'}, + {'(A) & (B) & ((C) | (D) | (E) | (F))', '(A) (B) (C) (D) (E) (F) |(4) &(3)' }, + -- Extra space + {'A & B | ! C', '(C) ! (A) (B) & |'}, + -- False minus + {'A + B + -C', '(A) (B) (-C) +(3)'}, + } + for _,c in ipairs(cases) do + test("Expression creation function: " .. c[1], function() + local expr,err = rspamd_expression.create(c[1], + {parse_func, process_func}, pool) + + if not c[2] then + assert_nil(expr, "Should not be able to parse " .. c[1]) + else + assert_not_nil(expr, "Cannot parse " .. c[1] .. '; error: ' .. (err or 'wut??')) + assert_equal(expr:to_string(), c[2], string.format("Evaluated expr to '%s', expected: '%s'", + expr:to_string(), c[2])) + end + end) + end + -- Expression is destroyed when the corresponding pool is destroyed + cases = { + {'(E) && ((B + B + B + B) >= 1)', 0}, + {'A & B | !C', 0}, + {'A & (!B | C)', 1}, + {'A + B + C + D + E + F >= 2', 1}, + {'((A + B + C + D) > 1) & F', 0}, + {'(A + B + C + D) > 1 && F || E', 1}, + {'(A + B + C + D) > 100 && F || !E', 0}, + {'F && ((A + B + C + D) > 1)', 0}, + {'(E) && ((B + B + B + B) >= 1)', 0}, + {'!!C', 1}, + {'(B) & (D) & ((G) | (H) | (I) | (A))', 0}, + {'A & C & (!D || !C || !E)', 1}, + {'A & C & !(D || C || E)', 0}, + {'A + B + C', 2}, + {'A * 2.0 + B + C', 3}, + {'A * 2.0 + B - C', 1}, + {'A / 2.0 + B - C', -0.5}, + } + for _,c in ipairs(cases) do + test("Expression process function: " .. c[1], function() + local expr,err = rspamd_expression.create(c[1], + {parse_func, process_func}, pool) + + assert_not_nil(expr, "Cannot parse " .. c[1] .. '; error: ' .. (err or 'wut??')) + res = expr:process(atoms) + assert_equal(res, c[2], string.format("Processed expr '%s'{%s} returned '%d', expected: '%d'", + expr:to_string(), c[1], res, c[2])) + end) + end +end) diff --git a/test/lua/unit/folding.lua b/test/lua/unit/folding.lua new file mode 100644 index 0000000..8a92384 --- /dev/null +++ b/test/lua/unit/folding.lua @@ -0,0 +1,66 @@ +--[[ +Copyright (c) 2022, Vsevolod Stakhov +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +]]-- + +context("Headers folding unit test", function() + local util = require("rspamd_util") + -- {header, value}, "expected result" + local cases = { + {{"test", "test"}, "test"}, + {{"test1", "_abc _def _ghi _fdjhfd _fhdjkfh _dkhkjd _fdjkf _dshfdks _fhdjfdkhfk _dshfds _fdsjk _fdkhfdks _fdsjf _dkf"}, + "_abc _def _ghi _fdjhfd _fhdjkfh _dkhkjd _fdjkf _dshfdks\r\n\t_fhdjfdkhfk _dshfds _fdsjk _fdkhfdks _fdsjf _dkf" + }, + {{"Test1", "_abc _def _ghi _fdjhfd _fhdjkfh _dkhaaaaaaaaaaakjdfdjkfdshfdksfhdjfdkhfkdshfdsfdsjkfdkhfdksfdsjf _dkf"}, + "_abc _def _ghi _fdjhfd _fhdjkfh\r\n\t_dkhaaaaaaaaaaakjdfdjkfdshfdksfhdjfdkhfkdshfdsfdsjkfdkhfdksfdsjf\r\n\t_dkf" + }, + {{"Content-Type", "multipart/mixed; boundary=\"---- =_NextPart_000_01BDBF1F.DA8F77EE\"hhhhhhhhhhhhhhhhhhhhhhhhh fjsdhfkjsd fhdjsfhkj"}, + "multipart/mixed; boundary=\"---- =_NextPart_000_01BDBF1F.DA8F77EE\"hhhhhhhhhhhhhhhhhhhhhhhhh\r\n\tfjsdhfkjsd fhdjsfhkj" + }, + {{"Content-Type", "multipart/mixed; boundary=\"---- =_NextPart_000_01BDBF1F.DA8F77EE\"hkjhgkfhgfhgf\"hfkjdhf fhjf fghjghf fdshjfhdsj\" hgjhgfjk"}, + "multipart/mixed; boundary=\"---- =_NextPart_000_01BDBF1F.DA8F77EE\"hkjhgkfhgfhgf\"hfkjdhf fhjf fghjghf fdshjfhdsj\" hgjhgfjk" + }, + {{"Content-Type", "Content-Type: multipart/mixed; boundary=\"---- =_NextPart_000_01BDBF1F.DA8F77EE\" abc def ghfdgfdsgj fdshfgfsdgfdsg hfsdgjfsdg fgsfgjsg"}, + "Content-Type: multipart/mixed; boundary=\"---- =_NextPart_000_01BDBF1F.DA8F77EE\" abc\r\n\tdef ghfdgfdsgj fdshfgfsdgfdsg hfsdgjfsdg fgsfgjsg" + }, + {{"X-Spam-Symbols", "Returnpath_BL2,HFILTER_FROM_BOUNCE,R_PARTS_DIFFER,R_IP_PBL,R_ONE_RCPT,R_googleredir,R_TO_SEEMS_AUTO,R_SPF_NEUTRAL,R_PRIORITY_3,RBL_SPAMHAUS_PBL,HFILTER_MID_NOT_FQDN,MISSING_CTE,R_HAS_URL,RBL_SPAMHAUS_CSS,RBL_SPAMHAUS_XBL,BAYES_SPAM,RECEIVED_RBL10", ','}, + "Returnpath_BL2,\r\n\tHFILTER_FROM_BOUNCE,\r\n\tR_PARTS_DIFFER,\r\n\tR_IP_PBL,\r\n\tR_ONE_RCPT,\r\n\tR_googleredir,\r\n\tR_TO_SEEMS_AUTO,\r\n\tR_SPF_NEUTRAL,\r\n\tR_PRIORITY_3,\r\n\tRBL_SPAMHAUS_PBL,\r\n\tHFILTER_MID_NOT_FQDN,\r\n\tMISSING_CTE,\r\n\tR_HAS_URL,\r\n\tRBL_SPAMHAUS_CSS,\r\n\tRBL_SPAMHAUS_XBL,\r\n\tBAYES_SPAM,\r\n\tRECEIVED_RBL10" + }, + } + local function escape_spaces(str) + str = string.gsub(str, '[\r\n]+', '') + str = string.gsub(str, '[ ]', '') + str = string.gsub(str, '[\t]', '') + + return str + end + for i,c in ipairs(cases) do + test("Headers folding: " .. i, function() + local fv = util.fold_header(c[1][1], c[1][2], 'crlf', c[1][3]) + assert_not_nil(fv) + assert_equal(fv, c[2], string.format("'%s' doesn't match with '%s'", + escape_spaces(c[2]), escape_spaces(fv))) + end) + end +end) diff --git a/test/lua/unit/fpconv.lua b/test/lua/unit/fpconv.lua new file mode 100644 index 0000000..e64626f --- /dev/null +++ b/test/lua/unit/fpconv.lua @@ -0,0 +1,97 @@ +-- fpconv tests + +context("Fpconv printf functions", function() + local ffi = require("ffi") + local niter_fuzz = 100000 + local function small_double() + return math.random() + end + local function large_double() + return math.random() * math.random(2^52) + end + local function huge_double() + return math.random(2^52) * math.random(2^52) + end + local function tiny_double() + return math.random() / math.random(2^52) + end + ffi.cdef[[ +int snprintf(char *str, size_t size, const char *format, ...); +long rspamd_snprintf(char *str, size_t size, const char *format, ...); +long rspamd_printf(const char *format, ...); +]] + local benchmarks = { + {'tiny fixed', small_double, '%f'}, + {'small fixed', tiny_double, '%f'}, + {'large fixed', large_double, '%.3f'}, + {'huge fixed', huge_double, '%.3f'}, + {'tiny scientific', small_double, '%g'}, + {'small scientific', tiny_double, '%g'}, + {'large scientific', large_double, '%g'}, + {'huge scientific', huge_double, '%g'}, + } + + local generic = { + {0, '%f', '0'}, + {0, '%.1f', '0.0'}, + {0, '%.2f', '0.00'}, + {0, '%.32f', '0.000000000000000000000000000'}, -- max + {0, '%.150f', '0.000000000000000000000000000'}, -- too large + {1/3, '%f', '0.3333333333333333'}, + {1/3, '%.1f', '0.3'}, + {1/3, '%.2f', '0.33'}, + {-1/3, '%.32f', '-0.333333333333333300000000000'}, + {-1/3, '%.150f', '-0.333333333333333300000000000'}, + {-3.6817595395344857e-68, '%f', '-3.6817595395344857e-68'}, + {3.5844466002796428e+298, '%f', '3.5844466002796428e+298'}, + {9223372036854775808, '%f', '9223372036854776000'}, -- 2^63 with precision lost + {2^50 + 0.2, '%f', '1125899906842624.3'}, -- 2^50 with precision lost + {2^50 + 0.2, '%.2f', '1125899906842624.30'}, -- 2^50 with precision lost + {-3.6817595395344857e-68, '%.3f', '-0.000'}, -- not enough precision + {3.5844466002796428e+298, '%.3f', '3.5844466002796428e+298'}, + {9223372036854775808, '%.3f', '9223372036854776000.000'}, -- 2^63 with precision lost + {math.huge, '%f', 'inf'}, + {-math.huge, '%f', '-inf'}, + {0.0/0.0, '%f', 'nan'}, + {math.huge, '%.1f', 'inf'}, + {-math.huge, '%.2f', '-inf'}, + {0.0/0.0, '%.3f', 'nan'}, + {math.huge, '%g', 'inf'}, + {-math.huge, '%g', '-inf'}, + {0.0/0.0, '%g', 'nan'}, + } + + local buf = ffi.new("char[64]") + local buf2 = ffi.new("char[64]") + + for i,c in ipairs(generic) do + test("Generic fp test fmt: " .. c[2] .. '; ' .. tostring(c[1]), function() + ffi.C.rspamd_snprintf(buf, 64, c[2], c[1]) + local sbuf = ffi.string(buf) + assert_equal(sbuf, c[3], c[3] .. " but test returned " .. sbuf) + end) + end + if os.getenv("RSPAMD_LUA_EXPENSIVE_TESTS") then + for _,c in ipairs(benchmarks) do + test("Fuzz fp test " .. c[1], function() + for _=1,niter_fuzz do + local sign = 1 + if math.random() > 0.5 then + sign = -1 + end + local d = c[2]() * sign + ffi.C.snprintf(buf, 64, c[3], d) + ffi.C.rspamd_snprintf(buf2, 64, c[3], d) + + local sbuf = ffi.string(buf) + local sbuf2 = ffi.string(buf2) + + assert_less_than(math.abs(d - tonumber(sbuf2))/math.abs(d), + 0.00001, + string.format('rspamd emitted: %s, libc emitted: %s, original number: %g', + sbuf2, sbuf, d)) + end + end) + end + end +end) \ No newline at end of file diff --git a/test/lua/unit/html.lua b/test/lua/unit/html.lua new file mode 100644 index 0000000..81c52ec --- /dev/null +++ b/test/lua/unit/html.lua @@ -0,0 +1,113 @@ +context("HTML processing", function() + local rspamd_util = require("rspamd_util") + local logger = require("rspamd_logger") + local cases = { + -- Entities + {[[.firebaseapp.com]], + [[.firebaseapp.com]]}, + {[[ + + + + + + Wikibooks + + + +

+ Hello, world! + +

+ + ]], 'Hello, world!\n'}, + {[[ + + + + + title + + +