aboutsummaryrefslogtreecommitdiffstats
path: root/test/lua
diff options
context:
space:
mode:
authorHadriel Kaplan <hadrielk@yahoo.com>2014-02-22 00:44:00 -0500
committerAnders Broman <a.broman58@gmail.com>2014-03-10 07:11:12 +0000
commitea46cdc4748d84d5026a7703b25e427f8170833e (patch)
tree97c581cda8563f0b91996fd685c9dc6fb42eeba5 /test/lua
parent81c0091c0ad593c5ded0af4622cf10c19cb18ae7 (diff)
Add GLib's regex library into Lua
While Lua's built-in pattern support is ok for simple things, many people end up wanting a real regex engine. Since Wireshark already includes the GLib Regex library (a wrapper for PCRE), it makes sense to expose that library to Lua scripts. This has been done using Lrexlib, one of the most popular regex bindings for Lua. Lrexlib didn't support binding GLib's Regex in particular - it does for PCRE but GLib is a different API - so I've done that. A fairly thorough testsuite came along with that, which has been incorporated into the wireshark wslua testuites as well in this commit. Change-Id: I05811d1edf7af8d7c9f4f081de6850f31c0717c7 Reviewed-on: https://code.wireshark.org/review/332 Reviewed-by: Anders Broman <a.broman58@gmail.com>
Diffstat (limited to 'test/lua')
-rwxr-xr-xtest/lua/common_sets.lua319
-rw-r--r--test/lua/glib_sets.lua204
-rw-r--r--test/lua/gregex.lua285
-rwxr-xr-xtest/lua/luatest.lua174
-rwxr-xr-xtest/lua/pat2pcre.lua87
-rwxr-xr-xtest/lua/pcre_sets.lua179
-rwxr-xr-xtest/lua/pcre_sets2.lua198
7 files changed, 1446 insertions, 0 deletions
diff --git a/test/lua/common_sets.lua b/test/lua/common_sets.lua
new file mode 100755
index 0000000000..e71251fea8
--- /dev/null
+++ b/test/lua/common_sets.lua
@@ -0,0 +1,319 @@
+-- See Copyright Notice in the file LICENSE
+
+-- This file should contain only test sets that behave identically
+-- when being run with pcre or posix regex libraries.
+
+local luatest = require "luatest"
+local N = luatest.NT
+
+local function norm(a) return a==nil and N or a end
+
+local function get_gsub (lib)
+ return lib.gsub or
+ function (subj, pattern, repl, n)
+ return lib.new (pattern) : gsub (subj, repl, n)
+ end
+end
+
+local function set_f_gmatch (lib, flg)
+ -- gmatch (s, p, [cf], [ef])
+ local function test_gmatch (subj, patt)
+ local out, guard = {}, 10
+ for a, b in lib.gmatch (subj, patt) do
+ table.insert (out, { norm(a), norm(b) })
+ guard = guard - 1
+ if guard == 0 then break end
+ end
+ return unpack (out)
+ end
+ return {
+ Name = "Function gmatch",
+ Func = test_gmatch,
+ --{ subj patt results }
+ { {"ab", lib.new"."}, {{"a",N}, {"b",N} } },
+ { {("abcd"):rep(3), "(.)b.(d)"}, {{"a","d"},{"a","d"},{"a","d"}} },
+ { {"abcd", ".*" }, {{"abcd",N},{"",N} } },--zero-length match
+ { {"abc", "^." }, {{"a",N}} },--anchored pattern
+ }
+end
+
+local function set_f_split (lib, flg)
+ -- split (s, p, [cf], [ef])
+ local function test_split (subj, patt)
+ local out, guard = {}, 10
+ for a, b, c in lib.split (subj, patt) do
+ table.insert (out, { norm(a), norm(b), norm(c) })
+ guard = guard - 1
+ if guard == 0 then break end
+ end
+ return unpack (out)
+ end
+ return {
+ Name = "Function split",
+ Func = test_split,
+ --{ subj patt results }
+ { {"ab", lib.new","}, {{"ab",N,N}, } },
+ { {"ab", ","}, {{"ab",N,N}, } },
+ { {",", ","}, {{"",",",N}, {"", N, N}, } },
+ { {",,", ","}, {{"",",",N}, {"",",",N}, {"",N,N} } },
+ { {"a,b", ","}, {{"a",",",N}, {"b",N,N}, } },
+ { {",a,b", ","}, {{"",",",N}, {"a",",",N}, {"b",N,N}} },
+ { {"a,b,", ","}, {{"a",",",N}, {"b",",",N}, {"",N,N} } },
+ { {"a,,b", ","}, {{"a",",",N}, {"",",",N}, {"b",N,N}} },
+ { {"ab<78>c", "<(.)(.)>"}, {{"ab","7","8"}, {"c",N,N}, } },
+ { {"abc", "^."}, {{"", "a",N}, {"bc",N,N}, } },--anchored pattern
+ { {"abc", "^"}, {{"", "", N}, {"abc",N,N}, } },
+-- { {"abc", "$"}, {{"abc","",N}, {"",N,N}, } },
+-- { {"abc", "^|$"}, {{"", "", N}, {"abc","",N},{"",N,N},} },
+ }
+end
+
+local function set_f_find (lib, flg)
+ return {
+ Name = "Function find",
+ Func = lib.find,
+ -- {subj, patt, st}, { results }
+ { {"abcd", lib.new".+"}, { 1,4 } }, -- [none]
+ { {"abcd", ".+"}, { 1,4 } }, -- [none]
+ { {"abcd", ".+", 2}, { 2,4 } }, -- positive st
+ { {"abcd", ".+", -2}, { 3,4 } }, -- negative st
+ { {"abcd", ".*"}, { 1,4 } }, -- [none]
+ { {"abc", "bc"}, { 2,3 } }, -- [none]
+ { {"abcd", "(.)b.(d)"}, { 1,4,"a","d" }}, -- [captures]
+ }
+end
+
+local function set_f_match (lib, flg)
+ return {
+ Name = "Function match",
+ Func = lib.match,
+ -- {subj, patt, st}, { results }
+ { {"abcd", lib.new".+"}, {"abcd"} }, -- [none]
+ { {"abcd", ".+"}, {"abcd"} }, -- [none]
+ { {"abcd", ".+", 2}, {"bcd"} }, -- positive st
+ { {"abcd", ".+", -2}, {"cd"} }, -- negative st
+ { {"abcd", ".*"}, {"abcd"} }, -- [none]
+ { {"abc", "bc"}, {"bc"} }, -- [none]
+ { {"abcd", "(.)b.(d)"}, {"a","d"} }, -- [captures]
+ }
+end
+
+local function set_m_exec (lib, flg)
+ return {
+ Name = "Method exec",
+ Method = "exec",
+ --{patt}, {subj, st} { results }
+ { {".+"}, {"abcd"}, {1,4,{}} }, -- [none]
+ { {".+"}, {"abcd",2}, {2,4,{}} }, -- positive st
+ { {".+"}, {"abcd",-2}, {3,4,{}} }, -- negative st
+ { {".*"}, {"abcd"}, {1,4,{}} }, -- [none]
+ { {"bc"}, {"abc"}, {2,3,{}} }, -- [none]
+ { { "(.)b.(d)"}, {"abcd"}, {1,4,{1,1,4,4}}},--[captures]
+ { {"(a+)6+(b+)"}, {"Taa66bbT",2}, {2,7,{2,3,6,7}}},--[st+captures]
+ }
+end
+
+local function set_m_tfind (lib, flg)
+ return {
+ Name = "Method tfind",
+ Method = "tfind",
+ --{patt}, {subj, st} { results }
+ { {".+"}, {"abcd"}, {1,4,{}} }, -- [none]
+ { {".+"}, {"abcd",2}, {2,4,{}} }, -- positive st
+ { {".+"}, {"abcd",-2}, {3,4,{}} }, -- negative st
+ { {".*"}, {"abcd"}, {1,4,{}} }, -- [none]
+ { {"bc"}, {"abc"}, {2,3,{}} }, -- [none]
+ { {"(.)b.(d)"}, {"abcd"}, {1,4,{"a","d"}}},--[captures]
+ }
+end
+
+local function set_m_find (lib, flg)
+ return {
+ Name = "Method find",
+ Method = "find",
+ --{patt}, {subj, st} { results }
+ { {".+"}, {"abcd"}, {1,4} }, -- [none]
+ { {".+"}, {"abcd",2}, {2,4} }, -- positive st
+ { {".+"}, {"abcd",-2}, {3,4} }, -- negative st
+ { {".*"}, {"abcd"}, {1,4} }, -- [none]
+ { {"bc"}, {"abc"}, {2,3} }, -- [none]
+ { {"(.)b.(d)"}, {"abcd"}, {1,4,"a","d"}},--[captures]
+ }
+end
+
+local function set_m_match (lib, flg)
+ return {
+ Name = "Method match",
+ Method = "match",
+ --{patt}, {subj, st} { results }
+ { {".+"}, {"abcd"}, {"abcd"} }, -- [none]
+ { {".+"}, {"abcd",2}, {"bcd" } }, -- positive st
+ { {".+"}, {"abcd",-2}, {"cd" } }, -- negative st
+ { {".*"}, {"abcd"}, {"abcd"} }, -- [none]
+ { {"bc"}, {"abc"}, {"bc" } }, -- [none]
+ {{ "(.)b.(d)"}, {"abcd"}, {"a","d"} }, --[captures]
+ }
+end
+
+local function set_f_gsub1 (lib, flg)
+ local subj, pat = "abcdef", "[abef]+"
+ local cpat = lib.new(pat)
+ return {
+ Name = "Function gsub, set1",
+ Func = get_gsub (lib),
+ --{ s, p, f, n, res1, res2, res3 },
+ { {subj, cpat, "", 0}, {subj, 0, 0} }, -- test "n" + empty_replace
+ { {subj, pat, "", 0}, {subj, 0, 0} }, -- test "n" + empty_replace
+ { {subj, pat, "", -1}, {subj, 0, 0} }, -- test "n" + empty_replace
+ { {subj, pat, "", 1}, {"cdef", 1, 1} },
+ { {subj, pat, "", 2}, {"cd", 2, 2} },
+ { {subj, pat, "", 3}, {"cd", 2, 2} },
+ { {subj, pat, "" }, {"cd", 2, 2} },
+ { {subj, pat, "#", 0}, {subj, 0, 0} }, -- test "n" + non-empty_replace
+ { {subj, pat, "#", 1}, {"#cdef", 1, 1} },
+ { {subj, pat, "#", 2}, {"#cd#", 2, 2} },
+ { {subj, pat, "#", 3}, {"#cd#", 2, 2} },
+ { {subj, pat, "#" }, {"#cd#", 2, 2} },
+ { {"abc", "^.", "#" }, {"#bc", 1, 1} }, -- anchored pattern
+ }
+end
+
+local function set_f_gsub2 (lib, flg)
+ local subj, pat = "abc", "([ac])"
+ return {
+ Name = "Function gsub, set2",
+ Func = get_gsub (lib),
+ --{ s, p, f, n, res1, res2, res3 },
+ { {subj, pat, "<%1>" }, {"<a>b<c>", 2, 2} }, -- test non-escaped chars in f
+ { {subj, pat, "%<%1%>" }, {"<a>b<c>", 2, 2} }, -- test escaped chars in f
+ { {subj, pat, "" }, {"b", 2, 2} }, -- test empty replace
+ { {subj, pat, "1" }, {"1b1", 2, 2} }, -- test odd and even %'s in f
+ { {subj, pat, "%1" }, {"abc", 2, 2} },
+ { {subj, pat, "%%1" }, {"%1b%1", 2, 2} },
+ { {subj, pat, "%%%1" }, {"%ab%c", 2, 2} },
+ { {subj, pat, "%%%%1" }, {"%%1b%%1", 2, 2} },
+ { {subj, pat, "%%%%%1" }, {"%%ab%%c", 2, 2} },
+ }
+end
+
+local function set_f_gsub3 (lib, flg)
+ return {
+ Name = "Function gsub, set3",
+ Func = get_gsub (lib),
+ --{ s, p, f, n, res1,res2,res3 },
+ { {"abc", "a", "%0" }, {"abc", 1, 1} }, -- test (in)valid capture index
+ { {"abc", "a", "%1" }, {"abc", 1, 1} },
+ { {"abc", "[ac]", "%1" }, {"abc", 2, 2} },
+ { {"abc", "(a)", "%1" }, {"abc", 1, 1} },
+ { {"abc", "(a)", "%2" }, "invalid capture index" },
+ }
+end
+
+local function set_f_gsub4 (lib, flg)
+ return {
+ Name = "Function gsub, set4",
+ Func = get_gsub (lib),
+ --{ s, p, f, n, res1, res2, res3 },
+ { {"a2c3", ".", "#" }, {"####", 4, 4} }, -- test .
+ { {"a2c3", ".+", "#" }, {"#", 1, 1} }, -- test .+
+ { {"a2c3", ".*", "#" }, {"##", 2, 2} }, -- test .*
+ { {"/* */ */", "\\/\\*(.*)\\*\\/", "#" }, {"#", 1, 1} },
+ { {"a2c3", "[0-9]", "#" }, {"a#c#", 2, 2} }, -- test %d
+ { {"a2c3", "[^0-9]", "#" }, {"#2#3", 2, 2} }, -- test %D
+ { {"a \t\nb", "[ \t\n]", "#" }, {"a###b", 3, 3} }, -- test %s
+ { {"a \t\nb", "[^ \t\n]", "#" }, {"# \t\n#", 2, 2} }, -- test %S
+ }
+end
+
+local function set_f_gsub5 (lib, flg)
+ local function frep1 () end -- returns nothing
+ local function frep2 () return "#" end -- ignores arguments
+ local function frep3 (...) return table.concat({...}, ",") end -- "normal"
+ local function frep4 () return {} end -- invalid return type
+ local function frep5 () return "7", "a" end -- 2-nd return is "a"
+ local function frep6 () return "7", "break" end -- 2-nd return is "break"
+ local subj = "a2c3"
+ return {
+ Name = "Function gsub, set5",
+ Func = get_gsub (lib),
+ --{ s, p, f, n, res1, res2, res3 },
+ { {subj, "a(.)c(.)", frep1 }, {subj, 1, 0} },
+ { {subj, "a(.)c(.)", frep2 }, {"#", 1, 1} },
+ { {subj, "a(.)c(.)", frep3 }, {"2,3", 1, 1} },
+ { {subj, "a.c.", frep3 }, {subj, 1, 1} },
+ { {subj, "z*", frep1 }, {subj, 5, 0} },
+ { {subj, "z*", frep2 }, {"#a#2#c#3#", 5, 5} },
+ { {subj, "z*", frep3 }, {subj, 5, 5} },
+ { {subj, subj, frep4 }, "invalid return type" },
+ { {"abc",".", frep5 }, {"777", 3, 3} },
+ { {"abc",".", frep6 }, {"777", 3, 3} },
+ }
+end
+
+local function set_f_gsub6 (lib, flg)
+ local tab1, tab2, tab3 = {}, { ["2"] = 56 }, { ["2"] = {} }
+ local subj = "a2c3"
+ return {
+ Name = "Function gsub, set6",
+ Func = get_gsub (lib),
+ --{ s, p, f, n, res1,res2,res3 },
+ { {subj, "a(.)c(.)", tab1 }, {subj, 1, 0} },
+ { {subj, "a(.)c(.)", tab2 }, {"56", 1, 1} },
+ { {subj, "a(.)c(.)", tab3 }, "invalid replacement type" },
+ { {subj, "a.c.", tab1 }, {subj, 1, 0} },
+ { {subj, "a.c.", tab2 }, {subj, 1, 0} },
+ { {subj, "a.c.", tab3 }, {subj, 1, 0} },
+ }
+end
+
+local function set_f_gsub8 (lib, flg)
+ local subj, patt, repl = "abcdef", "..", "*"
+ return {
+ Name = "Function gsub, set8",
+ Func = get_gsub (lib),
+ --{ s, p, f, n, res1, res2, res3 },
+ { {subj, patt, repl, function() end }, {"abcdef", 3, 0} },
+ { {subj, patt, repl, function() return nil end }, {"abcdef", 3, 0} },
+ { {subj, patt, repl, function() return false end }, {"abcdef", 3, 0} },
+ { {subj, patt, repl, function() return true end }, {"***", 3, 3} },
+ { {subj, patt, repl, function() return {} end }, {"***", 3, 3} },
+ { {subj, patt, repl, function() return "#" end }, {"###", 3, 3} },
+ { {subj, patt, repl, function() return 57 end }, {"575757", 3, 3} },
+ { {subj, patt, repl, function (from) return from end }, {"135", 3, 3} },
+ { {subj, patt, repl, function (from, to) return to end }, {"246", 3, 3} },
+ { {subj, patt, repl, function (from,to,rep) return rep end },
+ {"***", 3, 3} },
+ { {subj, patt, repl, function (from, to, rep) return rep..to..from end },
+ {"*21*43*65", 3, 3} },
+ { {subj, patt, repl, function() return nil end }, {"abcdef", 3, 0} },
+ { {subj, patt, repl, function() return nil, nil end }, {"abcdef", 3, 0} },
+ { {subj, patt, repl, function() return nil, false end }, {"abcdef", 3, 0} },
+ { {subj, patt, repl, function() return nil, true end }, {"ab**", 3, 2} },
+ { {subj, patt, repl, function() return true, true end }, {"***", 3, 3} },
+ { {subj, patt, repl, function() return nil, 0 end }, {"abcdef", 1, 0} },
+ { {subj, patt, repl, function() return true, 0 end }, {"*cdef", 1, 1} },
+ { {subj, patt, repl, function() return nil, 1 end }, {"ab*ef", 2, 1} },
+ { {subj, patt, repl, function() return true, 1 end }, {"**ef", 2, 2} },
+ }
+end
+
+return function (libname, isglobal)
+ local lib = isglobal and _G[libname] or require (libname)
+ return {
+ set_f_gmatch (lib),
+ set_f_split (lib),
+ set_f_find (lib),
+ set_f_match (lib),
+ set_m_exec (lib),
+ set_m_tfind (lib),
+ set_m_find (lib),
+ set_m_match (lib),
+ set_f_gsub1 (lib),
+ set_f_gsub2 (lib),
+ set_f_gsub3 (lib),
+ set_f_gsub4 (lib),
+ set_f_gsub5 (lib),
+ set_f_gsub6 (lib),
+ set_f_gsub8 (lib),
+ }
+end
diff --git a/test/lua/glib_sets.lua b/test/lua/glib_sets.lua
new file mode 100644
index 0000000000..0c3f38a483
--- /dev/null
+++ b/test/lua/glib_sets.lua
@@ -0,0 +1,204 @@
+-- See Copyright Notice in the file LICENSE
+
+local pat2pcre = require "pat2pcre"
+local luatest = require "luatest"
+local N = luatest.NT
+
+local function norm(a) return a==nil and N or a end
+
+local function fill (n, m)
+ local t = {}
+ for i = n, m, -1 do table.insert (t, i) end
+ return t
+end
+
+
+-- glib doesn't do partial matching return of matches, nor
+-- does it support ovecsize being set through the API
+local function set_m_dfa_exec (lib, flg)
+ return {
+ Name = "Method dfa_exec for glib",
+ Method = "dfa_exec",
+--{patt,cf,lo}, {subj,st,ef,os,ws} { results }
+ { {".+"}, {"abcd"}, {1,{4,3,2,1},4} }, -- [none]
+ { {".+"}, {"abcd",2}, {2,{4,3,2}, 3} }, -- positive st
+ { {".+"}, {"abcd",-2}, {3,{4,3}, 2} }, -- negative st
+ { {".+"}, {"abcd",5}, {N } }, -- failing st
+ { {".*"}, {"abcd"}, {1,{4,3,2,1,0},5}}, -- [none]
+ { {".*?"}, {"abcd"}, {1,{4,3,2,1,0},5}}, -- non-greedy
+ { {"aBC",flg.CASELESS}, {"abc"}, {1,{3},1} }, -- cf
+ { {"aBC","i" }, {"abc"}, {1,{3},1} }, -- cf
+ { {"bc"}, {"abc"}, {2,{3},1} }, -- [none]
+ { {"bc",flg.ANCHORED}, {"abc"}, {N } }, -- cf
+ { {"bc"}, {"abc",N, flg.ANCHORED}, {N } }, -- ef
+ { { "(.)b.(d)"}, {"abcd"}, {1,{4},1} }, --[captures]
+ { {"abc"}, {"ab"}, {N } },
+ { {"abc"}, {"abc",N,flg.PARTIAL}, {1,{3},1} },
+ { {"abc*"}, {"abcc",N,flg.PARTIAL}, {1,{4,3,2},3} },
+ { {"abc"}, {"ab",N,flg.PARTIAL}, {true} },
+ { {"bc"}, {"ab",N,flg.PARTIAL}, {true} },
+}
+end
+
+local function get_gsub (lib)
+ return lib.gsub or
+ function (subj, pattern, repl, n)
+ return lib.new (pattern) : gsub (subj, repl, n)
+ end
+end
+
+-- sadly, glib *always* sets the PCRE_UCP compilation flag, regardless
+-- of REGEX_RAW being set - this is, frankly, a bug in my opinion
+-- but anyway, it means things like '[:alpha:]' and '\w' match things that Lua's
+-- '%a' does not match
+local function set_f_gsub7 (lib, flg)
+ local subj = ""
+ for i = 0, 255 do
+ subj = subj .. string.char (i)
+ end
+
+ -- This set requires calling prepare_set before calling gsub_test
+ local set = {
+ Name = "Function gsub, set7 for glib",
+ Func = get_gsub (lib),
+ --{ s, p, f, n, },
+ { {subj, "[a-zA-Z]", "" }, },
+ { {subj, "[^a-zA-Z]", "" }, },
+ { {subj, "%c", "" }, },
+ { {subj, "%C", "" }, },
+ { {subj, "[a-z]", "" }, },
+ { {subj, "[^a-z]", "" }, },
+ { {subj, "%d", "" }, },
+ { {subj, "%D", "" }, },
+ { {subj, "%p", "" }, },
+ { {subj, "%P", "" }, },
+-- { {subj, "%s", "" }, },
+-- { {subj, "%S", "" }, },
+ { {subj, "[A-Z]", "" }, },
+ { {subj, "[^A-Z]", "" }, }, -- 10
+ { {subj, "[a-zA-Z0-9]", "" }, },
+ { {subj, "[^a-zA-Z0-9]", "" }, },
+ { {subj, "%x", "" }, },
+ { {subj, "%X", "" }, },
+ { {subj, "%z", "" }, },
+ { {subj, "%Z", "" }, },
+
+-- { {subj, "[%a]", "" }, },
+-- { {subj, "[%A]", "" }, },
+ { {subj, "[%c]", "" }, },
+ { {subj, "[%C]", "" }, },
+ { {subj, "[%d]", "" }, },
+ { {subj, "[%D]", "" }, },
+-- { {subj, "[%l]", "" }, },
+-- { {subj, "[%L]", "" }, },
+ { {subj, "[%p]", "" }, },
+ { {subj, "[%P]", "" }, },
+-- { {subj, "[%u]", "" }, },
+-- { {subj, "[%U]", "" }, },
+-- { {subj, "[%w]", "" }, },
+-- { {subj, "[%W]", "" }, },
+ { {subj, "[%x]", "" }, },
+ { {subj, "[%X]", "" }, },
+ { {subj, "[%z]", "" }, },
+ { {subj, "[%Z]", "" }, },
+
+-- { {subj, "[%a_]", "" }, },
+-- { {subj, "[%A_]", "" }, },
+ { {subj, "[%c_]", "" }, },
+ { {subj, "[%C_]", "" }, },
+-- { {subj, "[%l_]", "" }, },
+-- { {subj, "[%L_]", "" }, },
+ { {subj, "[%p_]", "" }, },
+ { {subj, "[%P_]", "" }, },
+-- { {subj, "[%u_]", "" }, },
+-- { {subj, "[%U_]", "" }, },
+-- { {subj, "[%w_]", "" }, },
+-- { {subj, "[%W_]", "" }, },
+ { {subj, "[%x_]", "" }, },
+ { {subj, "[%X_]", "" }, },
+ { {subj, "[%z_]", "" }, },
+ { {subj, "[%Z_]", "" }, },
+
+-- { {subj, "[%a%d]", "" }, },
+-- { {subj, "[%A%d]", "" }, },
+ { {subj, "[%c%d]", "" }, },
+ { {subj, "[%C%d]", "" }, },
+-- { {subj, "[%l%d]", "" }, },
+-- { {subj, "[%L%d]", "" }, },
+ { {subj, "[%p%d]", "" }, },
+ { {subj, "[%P%d]", "" }, },
+-- { {subj, "[%u%d]", "" }, },
+-- { {subj, "[%U%d]", "" }, },
+-- { {subj, "[%w%d]", "" }, },
+-- { {subj, "[%W%d]", "" }, },
+ { {subj, "[%x%d]", "" }, },
+ { {subj, "[%X%d]", "" }, },
+ { {subj, "[%z%d]", "" }, },
+ { {subj, "[%Z%d]", "" }, },
+
+-- { {subj, "[^%a%d]", "" }, },
+-- { {subj, "[^%A%d]", "" }, },
+ { {subj, "[^%c%d]", "" }, },
+ { {subj, "[^%C%d]", "" }, },
+-- { {subj, "[^%l%d]", "" }, },
+-- { {subj, "[^%L%d]", "" }, },
+ { {subj, "[^%p%d]", "" }, },
+ { {subj, "[^%P%d]", "" }, },
+-- { {subj, "[^%u%d]", "" }, },
+-- { {subj, "[^%U%d]", "" }, },
+-- { {subj, "[^%w%d]", "" }, },
+-- { {subj, "[^%W%d]", "" }, },
+ { {subj, "[^%x%d]", "" }, },
+ { {subj, "[^%X%d]", "" }, },
+ { {subj, "[^%z%d]", "" }, },
+ { {subj, "[^%Z%d]", "" }, },
+
+-- { {subj, "[^%a_]", "" }, },
+-- { {subj, "[^%A_]", "" }, },
+ { {subj, "[^%c_]", "" }, },
+ { {subj, "[^%C_]", "" }, },
+-- { {subj, "[^%l_]", "" }, },
+-- { {subj, "[^%L_]", "" }, },
+ { {subj, "[^%p_]", "" }, },
+ { {subj, "[^%P_]", "" }, },
+-- { {subj, "[^%u_]", "" }, },
+-- { {subj, "[^%U_]", "" }, },
+-- { {subj, "[^%w_]", "" }, },
+-- { {subj, "[^%W_]", "" }, },
+ { {subj, "[^%x_]", "" }, },
+ { {subj, "[^%X_]", "" }, },
+ { {subj, "[^%z_]", "" }, },
+ { {subj, "[^%Z_]", "" }, },
+
+ { {subj, "\100", "" }, },
+ { {subj, "[\100]", "" }, },
+ { {subj, "[^\100]", "" }, },
+ { {subj, "[\100-\200]", "" }, },
+ { {subj, "[^\100-\200]", "" }, },
+ { {subj, "\100a", "" }, },
+ { {subj, "[\100a]", "" }, },
+ { {subj, "[^\100a]", "" }, },
+ { {subj, "[\100-\200a]", "" }, },
+ { {subj, "[^\100-\200a]", "" }, },
+ }
+ -- fill in reference results
+ for _,v in ipairs(set) do
+ local r0, r1, r2 = pcall (string.gsub, unpack (v[1]))
+ v[2] = r0 and { r1, r2, r2 } or { r0, r1 }
+ end
+ -- convert patterns: lua -> pcre
+ for _, test in ipairs (set) do
+ test[1][2] = pat2pcre (test[1][2])
+ end
+ return set
+end
+
+return function (libname, isglobal)
+ local lib = isglobal and _G[libname] or require (libname)
+ local flags = lib.flags and lib.flags ()
+ local sets = {
+ set_m_dfa_exec (lib, flags),
+ set_f_gsub7 (lib, flags)
+ }
+ return sets
+end
diff --git a/test/lua/gregex.lua b/test/lua/gregex.lua
new file mode 100644
index 0000000000..2ad04ba6dc
--- /dev/null
+++ b/test/lua/gregex.lua
@@ -0,0 +1,285 @@
+
+-- Tests for GLib Regex functions
+-- written by Hadriel Kaplan, based on Lrexlib's test suite
+-- This is a test script for tshark/wireshark.
+-- This script runs inside tshark/wireshark, so to run it do:
+-- tshark -r empty.cap -X lua_script:<path_to_testdir>/lua/gregex.lua -X lua_script1:glib
+--
+-- if you have to give addtional paths to find the dependent lua files,
+-- use the '-X lua_script1:' syntax to add more arguments
+--
+-- available arguments:
+-- -d<dir> provides path directory for lua include files
+-- -v verbose mode
+-- -V very verbose mode
+
+
+-- save args before we do anything else
+local args = {...}
+for i,v in ipairs(args) do
+ print(i.." = "..v)
+end
+
+local function testing(...)
+ print("---- Testing "..tostring(...).." ----")
+end
+
+local count = 0
+
+local function test(name, ...)
+ count = count + 1
+ io.write("test "..name.."-"..count.."...")
+ if (...) == true then
+ io.write("passed\n")
+ io.flush()
+ else
+ io.write("failed!\n")
+ io.flush()
+ error(name.." test failed!")
+ end
+end
+
+------------- First test some basic stuff to make sure we're sane -----------
+
+print("Lua version: ".._VERSION)
+
+testing("Lrexlib GLib Regex library")
+
+local lib = GRegex
+test("global",_G.GRegex == lib)
+
+for name, val in pairs(lib) do
+ print("\t"..name.." = "..type(val))
+end
+
+test("class",type(lib) == 'table')
+test("class",type(lib._VERSION) == 'string')
+test("class",type(lib.find) == 'function')
+test("class",type(lib.compile_flags) == 'function')
+test("class",type(lib.match_flags) == 'function')
+test("class",type(lib.flags) == 'function')
+test("class",type(lib.gsub) == 'function')
+test("class",type(lib.gmatch) == 'function')
+test("class",type(lib.new) == 'function')
+test("class",type(lib.match) == 'function')
+test("class",type(lib.split) == 'function')
+test("class",type(lib.version) == 'function')
+
+testing("info and flags")
+
+test("typeof",typeof(lib) == 'GRegex')
+
+print(lib._VERSION)
+print("Glib version = "..lib.version())
+
+local function getTSize(t)
+ local c = 0
+ for k,v in pairs(t) do
+ -- print(k.." = "..v)
+ c = c + 1
+ end
+ return c
+end
+
+local flags = lib.flags()
+
+-- print("size = "..c)
+-- it's 84 for newer GLib, 61 for older
+test("flags", getTSize(flags) > 60)
+test("cflags", getTSize(lib.compile_flags()) > 15)
+test("eflags", getTSize(lib.match_flags()) > 8)
+
+testing("new")
+
+local results
+local function checkFunc(objname,funcname,...)
+ results = { pcall(objname[funcname],...) }
+ if results[1] then
+ return true
+ end
+ -- print("Got this error: '"..tostring(results[2]).."'")
+ return false
+end
+
+test("new", checkFunc(lib,"new",".*"))
+test("new", checkFunc(lib,"new",""))
+test("new", checkFunc(lib,"new","(hello|world)"))
+
+test("new_err", not checkFunc(lib,"new","*"))
+test("new_err", not checkFunc(lib,"new"))
+test("new_err", not checkFunc(lib,"new","(hello|world"))
+test("new_err", not checkFunc(lib,"new","[0-9"))
+-- invalid compile flag
+test("new_err", not checkFunc(lib,"new","[0-9]",flags.PARTIAL))
+
+
+local val1 = "hello world foo bar"
+local val2 = "hello wORld FOO bar"
+local patt = "hello (world) (.*) bar"
+local rgx = lib.new(patt)
+local rgx2 = lib.new(patt,flags.CASELESS)
+
+testing("typeof")
+test("typeof",typeof(rgx) == 'GRegex')
+test("typeof",typeof(rgx2) == 'GRegex')
+
+testing("match")
+test("match", checkFunc(lib,"match", val1,patt, 1, flags.CASELESS) and results[2] == "world" and results[3] == "foo")
+test("match", checkFunc(lib,"match", val2,patt, 1, flags.CASELESS) and results[2] == "wORld" and results[3] == "FOO")
+test("match", checkFunc(lib,"match", val1,rgx) and results[2] == "world" and results[3] == "foo")
+test("match", checkFunc(rgx,"match", rgx,val1) and results[2] == "world" and results[3] == "foo")
+test("match", checkFunc(rgx2,"match", rgx2,val2, 1) and results[2] == "wORld" and results[3] == "FOO")
+
+-- different offset won't match this pattern
+test("match_err", checkFunc(rgx2,"match", rgx2,val2, 4) and results[2] == nil)
+
+-- invalid compile flag
+test("match_err", not checkFunc(lib,"match", val1,patt, 1, flags.PARTIAL))
+-- invalid match flag
+test("match_err", not checkFunc(rgx,"match", rgx,val1, 1, flags.CASELESS))
+
+testing("find")
+
+test("find", checkFunc(lib,"find", val1,patt) and results[2] == 1 and results[3] == val1:len()
+ and results[4] == "world" and results[5] == "foo")
+test("find", checkFunc(lib,"find", val1,rgx) and results[2] == 1 and results[3] == val1:len()
+ and results[4] == "world" and results[5] == "foo")
+test("find", checkFunc(rgx,"find", rgx,val1) and results[2] == 1 and results[3] == val1:len()
+ and results[4] == "world" and results[5] == "foo")
+
+testing("match")
+
+--checkFunc(rgx,"exec", rgx,val1)
+--print(results[4][3],results[4][4])
+test("exec", checkFunc(rgx,"exec", rgx,val1) and results[2] == 1 and results[3] == val1:len()
+ and results[4][1] == 7 and results[4][2] == 11 and results[4][3] == 13 and results[4][4] == 15)
+
+print("\n----------------------------------------------------------\n")
+
+------- OK, we're sane, so run all the library's real tests ---------
+
+testing("Lrexlib-provided tests")
+
+-- we're not using the "real" lib name
+local GLIBNAME = "GRegex"
+local isglobal = true
+
+do
+ local dir
+ for i = 1, select ("#", ...) do
+ local arg = select (i, ...)
+ --print(arg)
+ if arg:sub(1,2) == "-d" then
+ dir = arg:sub(3)
+ end
+ end
+ dir = dir:gsub("[/\\]+$", "")
+ local path = dir .. "/?.lua;"
+ if package.path:sub(1, #path) ~= path then
+ package.path = path .. package.path
+ end
+end
+
+local luatest = require "luatest"
+
+-- returns: number of failures
+local function test_library (libname, setfile, verbose, really_verbose)
+ if verbose then
+ print (("[lib: %s; file: %s]"):format (libname, setfile))
+ end
+ local lib = isglobal and _G[libname] or require (libname)
+ local f = require (setfile)
+ local sets = f (libname, isglobal)
+
+ local n = 0 -- number of failures
+ for _, set in ipairs (sets) do
+ if verbose then
+ print (set.Name or "Unnamed set")
+ end
+ local err = luatest.test_set (set, lib, really_verbose)
+ if verbose then
+ for _,v in ipairs (err) do
+ print ("\nTest " .. v.i)
+ print (" Expected result:\n "..tostring(v))
+ luatest.print_results (v[1], " ")
+ table.remove(v,1)
+ print ("\n Got:")
+ luatest.print_results (v, " ")
+ end
+ end
+ n = n + #err
+ end
+ if verbose then
+ print ""
+ end
+
+ return n
+end
+
+local avail_tests = {
+ posix = { lib = "rex_posix", "common_sets", "posix_sets" },
+ gnu = { lib = "rex_gnu", "common_sets", "emacs_sets", "gnu_sets" },
+ oniguruma = { lib = "rex_onig", "common_sets", "oniguruma_sets", },
+ pcre = { lib = "rex_pcre", "common_sets", "pcre_sets", "pcre_sets2", },
+ glib = { lib = GLIBNAME, "common_sets", "pcre_sets", "pcre_sets2", "glib_sets" },
+ spencer = { lib = "rex_spencer", "common_sets", "posix_sets", "spencer_sets" },
+ tre = { lib = "rex_tre", "common_sets", "posix_sets", "spencer_sets", --[["tre_sets"]] },
+}
+
+do
+ local verbose, really_verbose, tests, nerr = false, false, {}, 0
+ local dir
+
+ -- check arguments
+ for i = 1, select ("#", ...) do
+ local arg = select (i, ...)
+ --print(arg)
+ if arg:sub(1,1) == "-" then
+ if arg == "-v" then
+ verbose = true
+ elseif arg == "-V" then
+ verbose = true
+ really_verbose = true
+ elseif arg:sub(1,2) == "-d" then
+ dir = arg:sub(3)
+ end
+ else
+ if avail_tests[arg] then
+ tests[#tests+1] = avail_tests[arg]
+ else
+ error ("invalid argument: [" .. arg .. "]")
+ end
+ end
+ end
+ assert (#tests > 0, "no library specified")
+ -- give priority to libraries located in the specified directory
+ if dir and not isglobal then
+ dir = dir:gsub("[/\\]+$", "")
+ for _, ext in ipairs {"dll", "so", "dylib"} do
+ if package.cpath:match ("%?%." .. ext) then
+ local cpath = dir .. "/?." .. ext .. ";"
+ if package.cpath:sub(1, #cpath) ~= cpath then
+ package.cpath = cpath .. package.cpath
+ end
+ break
+ end
+ end
+ end
+ -- do tests
+ for _, test in ipairs (tests) do
+ package.loaded[test.lib] = nil -- to force-reload the tested library
+ for _, setfile in ipairs (test) do
+ nerr = nerr + test_library (test.lib, setfile, verbose, really_verbose)
+ end
+ end
+ print ("Total number of failures: " .. nerr)
+
+ assert(nerr == 0, "Test failed!")
+end
+
+
+
+
+print("\n-----------------------------\n")
+
+print("All tests passed!\n\n")
diff --git a/test/lua/luatest.lua b/test/lua/luatest.lua
new file mode 100755
index 0000000000..617329c9c6
--- /dev/null
+++ b/test/lua/luatest.lua
@@ -0,0 +1,174 @@
+-- See Copyright Notice in the file LICENSE
+
+-- arrays: deep comparison
+local function eq (t1, t2, lut)
+ if t1 == t2 then return true end
+ if type(t1) ~= "table" or type(t2) ~= "table" or #t1 ~= #t2 then
+ return false
+ end
+
+ lut = lut or {} -- look-up table: are these 2 arrays already compared?
+ lut[t1] = lut[t1] or {}
+ if lut[t1][t2] then return true end
+ lut[t2] = lut[t2] or {}
+ lut[t1][t2], lut[t2][t1] = true, true
+
+ for k,v in ipairs (t1) do
+ if not eq (t2[k], v, lut) then return false end -- recursion
+ end
+ return true
+end
+
+-- a "nil GUID", to be used instead of nils in datasets
+local NT = "b5f74fe5-46f4-483a-8321-e58ba2fa0e17"
+
+-- pack vararg in table, replacing nils with "NT" items
+local function packNT (...)
+ local t = {}
+ for i=1, select ("#", ...) do
+ local v = select (i, ...)
+ t[i] = (v == nil) and NT or v
+ end
+ return t
+end
+
+-- unpack table into vararg, replacing "NT" items with nils
+local function unpackNT (t)
+ local len = #t
+ local function unpack_from (i)
+ local v = t[i]
+ if v == NT then v = nil end
+ if i == len then return v end
+ return v, unpack_from (i+1)
+ end
+ if len > 0 then return unpack_from (1) end
+end
+
+-- print results (deep into arrays)
+local function print_results (val, indent, lut)
+ indent = indent or ""
+ lut = lut or {} -- look-up table
+ local str = tostring (val)
+ if type (val) == "table" then
+ if lut[val] then
+ io.write (indent, str, "\n")
+ else
+ lut[val] = true
+ io.write (indent, str, "\n")
+ for i,v in ipairs (val) do
+ print_results (v, " " .. indent, lut) -- recursion
+ end
+ end
+ else
+ io.write (indent, val == NT and "nil" or str, "\n")
+ end
+end
+
+-- returns:
+-- 1) true, if success; false, if failure
+-- 2) test results table or error_message
+local function test_function (test, func)
+ local res
+ local t = packNT (pcall (func, unpackNT (test[1])))
+ if t[1] then
+ table.remove (t, 1)
+ res = t
+ if alien then
+ local subject = test[1][1]
+ local buf = alien.buffer (#subject)
+ if #subject > 0 then
+ alien.memmove (buf:topointer (), subject, #subject)
+ end
+ test[1][1] = buf
+ local t = packNT (pcall (func, unpackNT (test[1])))
+ if t[1] then
+ table.remove (t, 1)
+ res = t
+ else
+ print "alien test failed"
+ res = t[2] --> error_message
+ end
+ end
+ else
+ res = t[2] --> error_message
+ end
+ local how = (type (res) == type (test[2])) and
+ (type (res) == "string" or eq (res, test[2])) -- allow error messages to differ
+ return how, res
+end
+
+-- returns:
+-- 1) true, if success; false, if failure
+-- 2) test results table or error_message
+-- 3) test results table or error_message
+local function test_method (test, constructor, name)
+ local res1, res2
+ local subject = test[2][1]
+ local ok, r = pcall (constructor, unpackNT (test[1]))
+ if ok then
+ local t = packNT (pcall (r[name], r, unpackNT (test[2])))
+ if t[1] then
+ table.remove (t, 1)
+ res1, res2 = t
+ else
+ res1, res2 = 2, t[2] --> 2, error_message
+ end
+ else
+ res1, res2 = 1, r --> 1, error_message
+ end
+ return eq (res1, test[3]), res1, res2
+end
+
+-- returns: a list of failed tests
+local function test_set (set, lib, verbose)
+ local list = {}
+
+ if type (set.Func) == "function" then
+ local func = set.Func
+
+ for i,test in ipairs (set) do
+ if verbose then
+ io.write (" running function test "..i.."...")
+ io.flush ()
+ end
+ local ok, res = test_function (test, func)
+ if not ok then
+ if verbose then io.stdout:write("failed!\n") end
+ table.insert (list, {i=i, test[2], res})
+ elseif verbose then
+ io.write ("passed\n")
+ io.flush ()
+ end
+ end
+
+ elseif type (set.Method) == "string" then
+ for i,test in ipairs (set) do
+ if verbose then
+ io.write (" running method test "..i.."...")
+ io.flush ()
+ end
+ local ok, res1, res2 = test_method (test, lib.new, set.Method)
+ if not ok then
+ if verbose then io.stdout:write("failed!\n") end
+ table.insert (list, {i=i, test[3], res1, res2})
+ elseif verbose then
+ io.write ("passed\n")
+ io.flush ()
+ end
+ end
+
+ else
+ error ("neither set.Func nor set.Method is valid")
+ end
+
+ return list
+end
+
+return {
+ eq = eq,
+ NT = NT,
+ print_results = print_results,
+ test_function = test_function,
+ test_method = test_method,
+ test_set = test_set,
+}
diff --git a/test/lua/pat2pcre.lua b/test/lua/pat2pcre.lua
new file mode 100755
index 0000000000..2d60a443b2
--- /dev/null
+++ b/test/lua/pat2pcre.lua
@@ -0,0 +1,87 @@
+-- See Copyright Notice in the file lrexlib.h
+
+-- Convert Lua regex pattern to its PCRE equivalent.
+
+local t_esc = {
+ a = "[:alpha:]",
+ A = "[:^alpha:]",
+ c = "[:cntrl:]",
+ C = "[:^cntrl:]",
+ d = "[:digit:]",
+ D = "[:^digit:]",
+ l = "[:lower:]",
+ L = "[:^lower:]",
+ p = "[:punct:]",
+ P = "[:^punct:]",
+ s = "[:space:]",
+ S = "[:^space:]",
+ u = "[:upper:]",
+ U = "[:^upper:]",
+ w = "[:alnum:]",
+ W = "[:^alnum:]",
+ x = "[:xdigit:]",
+ X = "[:^xdigit:]",
+ z = "\\x00",
+ Z = "\\x01-\\xFF",
+}
+
+local function rep_normal (ch)
+ assert (ch ~= "b", "\"%b\" subpattern is not supported")
+ assert (ch ~= "0", "invalid capture index")
+ local v = t_esc[ch]
+ return v and ("[" .. v .. "]") or ("\\" .. ch)
+end
+
+local function rep_charclass (ch)
+ return t_esc[ch] or ("\\" .. ch)
+end
+
+function pat2pcre (s)
+ local ind = 0
+
+ local function getc ()
+ ind = ind + 1
+ return string.sub (s, ind, ind)
+ end
+
+ local function getnum ()
+ local num = string.match (s, "^\\(%d%d?%d?)", ind)
+ if num then
+ ind = ind + #num
+ return string.format ("\\x%02X", num)
+ end
+ end
+
+ local out, state = "", "normal"
+ while ind < #s do
+ local ch = getc ()
+ if state == "normal" then
+ if ch == "%" then
+ out = out .. rep_normal (getc ())
+ elseif ch == "-" then
+ out = out .. "*?"
+ elseif ch == "." then
+ out = out .. "\\C"
+ elseif ch == "[" then
+ out = out .. ch
+ state = "charclass"
+ else
+ local num = getnum ()
+ out = num and (out .. num) or (out .. ch)
+ end
+ elseif state == "charclass" then
+ if ch == "%" then
+ out = out .. rep_charclass (getc ())
+ elseif ch == "]" then
+ out = out .. ch
+ state = "normal"
+ else
+ local num = getnum ()
+ out = num and (out .. num) or (out .. ch)
+ end
+ end
+ end
+ return out
+end
+
+return pat2pcre
diff --git a/test/lua/pcre_sets.lua b/test/lua/pcre_sets.lua
new file mode 100755
index 0000000000..d1e50390cc
--- /dev/null
+++ b/test/lua/pcre_sets.lua
@@ -0,0 +1,179 @@
+-- See Copyright Notice in the file lrexlib.h
+
+local luatest = require "luatest"
+local N = luatest.NT
+
+local function norm(a) return a==nil and N or a end
+
+local function fill (n, m)
+ local t = {}
+ for i = n, m, -1 do table.insert (t, i) end
+ return t
+end
+
+local function set_named_subpatterns (lib, flg)
+ return {
+ Name = "Named Subpatterns",
+ Func = function (subj, methodname, patt, name1, name2)
+ local r = lib.new (patt)
+ local _,_,caps = r[methodname] (r, subj)
+ return norm(caps[name1]), norm(caps[name2])
+ end,
+ --{} N.B. subject is always first element
+ { {"abcd", "tfind", "(?P<dog>.)b.(?P<cat>d)", "dog", "cat"}, {"a","d"} },
+ { {"abcd", "exec", "(?P<dog>.)b.(?P<cat>d)", "dog", "cat"}, {"a","d"} },
+ }
+end
+
+local function set_f_find (lib, flg)
+ local cp1251 =
+ "ÀÁÂÃÄŨÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÜÛÚÝÞßàáâãäå¸æçèéêëìíîïðñòóôõö÷øùüûúýþÿ"
+ local loc = "Russian_Russia.1251"
+ return {
+ Name = "Function find",
+ Func = lib.find,
+ --{subj, patt, st,cf,ef,lo}, { results }
+ { {"abcd", ".+", 5}, { N } }, -- failing st
+ { {"abcd", ".*?"}, { 1,0 } }, -- non-greedy
+ { {"abc", "aBC", N,flg.CASELESS}, { 1,3 } }, -- cf
+ { {"abc", "aBC", N,"i" }, { 1,3 } }, -- cf
+ { {"abc", "bc", N,flg.ANCHORED}, { N } }, -- cf
+ { {"abc", "bc", N,N,flg.ANCHORED}, { N } }, -- ef
+--{ {cp1251, "[[:upper:]]+", N,N,N, loc}, { 1,33} }, -- locale
+--{ {cp1251, "[[:lower:]]+", N,N,N, loc}, {34,66} }, -- locale
+}
+end
+
+local function set_f_match (lib, flg)
+ return {
+ Name = "Function match",
+ Func = lib.match,
+ --{subj, patt, st,cf,ef,lo}, { results }
+ { {"abcd", ".+", 5}, { N }}, -- failing st
+ { {"abcd", ".*?"}, { "" }}, -- non-greedy
+ { {"abc", "aBC", N,flg.CASELESS}, {"abc" }}, -- cf
+ { {"abc", "aBC", N,"i" }, {"abc" }}, -- cf
+ { {"abc", "bc", N,flg.ANCHORED}, { N }}, -- cf
+ { {"abc", "bc", N,N,flg.ANCHORED}, { N }}, -- ef
+}
+end
+
+local function set_f_gmatch (lib, flg)
+ -- gmatch (s, p, [cf], [ef])
+ local pCSV = "(^[^,]*)|,([^,]*)"
+ local F = false
+ local function test_gmatch (subj, patt)
+ local out, guard = {}, 10
+ for a, b in lib.gmatch (subj, patt) do
+ table.insert (out, { norm(a), norm(b) })
+ guard = guard - 1
+ if guard == 0 then break end
+ end
+ return unpack (out)
+ end
+ return {
+ Name = "Function gmatch",
+ Func = test_gmatch,
+ --{ subj patt results }
+ { {"a\0c", "." }, {{"a",N},{"\0",N},{"c",N}} },--nuls in subj
+ { {"", pCSV}, {{"",F}} },
+ { {"12", pCSV}, {{"12",F}} },
+ { {",", pCSV}, {{"", F},{F,""}} },
+ { {"12,,45", pCSV}, {{"12",F},{F,""},{F,"45"}} },
+ { {",,12,45,,ab,", pCSV}, {{"",F},{F,""},{F,"12"},{F,"45"},{F,""},{F,"ab"},{F,""}} },
+ }
+end
+
+local function set_f_split (lib, flg)
+ -- split (s, p, [cf], [ef])
+ local function test_split (subj, patt)
+ local out, guard = {}, 10
+ for a, b, c in lib.split (subj, patt) do
+ table.insert (out, { norm(a), norm(b), norm(c) })
+ guard = guard - 1
+ if guard == 0 then break end
+ end
+ return unpack (out)
+ end
+ return {
+ Name = "Function split",
+ Func = test_split,
+ --{ subj patt results }
+ { {"a,\0,c", ","}, {{"a",",",N},{"\0",",",N},{"c",N,N}, } },--nuls in subj
+ { {"ab", "$"}, {{"ab","",N}, {"",N,N}, } },
+ { {"ab", "^|$"}, {{"", "", N}, {"ab","",N}, {"",N,N}, } },
+ { {"ab45ab","(?<=ab).*?"}, {{"ab","",N}, {"45ab","",N},{"",N,N}, } },
+ { {"ab", "\\b"}, {{"", "", N}, {"ab","",N}, {"",N,N}, } },
+ }
+end
+
+local function set_m_exec (lib, flg)
+ return {
+ Name = "Method exec",
+ Method = "exec",
+--{patt,cf,lo}, {subj,st,ef} { results }
+ { {".+"}, {"abcd",5}, { N } }, -- failing st
+ { {".*?"}, {"abcd"}, {1,0,{}} }, -- non-greedy
+ { {"aBC",flg.CASELESS}, {"abc"}, {1,3,{}} }, -- cf
+ { {"aBC","i" }, {"abc"}, {1,3,{}} }, -- cf
+ { {"bc",flg.ANCHORED}, {"abc"}, { N } }, -- cf
+ { {"bc"}, {"abc",N, flg.ANCHORED}, { N } }, -- ef
+}
+end
+
+local function set_m_tfind (lib, flg)
+ return {
+ Name = "Method tfind",
+ Method = "tfind",
+--{patt,cf,lo}, {subj,st,ef} { results }
+ { {".+"}, {"abcd",5}, { N } }, -- failing st
+ { {".*?"}, {"abcd"}, {1,0,{}} }, -- non-greedy
+ { {"aBC",flg.CASELESS}, {"abc"}, {1,3,{}} }, -- cf
+ { {"aBC","i" }, {"abc"}, {1,3,{}} }, -- cf
+ { {"bc",flg.ANCHORED}, {"abc"}, { N } }, -- cf
+ { {"bc"}, {"abc",N, flg.ANCHORED}, { N } }, -- ef
+}
+end
+
+local function set_m_dfa_exec (lib, flg)
+ return {
+ Name = "Method dfa_exec",
+ Method = "dfa_exec",
+--{patt,cf,lo}, {subj,st,ef,os,ws} { results }
+ { {".+"}, {"abcd"}, {1,{4,3,2,1},4} }, -- [none]
+ { {".+"}, {"abcd",2}, {2,{4,3,2}, 3} }, -- positive st
+ { {".+"}, {"abcd",-2}, {3,{4,3}, 2} }, -- negative st
+ { {".+"}, {"abcd",5}, {N } }, -- failing st
+ { {".*"}, {"abcd"}, {1,{4,3,2,1,0},5}}, -- [none]
+ { {".*?"}, {"abcd"}, {1,{4,3,2,1,0},5}}, -- non-greedy
+ { {"aBC",flg.CASELESS}, {"abc"}, {1,{3},1} }, -- cf
+ { {"aBC","i" }, {"abc"}, {1,{3},1} }, -- cf
+ { {"bc"}, {"abc"}, {2,{3},1} }, -- [none]
+ { {"bc",flg.ANCHORED}, {"abc"}, {N } }, -- cf
+ { {"bc"}, {"abc",N, flg.ANCHORED}, {N } }, -- ef
+ { { "(.)b.(d)"}, {"abcd"}, {1,{4},1} }, --[captures]
+ { {"abc"}, {"ab"}, {N } },
+ { {"abc"}, {"ab",N,flg.PARTIAL}, {1,{2},flg.ERROR_PARTIAL} },
+ { {".+"}, {string.rep("a",50),N,N,50,50}, {1, fill(50,26), 0}},-- small ovecsize
+}
+end
+
+return function (libname, isglobal)
+ local lib = isglobal and _G[libname] or require (libname)
+ local flags = lib.flags ()
+ local sets = {
+ set_f_match (lib, flags),
+ set_f_find (lib, flags),
+ set_f_gmatch (lib, flags),
+ set_f_split (lib, flags),
+ set_m_exec (lib, flags),
+ set_m_tfind (lib, flags),
+ }
+ if flags.MAJOR >= 4 then
+ table.insert (sets, set_named_subpatterns (lib, flags))
+ end
+ if flags.MAJOR >= 6 then
+ table.insert (sets, set_m_dfa_exec (lib, flags))
+ end
+ return sets
+end
diff --git a/test/lua/pcre_sets2.lua b/test/lua/pcre_sets2.lua
new file mode 100755
index 0000000000..c0c8d7a5b9
--- /dev/null
+++ b/test/lua/pcre_sets2.lua
@@ -0,0 +1,198 @@
+-- See Copyright Notice in the file LICENSE
+
+local pat2pcre = require "pat2pcre"
+
+local function get_gsub (lib)
+ return lib.gsub or
+ function (subj, pattern, repl, n)
+ return lib.new (pattern) : gsub (subj, repl, n)
+ end
+end
+
+local function set_f_gsub1 (lib, flg)
+ local subj, pat = "abcdef", "[abef]+"
+ return {
+ Name = "Function gsub, set1",
+ Func = get_gsub (lib),
+ --{ s, p, f, n, res1, res2, res3 },
+ { {"a\0c", ".", "#" }, {"###", 3, 3} }, -- subj contains nuls
+ }
+end
+
+local function set_f_gsub4 (lib, flg)
+ local pCSV = "(^[^,]*)|,([^,]*)"
+ local fCSV = function (a,b) return "["..(a or b).."]" end
+ local set = {
+ Name = "Function gsub, set4",
+ Func = get_gsub (lib),
+ --{ s, p, f, n, res1, res2, res3 },
+ { {"/* */ */", "%/%*(.*)%*%/", "#" }, {"#", 1, 1} },
+ { {"a2c3", ".-", "#" }, {"#########", 9, 9} }, -- test .-
+ { {"/**/", "%/%*(.-)%*%/", "#" }, {"#", 1, 1} },
+ { {"/* */ */", "%/%*(.-)%*%/", "#" }, {"# */", 1, 1} },
+ { {"a2c3", "%d", "#" }, {"a#c#", 2, 2} }, -- test %d
+ { {"a2c3", "%D", "#" }, {"#2#3", 2, 2} }, -- test %D
+ { {"a \t\nb", "%s", "#" }, {"a###b", 3, 3} }, -- test %s
+ { {"a \t\nb", "%S", "#" }, {"# \t\n#", 2, 2} }, -- test %S
+ { {"abcd", "\\b", "%1"}, {"abcd", 2, 2} },
+ { {"", pCSV,fCSV}, {"[]", 1, 1} },
+ { {"123", pCSV,fCSV}, {"[123]", 1, 1} },
+ { {",", pCSV,fCSV}, {"[][]", 2, 2} },
+ { {"123,,456", pCSV,fCSV}, {"[123][][456]", 3, 3}},
+ { {",,123,456,,abc,789,", pCSV,fCSV}, {"[][][123][456][][abc][789][]", 8, 8}},
+ }
+ -- convert patterns: lua -> pcre
+ for _, test in ipairs (set) do
+ test[1][2] = pat2pcre (test[1][2])
+ end
+ return set
+end
+
+local function set_f_gsub7 (lib, flg)
+ local subj = ""
+ for i = 0, 255 do
+ subj = subj .. string.char (i)
+ end
+
+ -- This set requires calling prepare_set before calling gsub_test
+ local set = {
+ Name = "Function gsub, set7",
+ Func = get_gsub (lib),
+ --{ s, p, f, n, },
+ { {subj, "%a", "" }, },
+ { {subj, "%A", "" }, },
+ { {subj, "%c", "" }, },
+ { {subj, "%C", "" }, },
+ { {subj, "%l", "" }, },
+ { {subj, "%L", "" }, },
+ { {subj, "%p", "" }, },
+ { {subj, "%P", "" }, },
+ { {subj, "%u", "" }, },
+ { {subj, "%U", "" }, },
+ { {subj, "%w", "" }, },
+ { {subj, "%W", "" }, },
+ { {subj, "%x", "" }, },
+ { {subj, "%X", "" }, },
+ { {subj, "%z", "" }, },
+ { {subj, "%Z", "" }, },
+
+ { {subj, "[%a]", "" }, },
+ { {subj, "[%A]", "" }, },
+ { {subj, "[%c]", "" }, },
+ { {subj, "[%C]", "" }, },
+ { {subj, "[%l]", "" }, },
+ { {subj, "[%L]", "" }, },
+ { {subj, "[%p]", "" }, },
+ { {subj, "[%P]", "" }, },
+ { {subj, "[%u]", "" }, },
+ { {subj, "[%U]", "" }, },
+ { {subj, "[%w]", "" }, },
+ { {subj, "[%W]", "" }, },
+ { {subj, "[%x]", "" }, },
+ { {subj, "[%X]", "" }, },
+ { {subj, "[%z]", "" }, },
+ { {subj, "[%Z]", "" }, },
+
+ { {subj, "[%a_]", "" }, },
+ { {subj, "[%A_]", "" }, },
+ { {subj, "[%c_]", "" }, },
+ { {subj, "[%C_]", "" }, },
+ { {subj, "[%l_]", "" }, },
+ { {subj, "[%L_]", "" }, },
+ { {subj, "[%p_]", "" }, },
+ { {subj, "[%P_]", "" }, },
+ { {subj, "[%u_]", "" }, },
+ { {subj, "[%U_]", "" }, },
+ { {subj, "[%w_]", "" }, },
+ { {subj, "[%W_]", "" }, },
+ { {subj, "[%x_]", "" }, },
+ { {subj, "[%X_]", "" }, },
+ { {subj, "[%z_]", "" }, },
+ { {subj, "[%Z_]", "" }, },
+
+ { {subj, "[%a%d]", "" }, },
+ { {subj, "[%A%d]", "" }, },
+ { {subj, "[%c%d]", "" }, },
+ { {subj, "[%C%d]", "" }, },
+ { {subj, "[%l%d]", "" }, },
+ { {subj, "[%L%d]", "" }, },
+ { {subj, "[%p%d]", "" }, },
+ { {subj, "[%P%d]", "" }, },
+ { {subj, "[%u%d]", "" }, },
+ { {subj, "[%U%d]", "" }, },
+ { {subj, "[%w%d]", "" }, },
+ { {subj, "[%W%d]", "" }, },
+ { {subj, "[%x%d]", "" }, },
+ { {subj, "[%X%d]", "" }, },
+ { {subj, "[%z%d]", "" }, },
+ { {subj, "[%Z%d]", "" }, },
+
+ { {subj, "[^%a%d]", "" }, },
+ { {subj, "[^%A%d]", "" }, },
+ { {subj, "[^%c%d]", "" }, },
+ { {subj, "[^%C%d]", "" }, },
+ { {subj, "[^%l%d]", "" }, },
+ { {subj, "[^%L%d]", "" }, },
+ { {subj, "[^%p%d]", "" }, },
+ { {subj, "[^%P%d]", "" }, },
+ { {subj, "[^%u%d]", "" }, },
+ { {subj, "[^%U%d]", "" }, },
+ { {subj, "[^%w%d]", "" }, },
+ { {subj, "[^%W%d]", "" }, },
+ { {subj, "[^%x%d]", "" }, },
+ { {subj, "[^%X%d]", "" }, },
+ { {subj, "[^%z%d]", "" }, },
+ { {subj, "[^%Z%d]", "" }, },
+
+ { {subj, "[^%a_]", "" }, },
+ { {subj, "[^%A_]", "" }, },
+ { {subj, "[^%c_]", "" }, },
+ { {subj, "[^%C_]", "" }, },
+ { {subj, "[^%l_]", "" }, },
+ { {subj, "[^%L_]", "" }, },
+ { {subj, "[^%p_]", "" }, },
+ { {subj, "[^%P_]", "" }, },
+ { {subj, "[^%u_]", "" }, },
+ { {subj, "[^%U_]", "" }, },
+ { {subj, "[^%w_]", "" }, },
+ { {subj, "[^%W_]", "" }, },
+ { {subj, "[^%x_]", "" }, },
+ { {subj, "[^%X_]", "" }, },
+ { {subj, "[^%z_]", "" }, },
+ { {subj, "[^%Z_]", "" }, },
+
+ { {subj, "\100", "" }, },
+ { {subj, "[\100]", "" }, },
+ { {subj, "[^\100]", "" }, },
+ { {subj, "[\100-\200]", "" }, },
+ { {subj, "[^\100-\200]", "" }, },
+ { {subj, "\100a", "" }, },
+ { {subj, "[\100a]", "" }, },
+ { {subj, "[^\100a]", "" }, },
+ { {subj, "[\100-\200a]", "" }, },
+ { {subj, "[^\100-\200a]", "" }, },
+ }
+ -- fill in reference results
+ for _,v in ipairs(set) do
+ local r0, r1, r2 = pcall (string.gsub, unpack (v[1]))
+ v[2] = r0 and { r1, r2, r2 } or { r0, r1 }
+ end
+ -- convert patterns: lua -> pcre
+ for _, test in ipairs (set) do
+ test[1][2] = pat2pcre (test[1][2])
+ end
+ return set
+end
+
+return function (libname, isglobal)
+ local lib = isglobal and _G[libname] or require (libname)
+ local flags = lib.flags and lib.flags ()
+ local sets = {
+ set_f_gsub1 (lib, flags),
+ set_f_gsub4 (lib, flags),
+ }
+ if flags.MAJOR*100 + flags.MINOR > 405 then
+ table.insert (sets, set_f_gsub7 (lib, flags))
+ end
+ return sets
+end