%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %% -module(re_SUITE). -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, pcre/1,compile_options/1, run_options/1,combined_options/1,replace_autogen/1, global_capture/1,replace_input_types/1,replace_return/1, split_autogen/1,split_options/1,split_specials/1, error_handling/1,pcre_cve_2008_2371/1, pcre_compile_workspace_overflow/1,re_infinite_loop/1, re_backwards_accented/1,opt_dupnames/1,opt_all_names/1,inspect/1, opt_no_start_optimize/1,opt_never_utf/1,opt_ucp/1, match_limit/1,sub_binaries/1,copt/1]). -include_lib("common_test/include/ct.hrl"). -include_lib("kernel/include/file.hrl"). suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap,{minutes,3}}]. all() -> [pcre, compile_options, run_options, combined_options, replace_autogen, global_capture, replace_input_types, replace_return, split_autogen, split_options, split_specials, error_handling, pcre_cve_2008_2371, pcre_compile_workspace_overflow, re_infinite_loop, re_backwards_accented, opt_dupnames, opt_all_names, inspect, opt_no_start_optimize,opt_never_utf,opt_ucp, match_limit, sub_binaries]. groups() -> []. init_per_suite(Config) -> Config. end_per_suite(_Config) -> ok. init_per_group(_GroupName, Config) -> Config. end_per_group(_GroupName, Config) -> Config. %% Run all applicable tests from the PCRE testsuites. pcre(Config) when is_list(Config) -> RootDir = proplists:get_value(data_dir, Config), Res = run_pcre_tests:test(RootDir), 0 = lists:sum([ X || {X,_,_} <- Res ]), {comment,Res}. %% Test all documented compile options. compile_options(Config) when is_list(Config) -> ok = ctest("ABDabcdABCD","abcd",[],true,{match,[{3,4}]}), ok = ctest("ABDabcdABCD","abcd",[anchored],true,nomatch), ok = ctest("ABDabcdABCD",".*abcd",[anchored],true,{match,[{0,7}]}), ok = ctest("ABCabcdABC","ABCD",[],true,nomatch), ok = ctest("ABCabcdABC","ABCD",[caseless],true,{match,[{3,4}]}), ok = ctest("abcdABC\n","ABC$",[],true,{match,[{4,3}]}), ok = ctest("abcdABC\n","ABC$",[dollar_endonly],true,nomatch), ok = ctest("abcdABC\n","ABC.",[],true,nomatch), ok = ctest("abcdABC\n","ABC.",[dotall],true,{match,[{4,4}]}), ok = ctest("abcdABCD","ABC .",[],true,nomatch), ok = ctest("abcdABCD","ABC .",[extended],true,{match,[{4,4}]}), ok = ctest("abcd\nABCD","ABC",[],true,{match,[{5,3}]}), ok = ctest("abcd\nABCD","ABC",[firstline],true,nomatch), ok = ctest("abcd\nABCD","^ABC",[],true,nomatch), ok = ctest("abcd\nABCD","^ABC",[multiline],true,{match,[{5,3}]}), ok = ctest("abcdABCD","(ABC)",[],true,{match,[{4,3},{4,3}]}), ok = ctest("abcdABCD","(ABC)",[no_auto_capture],true,{match,[{4,3}]}), ok = ctest(notused,"(?ABC)|(?DEF)",[],false,notused), ok = ctest("abcdABCD","(?ABC)|(?DEF)",[dupnames],true,{match,[{4,3},{4,3}]}), ok = ctest("abcdABCDabcABCD","abcd.*D",[],true,{match,[{0,15}]}), ok = ctest("abcdABCDabcABCD","abcd.*D",[ungreedy],true,{match,[{0,8}]}), ok = ctest("abcdABCabcABC\nD","abcd.*D",[],true,nomatch), ok = ctest("abcdABCabcABC\nD","abcd.*D",[{newline,cr}],true,{match,[{0,15}]}), ok = ctest("abcdABCabcABC\rD","abcd.*D",[],true,{match,[{0,15}]}), ok = ctest("abcdABCabcABC\rD","abcd.*D",[{newline,lf}],true,{match,[{0,15}]}), ok = ctest("abcdABCabcd\r\n","abcd$",[{newline,lf}],true,nomatch), ok = ctest("abcdABCabcd\r\n","abcd$",[{newline,cr}],true,nomatch), ok = ctest("abcdABCabcd\r\n","abcd$",[{newline,crlf}],true,{match,[{7,4}]}), ok = ctest("abcdABCabcd\r","abcd$",[{newline,crlf}],true,nomatch), ok = ctest("abcdABCabcd\n","abcd$",[{newline,crlf}],true,nomatch), ok = ctest("abcdABCabcd\r\n","abcd$",[{newline,anycrlf}],true,{match,[{7,4}]}), ok = ctest("abcdABCabcd\r","abcd$",[{newline,anycrlf}],true,{match,[{7,4}]}), ok = ctest("abcdABCabcd\n","abcd$",[{newline,anycrlf}],true,{match,[{7,4}]}), ok. %% Test all documented run specific options. run_options(Config) when is_list(Config) -> rtest("ABCabcdABC","abc",[],[],true), rtest("ABCabcdABC","abc",[anchored],[],false), %% Anchored in run overrides unanchored in compilation rtest("ABCabcdABC","abc",[],[anchored],false), rtest("","a?b?",[],[],true), rtest("","a?b?",[],[notempty],false), rtest("abc","^a",[],[],true), rtest("abc","^a",[],[notbol],false), rtest("ab\nc","^a",[multiline],[],true), rtest("ab\nc","^a",[multiline],[notbol],false), rtest("ab\nc","^c",[multiline],[notbol],true), rtest("abc","c$",[],[],true), rtest("abc","c$",[],[noteol],false), rtest("ab\nc","b$",[multiline],[],true), rtest("ab\nc","c$",[multiline],[],true), rtest("ab\nc","b$",[multiline],[noteol],true), rtest("ab\nc","c$",[multiline],[noteol],false), rtest("abc","ab",[],[{offset,0}],true), rtest("abc","ab",[],[{offset,1}],false), rtest("abcdABCabcABC\nD","abcd.*D",[],[],false), rtest("abcdABCabcABC\nD","abcd.*D",[],[{newline,cr}],true), rtest("abcdABCabcABC\rD","abcd.*D",[],[],true), rtest("abcdABCabcABC\rD","abcd.*D",[{newline,cr}],[{newline,lf}],true), rtest("abcdABCabcd\r\n","abcd$",[],[{newline,lf}],false), rtest("abcdABCabcd\r\n","abcd$",[],[{newline,cr}],false), rtest("abcdABCabcd\r\n","abcd$",[],[{newline,crlf}],true), rtest("abcdABCabcd\r","abcd$",[],[{newline,crlf}],false), rtest("abcdABCabcd\n","abcd$",[],[{newline,crlf}],false), rtest("abcdABCabcd\r\n","abcd$",[],[{newline,anycrlf}],true), rtest("abcdABCabcd\r","abcd$",[],[{newline,anycrlf}],true), rtest("abcdABCabcd\n","abcd$",[],[{newline,anycrlf}],true), {ok,MP} = re:compile(".*(abcd).*"), {match,[{0,10},{3,4}]} = re:run("ABCabcdABC",MP,[]), {match,[{0,10},{3,4}]} = re:run("ABCabcdABC",MP,[{capture,all}]), {match,[{0,10},{3,4}]} = re:run("ABCabcdABC",MP,[{capture,all,index}]), {match,["ABCabcdABC","abcd"]} = re:run("ABCabcdABC",MP,[{capture,all,list}]), {match,[<<"ABCabcdABC">>,<<"abcd">>]} = re:run("ABCabcdABC",MP,[{capture,all,binary}]), {match,[{0,10}]} = re:run("ABCabcdABC",MP,[{capture,first}]), {match,[{0,10}]} = re:run("ABCabcdABC",MP,[{capture,first,index}]), ?line {match,["ABCabcdABC"]} = re:run("ABCabcdABC",MP,[{capture,first,list}]), {match,[<<"ABCabcdABC">>]} = re:run("ABCabcdABC",MP,[{capture,first,binary}]), {match,[{3,4}]} = re:run("ABCabcdABC",MP,[{capture,all_but_first}]), {match,[{3,4}]} = re:run("ABCabcdABC",MP,[{capture,all_but_first,index}]), {match,["abcd"]} = re:run("ABCabcdABC",MP,[{capture,all_but_first,list}]), {match,[<<"abcd">>]} = re:run("ABCabcdABC",MP,[{capture,all_but_first,binary}]), match = re:run("ABCabcdABC",MP,[{capture,none}]), match = re:run("ABCabcdABC",MP,[{capture,none,index}]), match = re:run("ABCabcdABC",MP,[{capture,none,list}]), match = re:run("ABCabcdABC",MP,[{capture,none,binary}]), {ok,MP2} = re:compile(".*(?abcd).*"), {match,[{3,4}]} = re:run("ABCabcdABC",MP2,[{capture,[1]}]), {match,[{3,4}]} = re:run("ABCabcdABC",MP2,[{capture,['FOO']}]), {match,[{3,4}]} = re:run("ABCabcdABC",MP2,[{capture,["FOO"]}]), {match,["abcd"]} = re:run("ABCabcdABC",MP2,[{capture,["FOO"],list}]), {match,[<<"abcd">>]} = re:run("ABCabcdABC",MP2,[{capture,["FOO"],binary}]), {match,[{-1,0}]} = re:run("ABCabcdABC",MP2,[{capture,[200]}]), {match,[{-1,0}]} = re:run("ABCabcdABC",MP2,[{capture,['BAR']}]), {match,[""]} = re:run("ABCabcdABC",MP2,[{capture,[200],list}]), {match,[""]} = re:run("ABCabcdABC",MP2,[{capture,['BAR'],list}]), {match,[<<>>]} = re:run("ABCabcdABC",MP2,[{capture,[200],binary}]), {match,[<<>>]} = re:run("ABCabcdABC",MP2,[{capture,['BAR'],binary}]), {ok, MP3} = re:compile(".*((?abdd)|a(..d)).*"), {match,[{0,10},{3,4},{-1,0},{4,3}]} = re:run("ABCabcdABC",MP3,[]), {match,[{0,10},{3,4},{-1,0},{4,3}]} = re:run("ABCabcdABC",MP3,[{capture,all,index}]), {match,[<<"ABCabcdABC">>,<<"abcd">>,<<>>,<<"bcd">>]} = re:run("ABCabcdABC",MP3,[{capture,all,binary}]), {match,["ABCabcdABC","abcd",[],"bcd"]} = re:run("ABCabcdABC",MP3,[{capture,all,list}]), ok. %% Test compile options given directly to run. combined_options(Config) when is_list(Config) -> ok = crtest("ABDabcdABCD","abcd",[],true,{match,[{3,4}]}), ok = crtest("ABDabcdABCD","abcd",[anchored],true,nomatch), ok = crtest("ABDabcdABCD",".*abcd",[anchored],true,{match,[{0,7}]}), ok = crtest("ABCabcdABC","ABCD",[],true,nomatch), ok = crtest("ABCabcdABC","ABCD",[caseless],true,{match,[{3,4}]}), ok = crtest("abcdABC\n","ABC$",[],true,{match,[{4,3}]}), ok = crtest("abcdABC\n","ABC$",[dollar_endonly],true,nomatch), ok = crtest("abcdABC\n","ABC.",[],true,nomatch), ok = crtest("abcdABC\n","ABC.",[dotall],true,{match,[{4,4}]}), ok = crtest("abcdABCD","ABC .",[],true,nomatch), ok = crtest("abcdABCD","ABC .",[extended],true,{match,[{4,4}]}), ok = crtest("abcd\nABCD","ABC",[],true,{match,[{5,3}]}), ok = crtest("abcd\nABCD","ABC",[firstline],true,nomatch), ok = crtest("abcd\nABCD","^ABC",[],true,nomatch), ok = crtest("abcd\nABCD","^ABC",[multiline],true,{match,[{5,3}]}), ok = crtest("abcdABCD","(ABC)",[],true,{match,[{4,3},{4,3}]}), ok = crtest("abcdABCD","(ABC)",[no_auto_capture],true,{match,[{4,3}]}), ok = crtest(notused,"(?ABC)|(?DEF)",[],false,notused), ok = crtest("abcdABCD","(?ABC)|(?DEF)",[dupnames],true,{match,[{4,3},{4,3}]}), ok = crtest("abcdABCDabcABCD","abcd.*D",[],true,{match,[{0,15}]}), ok = crtest("abcdABCDabcABCD","abcd.*D",[ungreedy],true,{match,[{0,8}]}), ok = ctest("abcdABCabcABC\nD","abcd.*D",[],true,nomatch), ok = crtest("abcdABCabcABC\nD","abcd.*D",[{newline,cr}],true,{match,[{0,15}]}), ok = crtest("abcdABCabcABC\rD","abcd.*D",[],true,{match,[{0,15}]}), ok = crtest("abcdABCabcABC\rD","abcd.*D",[{newline,lf}],true,{match,[{0,15}]}), ok = crtest("abcdABCabcd\r\n","abcd$",[{newline,lf}],true,nomatch), ok = crtest("abcdABCabcd\r\n","abcd$",[{newline,cr}],true,nomatch), ok = crtest("abcdABCabcd\r\n","abcd$",[{newline,crlf}],true,{match,[{7,4}]}), ok = crtest("abcdABCabcd\r","abcd$",[{newline,crlf}],true,nomatch), ok = crtest("abcdABCabcd\n","abcd$",[{newline,crlf}],true,nomatch), ok = crtest("abcdABCabcd\r\n","abcd$",[{newline,anycrlf}],true,{match,[{7,4}]}), ok = crtest("abcdABCabcd\r","abcd$",[{newline,anycrlf}],true,{match,[{7,4}]}), ok = crtest("abcdABCabcd\n","abcd$",[{newline,anycrlf}],true,{match,[{7,4}]}), ok = crtest("abcdABCabcd\r\n","abcd$",[{newline,anycrlf},{capture,all,list}],true,{match,["abcd"]}), ok = crtest("abcdABCabcd\r","abcd$",[{newline,anycrlf},{capture,all,list}],true,{match,["abcd"]}), ok = crtest("abcdABCabcd\n","abcd$",[{newline,anycrlf},{capture,all,list}],true,{match,["abcd"]}), ok = crtest("abcdABCabcd\r\n","abcd$",[{newline,anycrlf},{capture,all,binary}],true,{match,[<<"abcd">>]}), ok = crtest("abcdABCabcd\r","abcd$",[{newline,anycrlf},{capture,all,binary}],true,{match,[<<"abcd">>]}), ok = crtest("abcdABCabcd\n","abcd$",[{newline,anycrlf},{capture,all,binary}],true,{match,[<<"abcd">>]}), %% Check that unique run-options fail in compile only case: {'EXIT',{badarg,_}} = (catch re:compile("abcd$",[{newline,anycrlf},{capture,all,binary}])), {'EXIT',{badarg,_}} = (catch re:compile("abcd$",[{newline,anycrlf},{offset,3}])), {'EXIT',{badarg,_}} = (catch re:compile("abcd$",[{newline,anycrlf},notempty])), {'EXIT',{badarg,_}} = (catch re:compile("abcd$",[{newline,anycrlf},notbol])), {'EXIT',{badarg,_}} = (catch re:compile("abcd$",[{newline,anycrlf},noteol])), {match,_} = re:run("abcdABCabcd\r\n","abcd$",[{newline,crlf}]), nomatch = re:run("abcdABCabcd\r\nefgh","abcd$",[{newline,crlf}]), {match,_} = re:run("abcdABCabcd\r\nefgh","abcd$",[{newline,crlf},multiline]), nomatch = re:run("abcdABCabcd\r\nefgh","efgh$",[{newline,crlf},multiline,noteol]), {match,_} = re:run("abcdABCabcd\r\nefgh","abcd$",[{newline,crlf},multiline,noteol]), {match,_} = re:run("abcdABCabcd\r\nefgh","^abcd",[{newline,crlf},multiline,noteol]), nomatch = re:run("abcdABCabcd\r\nefgh","^abcd",[{newline,crlf},multiline,notbol]), {match,_} = re:run("abcdABCabcd\r\nefgh","^efgh",[{newline,crlf},multiline,notbol]), {match,_} = re:run("ABC\nD","[a-z]*",[{newline,crlf}]), nomatch = re:run("ABC\nD","[a-z]*",[{newline,crlf},notempty]), ok. %% Test replace with autogenerated erlang module. replace_autogen(Config) when is_list(Config) -> re_testoutput1_replacement_test:run(), ok. %% Test capture options together with global searching. global_capture(Config) when is_list(Config) -> {match,[{3,4}]} = re:run("ABCabcdABC",".*(?abcd).*",[{capture,[1]}]), {match,[{10,4}]} = re:run("ABCabcdABCabcdA",".*(?abcd).*",[{capture,[1]}]), {match,[[{10,4}]]} = re:run("ABCabcdABCabcdA",".*(?abcd).*",[global,{capture,[1]}]), {match,[{3,4}]} = re:run("ABCabcdABC",".*(?abcd).*",[{capture,['FOO']}]), {match,[{10,4}]} = re:run("ABCabcdABCabcdA",".*(?abcd).*",[{capture,['FOO']}]), {match,[[{10,4}]]} = re:run("ABCabcdABCabcdA",".*(?abcd).*",[global,{capture,['FOO']}]), {match,[[{3,4},{3,4}],[{10,4},{10,4}]]} = re:run("ABCabcdABCabcdA","(?abcd)",[global]), {match,[[{3,4},{3,4}],[{10,4},{10,4}]]} = re:run("ABCabcdABCabcdA","(?abcd)",[global,{capture,all}]), {match,[[{3,4},{3,4}],[{10,4},{10,4}]]} = re:run("ABCabcdABCabcdA","(?abcd)",[global,{capture,all,index}]), {match,[[{3,4}],[{10,4}]]} = re:run("ABCabcdABCabcdA","(?abcd)",[global,{capture,first}]), {match,[[{3,4}],[{10,4}]]} = re:run("ABCabcdABCabcdA","(?abcd)",[global,{capture,all_but_first}]), {match,[[<<"bcd">>],[<<"bcd">>]]} = re:run("ABCabcdABCabcdA","a(?bcd)",[global,{capture,all_but_first,binary}]), {match,[["bcd"],["bcd"]]} = re:run("ABCabcdABCabcdA","a(?bcd)",[global,{capture,all_but_first,list}]), {match,[["abcd","bcd"],["abcd","bcd"]]} = re:run("ABCabcdABCabcdA","a(?bcd)",[global,{capture,all,list}]), {match,[[<<"abcd">>,<<"bcd">>],[<<"abcd">>,<<"bcd">>]]} = re:run("ABCabcdABCabcdA","a(?bcd)",[global,{capture,all,binary}]), {match,[[{3,4},{4,3}],[{10,4},{11,3}]]} = re:run("ABCabcdABCabcdA","a(?bcd)",[global,{capture,all,index}]), match = re:run("ABCabcdABCabcdA","a(?bcd)",[global,{capture,none,index}]), match = re:run("ABCabcdABCabcdA","a(?bcd)",[global,{capture,none,binary}]), match = re:run("ABCabcdABCabcdA","a(?bcd)",[global,{capture,none,list}]), {match,[[<<195,133,98,99,100>>,<<"bcd">>],[<<"abcd">>,<<"bcd">>]]} = re:run("ABCÅbcdABCabcdA",".(?bcd)",[global,{capture,all,binary},unicode]), {match,[["Åbcd","bcd"],["abcd","bcd"]]} = re:run(<<"ABC",8#303,8#205,"bcdABCabcdA">>,".(?bcd)",[global,{capture,all,list},unicode]), {match,[["Åbcd","bcd"],["abcd","bcd"]]} = re:run("ABCÅbcdABCabcdA",".(?bcd)",[global,{capture,all,list},unicode]), {match,[[{3,5},{5,3}],[{11,4},{12,3}]]} = re:run("ABCÅbcdABCabcdA",".(?bcd)",[global,{capture,all,index},unicode]), ok. %% Test replace with different input types. replace_input_types(Config) when is_list(Config) -> <<"abcd">> = re:replace("abcd","Z","X",[{return,binary},unicode]), <<"abcd">> = re:replace("abcd","\x{400}","X",[{return,binary},unicode]), <<"a",208,128,"cd">> = re:replace(<<"abcd">>,"b","\x{400}",[{return,binary},unicode]), ok. %% Test return options of replace together with global searching. replace_return(Config) when is_list(Config) -> {'EXIT',{badarg,_}} = (catch re:replace("na","(a","")), ok = replacetest(<<"nisse">>,"i","a",[{return,binary}],<<"nasse">>), ok = replacetest("ABC\305abcdABCabcdA","a(?bcd)","X",[global,{return,binary}],<<"ABCÅXABCXA">>), ok = replacetest("ABCÅabcdABCabcdA","a(?bcd)","X",[global,{return,iodata}],[<<"ABCÅ">>,<<"X">>,<<"ABC">>,<<"X">>|<<"A">>]), ok = replacetest("ABCÅabcdABCabcdA","a(?bcd)","X",[global,{return,list},unicode],"ABCÅXABCXA"), ok = replacetest("ABCÅabcdABCabcdA","a(?bcd)","X",[global,{return,binary},unicode],<<65,66,67,195,133,88,65,66,67,88,65>>), ok = replacetest("ABCÅabcdABCabcdA","a(?bcd)","X",[{return,binary},unicode],<<65,66,67,195,133,88,65,66,67,97,98,99,100,65>>), ok = replacetest("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\9X",[{return,binary}],<<"iXk">>), ok = replacetest("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\10X",[{return,binary}],<<"jXk">>), ok = replacetest("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\11X",[{return,binary}],<<"Xk">>), ok = replacetest("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g9X",[{return,binary}],<<"9X1">>), ok = replacetest("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g10X",[{return,binary}],<<"0X1">>), ok = replacetest("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g11X",[{return,binary}],<<"X1">>), ok = replacetest("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g{9}7",[{return,binary}],<<"971">>), ok = replacetest("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g{10}7",[{return,binary}],<<"071">>), ok = replacetest("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g{11}7",[{return,binary}],<<"71">>), ok = replacetest("a\x{400}bcd","d","X",[global,{return,list},unicode],"a\x{400}bcX"), ok = replacetest("a\x{400}bcd","d","X",[global,{return,binary},unicode],<<"a",208,128,"bcX">>), ok = replacetest("a\x{400}bcd","Z","X",[global,{return,list},unicode],"a\x{400}bcd"), ok = replacetest("a\x{400}bcd","Z","X",[global,{return,binary},unicode],<<"a",208,128,"bcd">>), ok. rtest(Subj, RE, Copt, Ropt, true) -> {ok,MP} = re:compile(RE,Copt), {match,_} = re:run(Subj,MP,Ropt), ok; rtest(Subj, RE, Copt, Ropt, false) -> {ok,MP} = re:compile(RE,Copt), nomatch = re:run(Subj,MP,Ropt), ok. ctest(_,RE,Options,false,_) -> case re:compile(RE,Options) of {ok,_} -> error; {error,_} -> ok end; ctest(Subject,RE,Options,true,Result) -> try {ok, Prog} = re:compile(RE,Options), Result = re:run(Subject,Prog,[]), ok catch _:_ -> error end. crtest(_,RE,Options,false,_) -> case (catch re:run("",RE,Options)) of {'EXIT',{badarg,_}} -> ok; _ -> error end; crtest(Subject,RE,Options,true,Result) -> try Result = re:run(Subject,RE,Options), ok catch _:_ -> error end. replacetest(Subject,RE,Replacement,Options,Result) -> Result = re:replace(Subject,RE,Replacement,Options), {CompileOptions,ReplaceOptions} = lists:partition(fun copt/1, Options), {ok,MP} = re:compile(RE,CompileOptions), Result = re:replace(Subject,MP,Replacement,ReplaceOptions), ok. splittest(Subject,RE,Options,Result) -> Result = re:split(Subject,RE,Options), {CompileOptions,SplitOptions} = lists:partition(fun copt/1, Options), {ok,MP} = re:compile(RE,CompileOptions), Result = re:split(Subject,MP,SplitOptions), ok. copt(caseless) -> true; copt(no_start_optimize) -> true; copt(never_utf) -> true; copt(ucp) -> true; copt(dollar_endonly) -> true; copt(dotall) -> true; copt(extended) -> true; copt(firstline) -> true; copt(multiline) -> true; copt(no_auto_capture) -> true; copt(dupnames) -> true; copt(ungreedy) -> true; copt(unicode) -> true; copt(_) -> false. %% Test split with autogenerated erlang module. split_autogen(Config) when is_list(Config) -> re_testoutput1_split_test:run(), ok. %% Test special options to split. split_options(Config) when is_list(Config) -> ok = splittest("a b c ","( )",[group,trim],[[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>]]), ok = splittest("a b c ","( )",[group,{parts,0}],[[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>]]), ok = splittest("a b c ","( )",[{parts,infinity},group],[[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<>>]]), ok = splittest("a b c ","( )",[group],[[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<>>]]), ok = splittest(" a b c d ","( +)",[group,trim],[[<<>>,<<" ">>],[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<"d">>,<<" ">>]]), ok = splittest(" a b c d ","( +)",[{parts,0},group],[[<<>>,<<" ">>],[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<"d">>,<<" ">>]]), ok = splittest(" a b c d ","( +)",[{parts,infinity},group],[[<<>>,<<" ">>],[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<"d">>,<<" ">>],[<<>>]]), ok = splittest("a b c d","( +)",[{parts,2},group],[[<<"a">>,<<" ">>],[<<"b c d">>]]), ok = splittest([967]++" b c d","( +)",[{parts,2},group,{return,list},unicode],[[[967]," "],["b c d"]]), ok = splittest([967]++" b c d","( +)",[{parts,2},group,{return,binary},unicode],[[<<207,135>>,<<" ">>],[<<"b c d">>]]), {'EXIT',{badarg,_}} = (catch re:split([967]++" b c d","( +)",[{parts,2},group,{return,binary}])), {'EXIT',{badarg,_}} = (catch re:split("a b c d","( +)",[{parts,-2}])), {'EXIT',{badarg,_}} = (catch re:split("a b c d","( +)",[{parts,banan}])), {'EXIT',{badarg,_}} = (catch re:split("a b c d","( +)",[{capture,all}])), {'EXIT',{badarg,_}} = (catch re:split("a b c d","( +)",[{capture,[],binary}])), %% Parts 0 is equal to no parts specification (implicit strip) ok = splittest("a b c d","( *)",[{parts,0},{return,list}],["a"," ","b"," ","c"," ","d"]), ok. join([]) -> []; join([A]) -> [A]; join([H|T]) -> [H,<<":">>|join(T)]. %% Some special cases of split that are easy to get wrong. split_specials(Config) when is_list(Config) -> %% More or less just to remember these icky cases <<"::abd:f">> = iolist_to_binary(join(re:split("abdf","^(?!(ab)de|x)(abd)(f)",[trim]))), <<":abc2xyzabc3">> = iolist_to_binary(join(re:split("abc1abc2xyzabc3","\\Aabc.",[trim]))), ok. %% Test that errors are handled correctly by the erlang code. error_handling(_Config) -> case test_server:is_native(re) of true -> %% Exceptions from native code look too different. {skip,"re is native"}; false -> error_handling() end. error_handling() -> %% This test checks the exception tuples manufactured in the erlang %% code to hide the trapping from the user at least when it comes to errors %% The malformed precomiled RE is detected after %% the trap to re:grun from grun, in the grun function clause %% that handles precompiled expressions {'EXIT',{badarg,[{re,run,["apa",{1,2,3,4},[global]],_}, {?MODULE,error_handling,0,_} | _]}} = (catch re:run("apa",{1,2,3,4},[global])), %% An invalid capture list will also cause a badarg late, %% but with a non pre compiled RE, the exception should be thrown by the %% grun function clause that handles RE's compiled implicitly by %% the run/3 BIF before trapping. {'EXIT',{badarg,[{re,run,["apa","p",[{capture,[1,{a}]},global]],_}, {?MODULE,error_handling,0,_} | _]}} = (catch re:run("apa","p",[{capture,[1,{a}]},global])), %% And so the case of a precompiled expression together with %% a compile-option (binary and list subject): {ok,RE} = re:compile("(p)"), {match,[[{1,1},{1,1}]]} = re:run(<<"apa">>,RE,[global]), {match,[[{1,1},{1,1}]]} = re:run("apa",RE,[global]), {'EXIT',{badarg,[{re,run, [<<"apa">>, {re_pattern,1,0,_,_}, [global,unicode]],_}, {?MODULE,error_handling,0,_} | _]}} = (catch re:run(<<"apa">>,RE,[global,unicode])), {'EXIT',{badarg,[{re,run, ["apa", {re_pattern,1,0,_,_}, [global,unicode]],_}, {?MODULE,error_handling,0,_} | _]}} = (catch re:run("apa",RE,[global,unicode])), {'EXIT',{badarg,_}} = (catch re:run("apa","(p",[])), {error, {compile, {_,_}}} = re:run("apa","(p",[report_errors]), {'EXIT',{badarg,_}} = (catch re:run("apa","(p",[global])), {error, {compile, {_,_}}} = re:run("apa","(p",[report_errors,global]), %% Badly formed options {'EXIT',{badarg,_}} = (catch re:run(<<"apa">>,RE,["global"])), {'EXIT',{badarg,_}} = (catch re:run(<<"apa">>,RE,[{offset,-1}])), {'EXIT',{badarg,_}} = (catch re:run(<<"apa">>,RE,[{offset,ett}])), {'EXIT',{badarg,_}} = (catch re:run(<<"apa">>,RE,[{captore,[1,2],binary}])), {'EXIT',{badarg,_}} = (catch re:run(<<"apa">>,RE,[{capture,[1,2],binary,list}])), {'EXIT',{badarg,_}} = (catch re:run(<<"apa">>,RE,[{capture,[1,2],bunary}])), {'EXIT',{badarg,_}} = (catch re:run(<<"apa">>,RE,[{capture,{1,2},binary}])), {'EXIT',{badarg,_}} = (catch re:run(<<"apa">>,RE,[{newline,3}])), {'EXIT',{badarg,_}} = (catch re:run(<<"apa">>,RE,[{newline,apa}])), {'EXIT',{badarg,_}} = (catch re:run(<<"apa">>,RE,[{njuline,cr}])), {'EXIT',{badarg,_}} = (catch re:run(<<"apa">>,RE,[{<<"newline">>,cr}])), {'EXIT',{badarg,_}} = (catch re:run(<<"apa">>,RE,[global|dupnames])), {'EXIT',{badarg,_}} = (catch re:run([<<"ap">>|$a],RE,[])), % Not an IO-list {'EXIT',{badarg,_}} = (catch re:compile([<<"ap">>|$a],[])), % Not an IO-list {'EXIT',{badarg,_}} = (catch re:run(<<"apa">>,RE,[{capture,[0|1],binary}])), {'EXIT',{badarg,_}} = (catch re:run(<<"apa">>,RE, [{capture,[<<"apa">>|1],binary}])), {'EXIT',{badarg,_}} = (catch re:run(<<"apa">>,RE, [{capture,[[<<"ap">>|$a]],binary}])), {'EXIT',{badarg,_}} = (catch re:run(<<"apa">>,[<<"(p">>|41],[])), {'EXIT',{badarg,_}} = (catch re:run(<<"apa">>,{re_pattern,3,0,0,[]},[])), {'EXIT',{badarg,_}} = (catch re:run(<<"apa">>,{re_pattern,3,0,0,<<"apa">>},[])), {'EXIT',{badarg,_}} = (catch re:run(<<"apa">>,{re_pattern,3,0,0,<<"apa",3:2>>},[])), {'EXIT',{badarg,_}} = (catch re:run(<<"apa",2:2>>,<<"(p)">>,[{capture,[0,1],binary}])), <<_:4,Temp:3/binary,_:4>> = <<38,23,6,18>>, {match,[{1,1},{1,1}]} = re:run(Temp,<<"(p)">>,[]), % Unaligned works %% The replace errors: {'EXIT',{badarg,[{re,replace,["apa",{1,2,3,4},"X",[]],_}, {?MODULE,error_handling,0,_} | _]}} = (catch re:replace("apa",{1,2,3,4},"X",[])), {'EXIT',{badarg,[{re,replace,["apa",{1,2,3,4},"X",[global]],_}, {?MODULE,error_handling,0,_} | _]}} = (catch re:replace("apa",{1,2,3,4},"X",[global])), {'EXIT',{badarg,[{re,replace, ["apa", {re_pattern,1,0,_,_}, "X", [unicode]],_}, {?MODULE,error_handling,0,_} | _]}} = (catch re:replace("apa",RE,"X",[unicode])), <<"aXa">> = iolist_to_binary(re:replace("apa","p","X",[])), {'EXIT',{badarg,[{re,replace, ["apa","p","X",[report_errors]],_}, {?MODULE,error_handling,0,_} | _]}} = (catch iolist_to_binary(re:replace("apa","p","X", [report_errors]))), {'EXIT',{badarg,[{re,replace, ["apa","p","X",[{capture,all,binary}]],_}, {?MODULE,error_handling,0,_} | _]}} = (catch iolist_to_binary(re:replace("apa","p","X", [{capture,all,binary}]))), {'EXIT',{badarg,[{re,replace, ["apa","p","X",[{capture,all}]],_}, {?MODULE,error_handling,0,_} | _]}} = (catch iolist_to_binary(re:replace("apa","p","X", [{capture,all}]))), {'EXIT',{badarg,[{re,replace, ["apa","p","X",[{return,banana}]],_}, {?MODULE,error_handling,0,_} | _]}} = (catch iolist_to_binary(re:replace("apa","p","X", [{return,banana}]))), {'EXIT',{badarg,_}} = (catch re:replace("apa","(p","X",[])), %% Badarg, not compile error. {'EXIT',{badarg,[{re,replace, ["apa","(p","X",[{return,banana}]],_}, {?MODULE,error_handling,0,_} | _]}} = (catch iolist_to_binary(re:replace("apa","(p","X", [{return,banana}]))), %% And the split errors: [<<"a">>,<<"a">>] = (catch re:split("apa","p",[])), [<<"a">>,<<"p">>,<<"a">>] = (catch re:split("apa",RE,[])), {'EXIT',{badarg,[{re,split,["apa","p",[report_errors]],_}, {?MODULE,error_handling,0,_} | _]}} = (catch re:split("apa","p",[report_errors])), {'EXIT',{badarg,[{re,split,["apa","p",[global]],_}, {?MODULE,error_handling,0,_} | _]}} = (catch re:split("apa","p",[global])), {'EXIT',{badarg,[{re,split,["apa","p",[{capture,all}]],_}, {?MODULE,error_handling,0,_} | _]}} = (catch re:split("apa","p",[{capture,all}])), {'EXIT',{badarg,[{re,split,["apa","p",[{capture,all,binary}]],_}, {?MODULE, error_handling,0,_} | _]}} = (catch re:split("apa","p",[{capture,all,binary}])), {'EXIT',{badarg,[{re,split,["apa",{1,2,3,4},[]],_}, {?MODULE,error_handling,0,_} | _]}} = (catch re:split("apa",{1,2,3,4})), {'EXIT',{badarg,[{re,split,["apa",{1,2,3,4},[]],_}, {?MODULE,error_handling,0,_} | _]}} = (catch re:split("apa",{1,2,3,4},[])), {'EXIT',{badarg,[{re,split, ["apa", RE, [unicode]],_}, {?MODULE,error_handling,0,_} | _]}} = (catch re:split("apa",RE,[unicode])), {'EXIT',{badarg,[{re,split, ["apa", RE, [{return,banana}]],_}, {?MODULE,error_handling,0,_} | _]}} = (catch re:split("apa",RE,[{return,banana}])), {'EXIT',{badarg,[{re,split, ["apa", RE, [banana]],_}, {?MODULE,error_handling,0,_} | _]}} = (catch re:split("apa",RE,[banana])), {'EXIT',{badarg,_}} = (catch re:split("apa","(p")), %%Exception on bad argument, not compilation error {'EXIT',{badarg,[{re,split, ["apa", "(p", [banana]],_}, {?MODULE,error_handling,0,_} | _]}} = (catch re:split("apa","(p",[banana])), ok. %% Fix as in http://vcs.pcre.org/viewvc?revision=360&view=revision pcre_cve_2008_2371(Config) when is_list(Config) -> %% Make sure it doesn't crash the emulator. re:compile(<<"(?i)[\xc3\xa9\xc3\xbd]|[\xc3\xa9\xc3\xbdA]">>, [unicode]), ok. %% Patch from %% http://vcs.pcre.org/viewvc/code/trunk/pcre_compile.c?r1=504&r2=505&view=patch pcre_compile_workspace_overflow(Config) when is_list(Config) -> N = 819, {error,{"internal error: overran compiling workspace",799}} = re:compile([lists:duplicate(N, $(), lists:duplicate(N, $))]), ok. %% Make sure matches that really loop infinitely actually fail. re_infinite_loop(Config) when is_list(Config) -> Str = "http:/www.flickr.com/slideShow/index.gne?group_id=&user_id=69845378@N0", EMail_regex = "[a-z0-9!#$%&'*+/=?^_`{|}~-]+" ++ "(\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*" ++ "@.*([a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+" ++ "([a-zA-Z]{2}|com|org|net|gov|mil" ++ "|biz|info|mobi|name|aero|jobs|museum)", nomatch = re:run(Str, EMail_regex), nomatch = re:run(Str, EMail_regex, [global]), {error,match_limit} = re:run(Str, EMail_regex,[report_errors]), {error,match_limit} = re:run(Str, EMail_regex,[report_errors,global]), ok. %% Check for nasty bug where accented graphemes can make PCRE back %% past beginning of subject. re_backwards_accented(Config) when is_list(Config) -> match = re:run(<<65,204,128,65,204,128,97,98,99>>, <<"\\X?abc">>, [unicode,{capture,none}]), ok. %% Check correct handling of dupnames option to re. opt_dupnames(Config) when is_list(Config) -> Days = ["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"], _ = [ begin Short = lists:sublist(Day,3), {match,[Short]} = re:run(Day, "(?Mon|Fri|Sun)(?:day)?|(?Tue)(?:sday)?|" "(?Wed)(?:nesday)?|(?Thu)(?:rsday)?|" "(?Sat)(?:urday)?", [dupnames, {capture, ['DN'], list}]) end || Day <- Days ], _ = [ begin Short = list_to_binary(lists:sublist(Day,3)), {match,[Short]} = re:run(Day, "(?Mon|Fri|Sun)(?:day)?|(?Tue)(?:sday)?|" "(?Wed)(?:nesday)?|(?Thu)(?:rsday)?|" "(?Sat)(?:urday)?", [dupnames, {capture, ['DN'], binary}]) end || Day <- Days ], _ = [ begin {match,[{0,3}]} = re:run(Day, "(?Mon|Fri|Sun)(?:day)?|(?Tue)(?:sday)?|" "(?Wed)(?:nesday)?|(?Thu)(?:rsday)?|" "(?Sat)(?:urday)?", [dupnames, {capture, ['DN'], index}]) end || Day <- Days ], {match,[{0,1},{1,3},{7,1}]} = re:run("SMondayX","(?.)(?Mon|Fri|Sun)(?:day)?(?.)|" "(?Tue)(?:sday)?|(?Wed)nesday|(?Thu)(?:rsday)?|" "(?Sat)(?:urday)?", [dupnames, {capture, ['Skrap','DN','Skrap2'],index}]), {match,[{-1,0},{0,3},{-1,0}]} = re:run("Wednesday","(?.)(?Mon|Fri|Sun)(?:day)?(?.)|" "(?Tue)(?:sday)?|(?Wed)nesday|(?Thu)(?:rsday)?|" "(?Sat)(?:urday)?", [dupnames, {capture, ['Skrap','DN','Skrap2'],index}]), nomatch = re:run("Wednsday","(?.)(?Mon|Fri|Sun)(?:day)?(?.)|" "(?Tue)(?:sday)?|(?Wed)nesday|(?Thu)(?:rsday)?|" "(?Sat)(?:urday)?", [dupnames, {capture, ['Skrap','DN','Skrap2'],index}]), {match,[<<>>]} = re:run("Subject","b",[dupnames,{capture,['B'],binary}]), {match,[<<"S">>,<<"u">>,<<"b">>,<<"j">>,<<"e">>,<<"c">>, <<"t">>,<<"I">>,<<"s">>,<<"M">>,<<"o">>,<<"r">>,<<"e">>, <<"T">>,<<"h">>,<<"a">>,<<"n">>,<<"T">>,<<"e">>,<<"n">>]} = re:run("SubjectIsMoreThanTen", "(?S)(?u)(?b)(?j)(?e)(?c)(?t)" "(?I)(?s)(?M)(?o)(?r)(?e)(?T)" "(?h)(?a)(?n)(?T)(?e)(?n)", [dupnames,{capture,['S','u','b','j','e','c','t', 'I','s','M','o','r','e','T', 'h','a','n','T','e','n'],binary}]), {match,[<<"S">>,<<"u">>,<<"b">>,<<"j">>,<<"e">>,<<"c">>, <<"t">>,<<"I">>,<<"s">>,<<"M">>,<<"o">>,<<"r">>,<<"e">>, <<"T">>,<<"h">>,<<"a">>,<<"n">>,<<"T">>,<<"e">>,<<"n">>]} = re:run("SubjectIsMoreThanTen", "(?S)(?u)(?b)(?j)(?e)(?c)(?t)" "(?I)(?s)(?M)(?o)(?r)(?e)(?T)" "(?h)(?a)(?n)(?T)(?e)(?n)", [dupnames, {capture,all_but_first,list}, {capture,['S','u','b','j','e','c','t', 'I','s','M','o','r','e','T', 'h','a','n','T','e','n'],binary}]), {match,[<<"S">>,<<"u">>,<<"b">>,<<"j">>,<<"e">>,<<"c">>, <<"t">>,<<"I">>,<<"s">>,<<"M">>,<<"o">>,<<"r">>,<<"e">>, <<"T">>,<<"h">>,<<"a">>,<<"n">>,<<"T">>,<<"e">>,<<"n">>]} = re:run("SubjectIsMoreThanTen", "(?S)(?u)(?b)(?j)(?e)(?c)(?t)" "(?I)(?s)(?M)(?o)(?r)(?e)(?T)" "(?h)(?a)(?n)(?T)(?e)(?n)", [dupnames, {capture,["S","u","b","j","e","c","t", "I","s","M","o","r","e","T", "h","a","n","T","e","n"],binary}]), {match,[<<"S">>,<<"u">>,<<"b">>,<<"j">>,<<"e">>,<<"c">>, <<"t">>,<<"I">>,<<"s">>,<<"M">>,<<"o">>,<<"r">>,<<"e">>, <<"T">>,<<"h">>,<<"a">>,<<"n">>,<<"T">>,<<"e">>,<<"n">>]} = re:run("SubjectIsMoreThanTen", "(?S)(?u)(?b)(?j)(?e)(?c)(?t)" "(?I)(?s)(?M)(?o)(?r)(?e)(?T)" "(?h)(?a)(?n)(?T)(?e)(?n)", [dupnames, {capture,["S","u","b","j","e","c","t", "I","s","M","o","r","e","T", "h","a","n","T","e","then"],binary}]), ok. %% Test capturing of all_names. opt_all_names(Config) when is_list(Config) -> Days = ["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"], {match,[{1,3},{0,1},{7,1}]} = re:run("SMondayX","(?.)(?Mon|Fri|Sun)(?:day)?(?.)|" "(?Tue)(?:sday)?|(?Wed)nesday|(?Thu)(?:rsday)?|" "(?Sat)(?:urday)?", [dupnames, {capture, all_names,index}]), {match,[{0,3},{-1,0},{-1,0}]} = re:run("Wednesday","(?.)(?Mon|Fri|Sun)(?:day)?(?.)|" "(?Tue)(?:sday)?|(?Wed)nesday|(?Thu)(?:rsday)?|" "(?Sat)(?:urday)?", [dupnames, {capture, all_names,index}]), _ = [ begin {match,[{0,3}]} = re:run(Day, "(?Mon|Fri|Sun)(?:day)?|(?Tue)(?:sday)?|" "(?Wed)(?:nesday)?|(?Thu)(?:rsday)?|" "(?Sat)(?:urday)?", [dupnames, {capture, all_names, index}]) end || Day <- Days ], _ = [ begin match = re:run(Day, "(Mon|Fri|Sun)(?:day)?|(Tue)(?:sday)?|" "(Wed)(?:nesday)?|(Thu)(?:rsday)?|" "(Sat)(?:urday)?", [dupnames, {capture, all_names, index}]) end || Day <- Days ], {match,[{0,1},{-1,0},{-1,0}]} = re:run("A","(?A)|(?B)|(?C)",[{capture, all_names, index}]), {match,[{-1,0},{0,1},{-1,0}]} = re:run("B","(?A)|(?B)|(?C)",[{capture, all_names, index}]), {match,[{-1,0},{-1,0},{0,1}]} = re:run("C","(?A)|(?B)|(?C)",[{capture, all_names, index}]), {match,[<<"A">>,<<>>,<<>>]} = re:run("A","(?A)|(?B)|(?C)",[{capture, all_names, binary}]), {match,[<<>>,<<"B">>,<<>>]} = re:run("B","(?A)|(?B)|(?C)",[{capture, all_names, binary}]), {match,[<<>>,<<>>,<<"C">>]} = re:run("C","(?A)|(?B)|(?C)",[{capture, all_names, binary}]), {match,["A",[],[]]} = re:run("A","(?A)|(?B)|(?C)",[{capture, all_names, list}]), {match,[[],"B",[]]} = re:run("B","(?A)|(?B)|(?C)",[{capture, all_names, list}]), {match,[[],[],"C"]} = re:run("C","(?A)|(?B)|(?C)",[{capture, all_names, list}]), {match,[{-1,0},{-1,0},{0,1}]} = re:run("A","(?A)|(?B)|(?C)",[{capture, all_names, index}]), {match,[{-1,0},{0,1},{-1,0}]} = re:run("B","(?A)|(?B)|(?C)",[{capture, all_names, index}]), {match,[{0,1},{-1,0},{-1,0}]} = re:run("C","(?A)|(?B)|(?C)",[{capture, all_names, index}]), {match,[<<>>,<<>>,<<"A">>]} = re:run("A","(?A)|(?B)|(?C)",[{capture, all_names, binary}]), {match,[<<>>,<<>>,<<"A">>]} = re:run("A","(?A)|(?B)|(?C)",[{capture, all_but_first, binary},{capture, all_names, binary}]), {match,[<<>>,<<"B">>,<<>>]} = re:run("B","(?A)|(?B)|(?C)",[{capture, all_names, binary}]), {match,[<<"C">>,<<>>,<<>>]} = re:run("C","(?A)|(?B)|(?C)",[{capture, all_names, binary}]), {match,[[],[],"A"]} = re:run("A","(?A)|(?B)|(?C)",[{capture, all_names, list}]), {match,[[],"B",[]]} = re:run("B","(?A)|(?B)|(?C)",[{capture, all_names, list}]), {match,["C",[],[]]} = re:run("C","(?A)|(?B)|(?C)",[{capture, all_names, list}]), {match,[[<<>>,<<>>,<<"C">>], [<<>>,<<>>,<<"C">>], [<<>>,<<>>,<<"C">>]]} = re:run("CCC","(?A)|(?B)|(?C)", [global,{capture, all_names, binary}]), {match,[[<<"C">>,<<>>], [<<>>,<<"B">>], [<<"C">>,<<>>]]} = re:run("CBC","(?A)|(?B)|(?C)", [global,dupnames,{capture, all_names, binary}]), {match,[[]]} = re:run("ABCE","(?D)|(?E)|(?F)",[dupnames,{capture,['A'],list}]), {match,["D"]} = re:run("ABCDE","(?D)|(?E)|(?F)",[dupnames,{capture,['A'],list}]), {match,["F"]} = re:run("ABCFE","(?D)|(?E)|(?F)",[dupnames,{capture,['A'],list}]), {match,["F",[]]} = re:run("ABCFE","(?D)|(?E)|(?F)",[dupnames,{capture,['A','B'],list}]), {match,[[],"E"]} = re:run("ABCE","(?D)|(?E)|(?F)",[dupnames,{capture,['A','B'],list}]), {match,[[],"E"]} = re:run("ABCE","(?D)|(?E)|(?F)",[dupnames,{capture,all_names,list}]), {match,[{-1,0},{3,1}]} = re:run("ABCE","(?D)|(?E)|(?F)",[dupnames,{capture,all_names,index}]), match = re:run("Subject","b",[dupnames,{capture,all_names,binary}]), {match,[<<"I">>,<<"M">>,<<"S">>,<<"T">>,<<"a">>,<<"b">>, <<"c">>,<<"e">>,<<"h">>,<<"j">>,<<"n">>,<<"o">>,<<"r">>, <<"s">>,<<"t">>,<<"u">>]} = re:run("SubjectIsMoreThanTen","(?S)(?u)(?b)(?j)" "(?e)(?c)(?t)(?I)(?s)(?M)(?o)(?r)" "(?e)(?T)(?h)(?a)(?n)(?T)(?e)(?n)", [dupnames,{capture,all_names,binary}]), ok. %% Test the minimal inspect function. inspect(Config) when is_list(Config)-> {ok,MP} = re:compile("(?A)|(?B)|(?C)."), {namelist,[<<"A">>,<<"B">>,<<"C">>]} = re:inspect(MP,namelist), {ok,MPD} = re:compile("(?A)|(?B)|(?C).",[dupnames]), {namelist,[<<"A">>,<<"B">>]} = re:inspect(MPD,namelist), {ok,MPN} = re:compile("(A)|(B)|(C)."), {namelist,[]} = re:inspect(MPN,namelist), {'EXIT',{badarg,_}} = (catch re:inspect(MPD,namelistk)), {'EXIT',{badarg,_}} = (catch re:inspect({re_pattern,3,0,0,<<"kalle">>},namelist)), {'EXIT',{badarg,_}} = (catch re:inspect({re_pattern,3,0,0,<<"kalle",2:2>>},namelist)), ok. %% Test that the no_start_optimize compilation flag works. opt_no_start_optimize(Config) when is_list(Config) -> {match, [{3,3}]} = re:run("DEFABC","(*COMMIT)ABC",[]), % Start optimization makes this result wrong! nomatch = re:run("DEFABC","(*COMMIT)ABC",[no_start_optimize]), % This is the correct result... ok. %% Check that the never_utf option works. opt_never_utf(Config) when is_list(Config) -> {match,[{0,3}]} = re:run("ABC","ABC",[never_utf]), {match,[{0,3}]} = re:run("ABC","(*UTF)ABC",[]), {ok,_} = re:compile("(*UTF)ABC"), {ok,_} = re:compile("(*UTF)ABC",[unicode]), {ok,_} = re:compile("(*UTF8)ABC"), {'EXIT',{badarg,_}} = (catch re:run("ABC","ABC",[unicode,never_utf])), {'EXIT',{badarg,_}} = (catch re:run("ABC","(*UTF)ABC",[never_utf])), {'EXIT',{badarg,_}} = (catch re:run("ABC","(*UTF8)ABC",[never_utf])), {error,_} = (catch re:compile("ABC",[unicode,never_utf])), {error,_} = (catch re:compile("(*UTF)ABC",[never_utf])), {error,_} = (catch re:compile("(*UTF8)ABC",[never_utf])), ok. %% Check that the ucp option is passed to PCRE. opt_ucp(Config) when is_list(Config) -> {match,[{0,1}]} = re:run([$a],"\\w",[unicode]), {match,[{0,2}]} = re:run([229],"\\w",[unicode]), % Latin1 works without UCP, as we have a default %% Latin1 table nomatch = re:run([1024],"\\w",[unicode]), % Latin1 word characters only, 1024 is not latin1 {match,[{0,2}]} = re:run([1024],"\\w",[unicode,ucp]), % Any Unicode word character works with 'ucp' ok. %% Check that the match_limit and match_limit_recursion options work. match_limit(Config) when is_list(Config) -> nomatch = re:run("aaaaaaaaaaaaaz","(a+)*zz",[]), nomatch = re:run("aaaaaaaaaaaaaz","(a+)*zz",[{match_limit,3000}]), nomatch = re:run("aaaaaaaaaaaaaz","(a+)*zz",[{match_limit_recursion,10}]), nomatch = re:run("aaaaaaaaaaaaaz","(a+)*zz",[report_errors]), {error,match_limit} = re:run("aaaaaaaaaaaaaz","(a+)*zz",[{match_limit,3000}, report_errors]), {error,match_limit_recursion} = re:run("aaaaaaaaaaaaaz","(a+)*zz",[{match_limit_recursion,10}, report_errors]), {error,match_limit} = re:run("aaaaaaaaaaaaaz","(a+)*zz",[{match_limit,3000}, report_errors,global]), {error,match_limit_recursion} = re:run("aaaaaaaaaaaaaz","(a+)*zz",[{match_limit_recursion,10}, report_errors,global]), ["aaaaaaaaaaaaaz"] = re:split("aaaaaaaaaaaaaz","(a+)*zz", [{match_limit_recursion,10},{return,list}]), ["aaaaaaaaaaaaaz"] = re:split("aaaaaaaaaaaaaz","(a+)*zz", [{match_limit,3000},{return,list}]), "aaaaaaaaaaaaaz" = re:replace("aaaaaaaaaaaaaz","(a+)*zz","!", [{match_limit_recursion,10},{return,list}]), "aaaaaaaaaaaaaz" = re:replace("aaaaaaaaaaaaaz","(a+)*zz","!", [{match_limit,3000},{return,list}]), {'EXIT', {badarg,_}} = (catch re:replace("aaaaaaaaaaaaaz","(a+)*zz","!", [{match_limit_recursion,-1},{return,list}])), {'EXIT', {badarg,_}} = (catch re:replace("aaaaaaaaaaaaaz","(a+)*zz","!", [{match_limit,-1},{return,list}])), {'EXIT', {badarg,_}} = (catch re:run("aaaaaaaaaaaaaz","(a+)*zz", [{match_limit_recursion,-1}, report_errors,global])), {'EXIT', {badarg,_}} = (catch re:run("aaaaaaaaaaaaaz","(a+)*zz", [{match_limit,-1}, report_errors,global])), ok. %% Test that we get sub-binaries if subject is a binary and we capture %% binaries. sub_binaries(Config) when is_list(Config) -> Bin = list_to_binary(lists:seq(1,255)), {match,[B,C]}=re:run(Bin,"(a)",[{capture,all,binary}]), 255 = binary:referenced_byte_size(B), 255 = binary:referenced_byte_size(C), {match,[D]}=re:run(Bin,"(a)",[{capture,[1],binary}]), 255 = binary:referenced_byte_size(D), ok.