1: %% -*- coding: utf-8 -*-
    2: %%
    3: %% %CopyrightBegin%
    4: %%
    5: %% Copyright Ericsson AB 2008-2012. All Rights Reserved.
    6: %%
    7: %% The contents of this file are subject to the Erlang Public License,
    8: %% Version 1.1, (the "License"); you may not use this file except in
    9: %% compliance with the License. You should have received a copy of the
   10: %% Erlang Public License along with this software. If not, it can be
   11: %% retrieved online at http://www.erlang.org/.
   12: %%
   13: %% Software distributed under the License is distributed on an "AS IS"
   14: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
   15: %% the License for the specific language governing rights and limitations
   16: %% under the License.
   17: %%
   18: %% %CopyrightEnd%
   19: %%
   20: -module(re_SUITE).
   21: 
   22: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
   23: 	 init_per_group/2,end_per_group/2, pcre/1,compile_options/1,
   24: 	 run_options/1,combined_options/1,replace_autogen/1,
   25: 	 global_capture/1,replace_input_types/1,replace_return/1,
   26: 	 split_autogen/1,split_options/1,split_specials/1,
   27: 	 error_handling/1,pcre_cve_2008_2371/1,
   28: 	 pcre_compile_workspace_overflow/1,re_infinite_loop/1]).
   29: 
   30: -include_lib("test_server/include/test_server.hrl").
   31: -include_lib("kernel/include/file.hrl").
   32: 
   33: suite() -> [{ct_hooks,[ts_install_cth]}].
   34: 
   35: all() -> 
   36:     [pcre, compile_options, run_options, combined_options,
   37:      replace_autogen, global_capture, replace_input_types,
   38:      replace_return, split_autogen, split_options,
   39:      split_specials, error_handling, pcre_cve_2008_2371,
   40:      pcre_compile_workspace_overflow, re_infinite_loop].
   41: 
   42: groups() -> 
   43:     [].
   44: 
   45: init_per_suite(Config) ->
   46:     Config.
   47: 
   48: end_per_suite(_Config) ->
   49:     ok.
   50: 
   51: init_per_group(_GroupName, Config) ->
   52:     Config.
   53: 
   54: end_per_group(_GroupName, Config) ->
   55:     Config.
   56: 
   57: 
   58: pcre(doc) ->
   59:     ["Run all applicable tests from the PCRE testsuites."];
   60: pcre(Config) when is_list(Config) ->
   61:     Dog = ?t:timetrap(?t:minutes(3)),
   62:     RootDir = ?config(data_dir, Config),
   63:     Res = run_pcre_tests:test(RootDir),
   64:     0 = lists:sum([ X || {X,_,_} <- Res ]),
   65:     ?t:timetrap_cancel(Dog),
   66:     {comment,Res}.
   67: 
   68: compile_options(doc) ->
   69:     ["Test all documented compile options"];
   70: compile_options(Config) when is_list(Config) ->
   71:     ?line ok = ctest("ABDabcdABCD","abcd",[],true,{match,[{3,4}]}),
   72:     ?line ok = ctest("ABDabcdABCD","abcd",[anchored],true,nomatch),
   73:     ?line ok = ctest("ABDabcdABCD",".*abcd",[anchored],true,{match,[{0,7}]}),
   74:     ?line ok = ctest("ABCabcdABC","ABCD",[],true,nomatch),
   75:     ?line ok = ctest("ABCabcdABC","ABCD",[caseless],true,{match,[{3,4}]}),
   76:     ?line ok = ctest("abcdABC\n","ABC$",[],true,{match,[{4,3}]}),
   77:     ?line ok = ctest("abcdABC\n","ABC$",[dollar_endonly],true,nomatch),
   78:     ?line ok = ctest("abcdABC\n","ABC.",[],true,nomatch),
   79:     ?line ok = ctest("abcdABC\n","ABC.",[dotall],true,{match,[{4,4}]}),
   80:     ?line ok = ctest("abcdABCD","ABC .",[],true,nomatch),
   81:     ?line ok = ctest("abcdABCD","ABC .",[extended],true,{match,[{4,4}]}),
   82:     ?line ok = ctest("abcd\nABCD","ABC",[],true,{match,[{5,3}]}),
   83:     ?line ok = ctest("abcd\nABCD","ABC",[firstline],true,nomatch),
   84:     ?line ok = ctest("abcd\nABCD","^ABC",[],true,nomatch),
   85:     ?line ok = ctest("abcd\nABCD","^ABC",[multiline],true,{match,[{5,3}]}),
   86:     ?line ok = ctest("abcdABCD","(ABC)",[],true,{match,[{4,3},{4,3}]}),
   87:     ?line ok = ctest("abcdABCD","(ABC)",[no_auto_capture],true,{match,[{4,3}]}),
   88:     ?line ok = ctest(notused,"(?<FOO>ABC)|(?<FOO>DEF)",[],false,notused),
   89:     ?line ok = ctest("abcdABCD","(?<FOO>ABC)|(?<FOO>DEF)",[dupnames],true,{match,[{4,3},{4,3}]}),
   90:     ?line ok = ctest("abcdABCDabcABCD","abcd.*D",[],true,{match,[{0,15}]}),
   91:     ?line ok = ctest("abcdABCDabcABCD","abcd.*D",[ungreedy],true,{match,[{0,8}]}),
   92:     ?line ok = ctest("abcdABCabcABC\nD","abcd.*D",[],true,nomatch),
   93:     ?line ok = ctest("abcdABCabcABC\nD","abcd.*D",[{newline,cr}],true,{match,[{0,15}]}),
   94:     ?line ok = ctest("abcdABCabcABC\rD","abcd.*D",[],true,{match,[{0,15}]}),
   95:     ?line ok = ctest("abcdABCabcABC\rD","abcd.*D",[{newline,lf}],true,{match,[{0,15}]}),
   96:     ?line ok = ctest("abcdABCabcd\r\n","abcd$",[{newline,lf}],true,nomatch),
   97:     ?line ok = ctest("abcdABCabcd\r\n","abcd$",[{newline,cr}],true,nomatch),
   98:     ?line ok = ctest("abcdABCabcd\r\n","abcd$",[{newline,crlf}],true,{match,[{7,4}]}),
   99:     
  100:      ?line ok = ctest("abcdABCabcd\r","abcd$",[{newline,crlf}],true,nomatch),
  101:      ?line ok = ctest("abcdABCabcd\n","abcd$",[{newline,crlf}],true,nomatch),
  102:     ?line ok = ctest("abcdABCabcd\r\n","abcd$",[{newline,anycrlf}],true,{match,[{7,4}]}),
  103:     
  104:      ?line ok = ctest("abcdABCabcd\r","abcd$",[{newline,anycrlf}],true,{match,[{7,4}]}),
  105:      ?line ok = ctest("abcdABCabcd\n","abcd$",[{newline,anycrlf}],true,{match,[{7,4}]}),
  106:     ok.
  107: 
  108: run_options(doc) ->
  109:     ["Test all documented run specific options"];
  110: run_options(Config) when is_list(Config) ->
  111:     ?line rtest("ABCabcdABC","abc",[],[],true),
  112:     ?line rtest("ABCabcdABC","abc",[anchored],[],false),
  113:     % Anchored in run overrides unanchored in compilation
  114:     ?line rtest("ABCabcdABC","abc",[],[anchored],false), 
  115:     
  116:     ?line rtest("","a?b?",[],[],true),
  117:     ?line rtest("","a?b?",[],[notempty],false),
  118: 
  119:     ?line rtest("abc","^a",[],[],true),
  120:     ?line rtest("abc","^a",[],[notbol],false),
  121:     ?line rtest("ab\nc","^a",[multiline],[],true),
  122:     ?line rtest("ab\nc","^a",[multiline],[notbol],false),
  123:     ?line rtest("ab\nc","^c",[multiline],[notbol],true),
  124: 
  125:     ?line rtest("abc","c$",[],[],true),
  126:     ?line rtest("abc","c$",[],[noteol],false),
  127: 
  128:     ?line rtest("ab\nc","b$",[multiline],[],true),
  129:     ?line rtest("ab\nc","c$",[multiline],[],true),
  130:     ?line rtest("ab\nc","b$",[multiline],[noteol],true),
  131:     ?line rtest("ab\nc","c$",[multiline],[noteol],false),
  132: 
  133:     ?line rtest("abc","ab",[],[{offset,0}],true),
  134:     ?line rtest("abc","ab",[],[{offset,1}],false),
  135:     
  136:     ?line rtest("abcdABCabcABC\nD","abcd.*D",[],[],false),
  137:     ?line rtest("abcdABCabcABC\nD","abcd.*D",[],[{newline,cr}],true),
  138:     ?line rtest("abcdABCabcABC\rD","abcd.*D",[],[],true),
  139:     ?line rtest("abcdABCabcABC\rD","abcd.*D",[{newline,cr}],[{newline,lf}],true),
  140:     ?line rtest("abcdABCabcd\r\n","abcd$",[],[{newline,lf}],false),
  141:     ?line rtest("abcdABCabcd\r\n","abcd$",[],[{newline,cr}],false),
  142:     ?line rtest("abcdABCabcd\r\n","abcd$",[],[{newline,crlf}],true),
  143:     
  144:     ?line rtest("abcdABCabcd\r","abcd$",[],[{newline,crlf}],false),
  145:     ?line rtest("abcdABCabcd\n","abcd$",[],[{newline,crlf}],false),
  146:     ?line rtest("abcdABCabcd\r\n","abcd$",[],[{newline,anycrlf}],true),
  147:     
  148:     ?line rtest("abcdABCabcd\r","abcd$",[],[{newline,anycrlf}],true),
  149:     ?line rtest("abcdABCabcd\n","abcd$",[],[{newline,anycrlf}],true),
  150:     
  151:     ?line {ok,MP} = re:compile(".*(abcd).*"),
  152:     ?line {match,[{0,10},{3,4}]} = re:run("ABCabcdABC",MP,[]),
  153:     ?line {match,[{0,10},{3,4}]} = re:run("ABCabcdABC",MP,[{capture,all}]),
  154:     ?line {match,[{0,10},{3,4}]} = re:run("ABCabcdABC",MP,[{capture,all,index}]),
  155:     ?line {match,["ABCabcdABC","abcd"]} = re:run("ABCabcdABC",MP,[{capture,all,list}]),
  156:     ?line {match,[<<"ABCabcdABC">>,<<"abcd">>]} = re:run("ABCabcdABC",MP,[{capture,all,binary}]),
  157:     ?line {match,[{0,10}]} = re:run("ABCabcdABC",MP,[{capture,first}]),
  158:     ?line {match,[{0,10}]} = re:run("ABCabcdABC",MP,[{capture,first,index}]),       ?line {match,["ABCabcdABC"]} = re:run("ABCabcdABC",MP,[{capture,first,list}]),       
  159:     ?line {match,[<<"ABCabcdABC">>]} = re:run("ABCabcdABC",MP,[{capture,first,binary}]),    
  160:     
  161:     ?line {match,[{3,4}]} = re:run("ABCabcdABC",MP,[{capture,all_but_first}]),
  162:     ?line {match,[{3,4}]} = re:run("ABCabcdABC",MP,[{capture,all_but_first,index}]),
  163:     ?line {match,["abcd"]} = re:run("ABCabcdABC",MP,[{capture,all_but_first,list}]),
  164:     ?line {match,[<<"abcd">>]} = re:run("ABCabcdABC",MP,[{capture,all_but_first,binary}]),
  165:     
  166:     ?line match = re:run("ABCabcdABC",MP,[{capture,none}]),
  167:     ?line match = re:run("ABCabcdABC",MP,[{capture,none,index}]),
  168:     ?line match = re:run("ABCabcdABC",MP,[{capture,none,list}]),
  169:     ?line match = re:run("ABCabcdABC",MP,[{capture,none,binary}]),
  170: 
  171:     ?line {ok,MP2} = re:compile(".*(?<FOO>abcd).*"),
  172:     ?line {match,[{3,4}]} = re:run("ABCabcdABC",MP2,[{capture,[1]}]),
  173:     ?line {match,[{3,4}]} = re:run("ABCabcdABC",MP2,[{capture,['FOO']}]),
  174:     ?line {match,[{3,4}]} = re:run("ABCabcdABC",MP2,[{capture,["FOO"]}]),
  175:     ?line {match,["abcd"]} = re:run("ABCabcdABC",MP2,[{capture,["FOO"],list}]),
  176:     ?line {match,[<<"abcd">>]} = re:run("ABCabcdABC",MP2,[{capture,["FOO"],binary}]),
  177:     
  178:     ?line {match,[{-1,0}]} = re:run("ABCabcdABC",MP2,[{capture,[200]}]),
  179:     ?line {match,[{-1,0}]} = re:run("ABCabcdABC",MP2,[{capture,['BAR']}]),
  180:     ?line {match,[""]} = re:run("ABCabcdABC",MP2,[{capture,[200],list}]),
  181:     ?line {match,[""]} = re:run("ABCabcdABC",MP2,[{capture,['BAR'],list}]),
  182:     ?line {match,[<<>>]} = re:run("ABCabcdABC",MP2,[{capture,[200],binary}]),
  183:     ?line {match,[<<>>]} = re:run("ABCabcdABC",MP2,[{capture,['BAR'],binary}]),
  184: 
  185:     ?line {ok, MP3} = re:compile(".*((?<FOO>abdd)|a(..d)).*"),
  186:     ?line {match,[{0,10},{3,4},{-1,0},{4,3}]} = re:run("ABCabcdABC",MP3,[]),
  187:     ?line {match,[{0,10},{3,4},{-1,0},{4,3}]} = re:run("ABCabcdABC",MP3,[{capture,all,index}]),
  188:     ?line {match,[<<"ABCabcdABC">>,<<"abcd">>,<<>>,<<"bcd">>]} = re:run("ABCabcdABC",MP3,[{capture,all,binary}]),
  189:     ?line {match,["ABCabcdABC","abcd",[],"bcd"]} = re:run("ABCabcdABC",MP3,[{capture,all,list}]),
  190:     ok.
  191:     
  192: 
  193:     
  194: combined_options(doc) ->    
  195:     ["Test compile options given directly to run"];
  196: combined_options(Config) when is_list(Config) ->
  197:     ?line ok = crtest("ABDabcdABCD","abcd",[],true,{match,[{3,4}]}),
  198:     ?line ok = crtest("ABDabcdABCD","abcd",[anchored],true,nomatch),
  199:     ?line ok = crtest("ABDabcdABCD",".*abcd",[anchored],true,{match,[{0,7}]}),
  200:     ?line ok = crtest("ABCabcdABC","ABCD",[],true,nomatch),
  201:     ?line ok = crtest("ABCabcdABC","ABCD",[caseless],true,{match,[{3,4}]}),
  202:     ?line ok = crtest("abcdABC\n","ABC$",[],true,{match,[{4,3}]}),
  203:     ?line ok = crtest("abcdABC\n","ABC$",[dollar_endonly],true,nomatch),
  204:     ?line ok = crtest("abcdABC\n","ABC.",[],true,nomatch),
  205:     ?line ok = crtest("abcdABC\n","ABC.",[dotall],true,{match,[{4,4}]}),
  206:     ?line ok = crtest("abcdABCD","ABC .",[],true,nomatch),
  207:     ?line ok = crtest("abcdABCD","ABC .",[extended],true,{match,[{4,4}]}),
  208:     ?line ok = crtest("abcd\nABCD","ABC",[],true,{match,[{5,3}]}),
  209:     ?line ok = crtest("abcd\nABCD","ABC",[firstline],true,nomatch),
  210:     ?line ok = crtest("abcd\nABCD","^ABC",[],true,nomatch),
  211:     ?line ok = crtest("abcd\nABCD","^ABC",[multiline],true,{match,[{5,3}]}),
  212:     ?line ok = crtest("abcdABCD","(ABC)",[],true,{match,[{4,3},{4,3}]}),
  213:     ?line ok = crtest("abcdABCD","(ABC)",[no_auto_capture],true,{match,[{4,3}]}),
  214:     ?line ok = crtest(notused,"(?<FOO>ABC)|(?<FOO>DEF)",[],false,notused),
  215:     ?line ok = crtest("abcdABCD","(?<FOO>ABC)|(?<FOO>DEF)",[dupnames],true,{match,[{4,3},{4,3}]}),
  216:     ?line ok = crtest("abcdABCDabcABCD","abcd.*D",[],true,{match,[{0,15}]}),
  217:     ?line ok = crtest("abcdABCDabcABCD","abcd.*D",[ungreedy],true,{match,[{0,8}]}),
  218:     ?line ok = ctest("abcdABCabcABC\nD","abcd.*D",[],true,nomatch),
  219:     ?line ok = crtest("abcdABCabcABC\nD","abcd.*D",[{newline,cr}],true,{match,[{0,15}]}),
  220:     ?line ok = crtest("abcdABCabcABC\rD","abcd.*D",[],true,{match,[{0,15}]}),
  221:     ?line ok = crtest("abcdABCabcABC\rD","abcd.*D",[{newline,lf}],true,{match,[{0,15}]}),
  222:     ?line ok = crtest("abcdABCabcd\r\n","abcd$",[{newline,lf}],true,nomatch),
  223:     ?line ok = crtest("abcdABCabcd\r\n","abcd$",[{newline,cr}],true,nomatch),
  224:     ?line ok = crtest("abcdABCabcd\r\n","abcd$",[{newline,crlf}],true,{match,[{7,4}]}),
  225:     
  226:     ?line ok = crtest("abcdABCabcd\r","abcd$",[{newline,crlf}],true,nomatch),
  227:     ?line ok = crtest("abcdABCabcd\n","abcd$",[{newline,crlf}],true,nomatch),
  228:     ?line ok = crtest("abcdABCabcd\r\n","abcd$",[{newline,anycrlf}],true,{match,[{7,4}]}),
  229:     
  230:     ?line ok = crtest("abcdABCabcd\r","abcd$",[{newline,anycrlf}],true,{match,[{7,4}]}),
  231:     ?line ok = crtest("abcdABCabcd\n","abcd$",[{newline,anycrlf}],true,{match,[{7,4}]}),
  232: 
  233:     ?line ok = crtest("abcdABCabcd\r\n","abcd$",[{newline,anycrlf},{capture,all,list}],true,{match,["abcd"]}),
  234:     
  235:     ?line ok = crtest("abcdABCabcd\r","abcd$",[{newline,anycrlf},{capture,all,list}],true,{match,["abcd"]}),
  236:     
  237:     ?line ok = crtest("abcdABCabcd\n","abcd$",[{newline,anycrlf},{capture,all,list}],true,{match,["abcd"]}),
  238:     
  239:     ?line ok = crtest("abcdABCabcd\r\n","abcd$",[{newline,anycrlf},{capture,all,binary}],true,{match,[<<"abcd">>]}),
  240:     
  241:     ?line ok = crtest("abcdABCabcd\r","abcd$",[{newline,anycrlf},{capture,all,binary}],true,{match,[<<"abcd">>]}),
  242:     ?line ok = crtest("abcdABCabcd\n","abcd$",[{newline,anycrlf},{capture,all,binary}],true,{match,[<<"abcd">>]}),
  243:     
  244:     % Check that unique run-options fail in compile only case:
  245:     ?line {'EXIT',{badarg,_}} = (catch re:compile("abcd$",[{newline,anycrlf},{capture,all,binary}])),
  246:     ?line {'EXIT',{badarg,_}} = (catch re:compile("abcd$",[{newline,anycrlf},{offset,3}])),
  247:     ?line {'EXIT',{badarg,_}} = (catch re:compile("abcd$",[{newline,anycrlf},notempty])),
  248:     ?line {'EXIT',{badarg,_}} = (catch re:compile("abcd$",[{newline,anycrlf},notbol])),
  249:     ?line {'EXIT',{badarg,_}} = (catch re:compile("abcd$",[{newline,anycrlf},noteol])),
  250: 
  251: 
  252:     ?line {match,_} = re:run("abcdABCabcd\r\n","abcd$",[{newline,crlf}]),
  253:     ?line nomatch = re:run("abcdABCabcd\r\nefgh","abcd$",[{newline,crlf}]),
  254:     ?line {match,_} = re:run("abcdABCabcd\r\nefgh","abcd$",[{newline,crlf},multiline]),
  255:     ?line nomatch = re:run("abcdABCabcd\r\nefgh","efgh$",[{newline,crlf},multiline,noteol]),
  256:     ?line {match,_} = re:run("abcdABCabcd\r\nefgh","abcd$",[{newline,crlf},multiline,noteol]),
  257:     ?line {match,_} = re:run("abcdABCabcd\r\nefgh","^abcd",[{newline,crlf},multiline,noteol]),
  258:     ?line nomatch = re:run("abcdABCabcd\r\nefgh","^abcd",[{newline,crlf},multiline,notbol]),
  259:     ?line {match,_} = re:run("abcdABCabcd\r\nefgh","^efgh",[{newline,crlf},multiline,notbol]),
  260:     ?line {match,_} = re:run("ABC\nD","[a-z]*",[{newline,crlf}]),
  261:     ?line nomatch = re:run("ABC\nD","[a-z]*",[{newline,crlf},notempty]),
  262:     ok.
  263: 
  264: replace_autogen(doc) ->    
  265:     ["Test replace with autogenerated erlang module"];
  266: replace_autogen(Config) when is_list(Config) ->
  267:     Dog = ?t:timetrap(?t:minutes(3)),
  268:     re_testoutput1_replacement_test:run(),
  269:     ?t:timetrap_cancel(Dog),
  270:     ok.
  271: 
  272: global_capture(doc) ->    
  273:     ["Tests capture options together with global searching"];
  274: global_capture(Config) when is_list(Config) ->
  275:     Dog = ?t:timetrap(?t:minutes(3)),
  276:     ?line {match,[{3,4}]} = re:run("ABCabcdABC",".*(?<FOO>abcd).*",[{capture,[1]}]),
  277:     ?line {match,[{10,4}]} = re:run("ABCabcdABCabcdA",".*(?<FOO>abcd).*",[{capture,[1]}]),
  278:     ?line {match,[[{10,4}]]} = re:run("ABCabcdABCabcdA",".*(?<FOO>abcd).*",[global,{capture,[1]}]),
  279:     ?line {match,[{3,4}]} = re:run("ABCabcdABC",".*(?<FOO>abcd).*",[{capture,['FOO']}]),
  280:     ?line {match,[{10,4}]} = re:run("ABCabcdABCabcdA",".*(?<FOO>abcd).*",[{capture,['FOO']}]),
  281:     ?line {match,[[{10,4}]]} = re:run("ABCabcdABCabcdA",".*(?<FOO>abcd).*",[global,{capture,['FOO']}]),
  282:     ?line {match,[[{3,4},{3,4}],[{10,4},{10,4}]]} = re:run("ABCabcdABCabcdA","(?<FOO>abcd)",[global]),
  283:     ?line {match,[[{3,4},{3,4}],[{10,4},{10,4}]]} = re:run("ABCabcdABCabcdA","(?<FOO>abcd)",[global,{capture,all}]),
  284:     ?line {match,[[{3,4},{3,4}],[{10,4},{10,4}]]} = re:run("ABCabcdABCabcdA","(?<FOO>abcd)",[global,{capture,all,index}]),
  285:     ?line {match,[[{3,4}],[{10,4}]]} = re:run("ABCabcdABCabcdA","(?<FOO>abcd)",[global,{capture,first}]),
  286:     ?line {match,[[{3,4}],[{10,4}]]} = re:run("ABCabcdABCabcdA","(?<FOO>abcd)",[global,{capture,all_but_first}]),
  287:     ?line {match,[[<<"bcd">>],[<<"bcd">>]]} = re:run("ABCabcdABCabcdA","a(?<FOO>bcd)",[global,{capture,all_but_first,binary}]),
  288:     ?line {match,[["bcd"],["bcd"]]} = re:run("ABCabcdABCabcdA","a(?<FOO>bcd)",[global,{capture,all_but_first,list}]),
  289:     ?line {match,[["abcd","bcd"],["abcd","bcd"]]} = re:run("ABCabcdABCabcdA","a(?<FOO>bcd)",[global,{capture,all,list}]),
  290:     ?line {match,[[<<"abcd">>,<<"bcd">>],[<<"abcd">>,<<"bcd">>]]} = re:run("ABCabcdABCabcdA","a(?<FOO>bcd)",[global,{capture,all,binary}]),
  291:     ?line {match,[[{3,4},{4,3}],[{10,4},{11,3}]]} = re:run("ABCabcdABCabcdA","a(?<FOO>bcd)",[global,{capture,all,index}]),
  292:     ?line match = re:run("ABCabcdABCabcdA","a(?<FOO>bcd)",[global,{capture,none,index}]),
  293:     ?line match = re:run("ABCabcdABCabcdA","a(?<FOO>bcd)",[global,{capture,none,binary}]),
  294:     ?line match = re:run("ABCabcdABCabcdA","a(?<FOO>bcd)",[global,{capture,none,list}]),
  295:     ?line {match,[[<<195,133,98,99,100>>,<<"bcd">>],[<<"abcd">>,<<"bcd">>]]} = re:run("ABCÅbcdABCabcdA",".(?<FOO>bcd)",[global,{capture,all,binary},unicode]),
  296:     ?line {match,[["Åbcd","bcd"],["abcd","bcd"]]} = re:run(<<"ABC",8#303,8#205,"bcdABCabcdA">>,".(?<FOO>bcd)",[global,{capture,all,list},unicode]),
  297:     ?line {match,[["Åbcd","bcd"],["abcd","bcd"]]} = re:run("ABCÅbcdABCabcdA",".(?<FOO>bcd)",[global,{capture,all,list},unicode]),
  298:     ?line {match,[[{3,5},{5,3}],[{11,4},{12,3}]]} = re:run("ABCÅbcdABCabcdA",".(?<FOO>bcd)",[global,{capture,all,index},unicode]),
  299:     ?t:timetrap_cancel(Dog),
  300:     ok.
  301: 
  302: replace_input_types(doc) ->
  303:     ["Tests replace with different input types"];
  304: replace_input_types(Config) when is_list(Config) ->
  305:     Dog = ?t:timetrap(?t:minutes(3)),
  306:     ?line <<"abcd">> = re:replace("abcd","Z","X",[{return,binary},unicode]),
  307:     ?line <<"abcd">> = re:replace("abcd","\x{400}","X",[{return,binary},unicode]),
  308:     ?line <<"a",208,128,"cd">> = re:replace(<<"abcd">>,"b","\x{400}",[{return,binary},unicode]),
  309:     ?t:timetrap_cancel(Dog),
  310:     ok.
  311: 
  312: replace_return(doc) ->    
  313:     ["Tests return options of replace together with global searching"];
  314: replace_return(Config) when is_list(Config) ->
  315:     Dog = ?t:timetrap(?t:minutes(3)),
  316:     ?line {'EXIT',{badarg,_}} = (catch re:replace("na","(a","")),
  317:     ?line <<"nasse">> = re:replace(<<"nisse">>,"i","a",[{return,binary}]),
  318:     ?line <<"ABCÅXABCXA">> = re:replace("ABC\305abcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,binary}]),
  319:     
  320:     ?line [<<"ABCÅ">>,
  321: 	   <<"X">>,
  322: 	   <<"ABC">>,
  323: 	   <<"X">> | 
  324: 	   <<"A">> ] = 
  325: 	re:replace("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,iodata}]),
  326:     ?line "ABCÅXABCXA" = re:replace("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,list},unicode]),
  327:     ?line <<65,66,67,195,133,88,65,66,67,88,65>> = re:replace("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,binary},unicode]),
  328:     ?line <<65,66,67,195,133,88,65,66,67,97,98,99,100,65>> = re:replace("ABCÅabcdABCabcdA","a(?<FOO>bcd)","X",[{return,binary},unicode]),
  329:     ?line <<"iXk">> = re:replace("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\9X",[{return,binary}]),
  330:     ?line <<"jXk">> = re:replace("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\10X",[{return,binary}]),
  331:     ?line <<"Xk">> = re:replace("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\11X",[{return,binary}]),
  332:     ?line <<"9X1">> = re:replace("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g9X",[{return,binary}]),
  333:     ?line <<"0X1">> = re:replace("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g10X",[{return,binary}]),
  334:     ?line <<"X1">> = re:replace("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g11X",[{return,binary}]),
  335:     ?line <<"971">> = re:replace("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g{9}7",[{return,binary}]),
  336:     ?line <<"071">> = re:replace("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g{10}7",[{return,binary}]),
  337:     ?line <<"71">> = re:replace("12345678901","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\g{11}7",[{return,binary}]),
  338:     ?line "a\x{400}bcX" = re:replace("a\x{400}bcd","d","X",[global,{return,list},unicode]),
  339:     ?line <<"a",208,128,"bcX">> = re:replace("a\x{400}bcd","d","X",[global,{return,binary},unicode]),
  340:     ?line "a\x{400}bcd" = re:replace("a\x{400}bcd","Z","X",[global,{return,list},unicode]),
  341:     ?line <<"a",208,128,"bcd">> = re:replace("a\x{400}bcd","Z","X",[global,{return,binary},unicode]),
  342:     ?t:timetrap_cancel(Dog),
  343:     ok.
  344: 
  345: rtest(Subj, RE, Copt, Ropt, true) ->
  346:     {ok,MP} = re:compile(RE,Copt), 
  347:     {match,_} = re:run(Subj,MP,Ropt),
  348:     ok;
  349: rtest(Subj, RE, Copt, Ropt, false) ->
  350:     {ok,MP} = re:compile(RE,Copt), 
  351:     nomatch = re:run(Subj,MP,Ropt),
  352:     ok.
  353: 
  354: ctest(_,RE,Options,false,_) ->
  355:     case re:compile(RE,Options) of
  356: 	{ok,_} ->
  357: 	    error;
  358: 	{error,_} ->
  359: 	    ok
  360:     end;
  361: ctest(Subject,RE,Options,true,Result) ->
  362:     try
  363: 	{ok, Prog} = re:compile(RE,Options),
  364: 	Result = re:run(Subject,Prog,[]),
  365: 	ok
  366:     catch
  367: 	_:_ ->
  368: 	    error
  369:     end.
  370: crtest(_,RE,Options,false,_) ->
  371:     case (catch re:run("",RE,Options)) of
  372: 	{'EXIT',{badarg,_}} ->
  373: 	    ok;
  374: 	_ ->
  375: 	    error
  376:     end;
  377: crtest(Subject,RE,Options,true,Result) ->
  378:     try
  379: 	Result = re:run(Subject,RE,Options),
  380: 	ok
  381:     catch
  382: 	_:_ ->
  383: 	    error
  384:     end.
  385: 
  386: split_autogen(doc) ->    
  387:     ["Test split with autogenerated erlang module"];
  388: split_autogen(Config) when is_list(Config) ->
  389:     Dog = ?t:timetrap(?t:minutes(3)),
  390:     re_testoutput1_split_test:run(),
  391:     ?t:timetrap_cancel(Dog),
  392:     ok.
  393: 
  394: split_options(doc) ->
  395:     ["Test special options to split."];
  396: split_options(Config) when is_list(Config) ->
  397:     Dog = ?t:timetrap(?t:minutes(1)),
  398:     ?line [[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>]] = re:split("a b c ","( )",[group,trim]),
  399:     ?line [[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>]] = re:split("a b c ","( )",[group,{parts,0}]),
  400:     ?line [[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<>>]] = 
  401: 	re:split("a b c ","( )",[{parts,infinity},group]),
  402:     ?line [[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<>>]] = 
  403: 	re:split("a b c ","( )",[group]),
  404:     ?line [[<<>>,<<" ">>],[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],
  405: 	   [<<"c">>,<<" ">>],[<<"d">>,<<" ">>]] = 
  406: 	re:split(" a b c d ","( +)",[group,trim]),
  407:     ?line [[<<>>,<<" ">>],[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],
  408: 	   [<<"c">>,<<" ">>],[<<"d">>,<<" ">>]] = 
  409: 	re:split(" a b c d ","( +)",[{parts,0},group]),
  410:     ?line [[<<>>,<<" ">>],[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],
  411: 	   [<<"c">>,<<" ">>],[<<"d">>,<<" ">>],[<<>>]] =  
  412: 	re:split(" a b c d ","( +)",[{parts,infinity},group]),
  413:     ?line [[<<"a">>,<<" ">>],[<<"b c d">>]] =
  414: 	re:split("a b c d","( +)",[{parts,2},group]),
  415:     ?line [[[967]," "],["b c d"]] = 
  416: 	re:split([967]++" b c d","( +)",
  417: 		 [{parts,2},group,{return,list},unicode]),    
  418:     ?line [[<<207,135>>,<<" ">>],[<<"b c d">>]] = 
  419: 	re:split([967]++" b c d","( +)",
  420: 		 [{parts,2},group,{return,binary},unicode]),
  421:     ?line {'EXIT',{badarg,_}} = 
  422: 	(catch re:split([967]++" b c d","( +)",
  423: 		       [{parts,2},group,{return,binary}])),
  424:     ?line {'EXIT',{badarg,_}} = 
  425: 	(catch re:split("a b c d","( +)",[{parts,-2}])),
  426:     ?line {'EXIT',{badarg,_}} = 
  427: 	(catch re:split("a b c d","( +)",[{parts,banan}])),
  428:     ?line {'EXIT',{badarg,_}} = 
  429: 	(catch re:split("a b c d","( +)",[{capture,all}])),
  430:     ?line {'EXIT',{badarg,_}} = 
  431: 	(catch re:split("a b c d","( +)",[{capture,[],binary}])),
  432:     % Parts 0 is equal to no parts specification (implicit strip)
  433:     ?line ["a"," ","b"," ","c"," ","d"] = 
  434: 	re:split("a b c d","( *)",[{parts,0},{return,list}]),
  435:     ?t:timetrap_cancel(Dog),
  436:     ok.
  437:     
  438: join([]) -> [];
  439: join([A]) -> [A];
  440: join([H|T]) -> [H,<<":">>|join(T)].
  441: 
  442: split_specials(doc) ->
  443:     ["Some special cases of split that are easy to get wrong."];
  444: split_specials(Config) when is_list(Config) ->
  445:     %% More or less just to remember these icky cases
  446:     Dog = ?t:timetrap(?t:minutes(1)),
  447:     ?line <<"::abd:f">> = 
  448: 	iolist_to_binary(join(re:split("abdf","^(?!(ab)de|x)(abd)(f)",[trim]))),
  449:     ?line <<":abc2xyzabc3">> = 
  450: 	iolist_to_binary(join(re:split("abc1abc2xyzabc3","\\Aabc.",[trim]))),
  451:     ?t:timetrap_cancel(Dog),
  452:     ok.
  453:     
  454: 
  455: %% Test that errors are handled correctly by the erlang code.
  456: error_handling(_Config) ->
  457:     case test_server:is_native(re) of
  458: 	true ->
  459: 	    %% Exceptions from native code look too different.
  460: 	    {skip,"re is native"};
  461: 	false ->
  462: 	    error_handling()
  463:     end.
  464: 	    
  465: error_handling() ->
  466:     % This test checks the exception tuples manufactured in the erlang
  467:     % code to hide the trapping from the user at least when it comes to errors
  468:     Dog = ?t:timetrap(?t:minutes(1)),
  469:     % The malformed precomiled RE is detected after 
  470:     % the trap to re:grun from grun, in the grun function clause
  471:     % that handles precompiled expressions
  472:     ?line {'EXIT',{badarg,[{re,run,["apa",{1,2,3,4},[global]],_},
  473: 			   {?MODULE,error_handling,0,_} | _]}} =
  474: 	(catch re:run("apa",{1,2,3,4},[global])),
  475:     % An invalid capture list will also cause a badarg late, 
  476:     % but with a non pre compiled RE, the exception should be thrown by the
  477:     % grun function clause that handles RE's compiled implicitly by
  478:     % the run/3 BIF before trapping.
  479:     ?line {'EXIT',{badarg,[{re,run,["apa","p",[{capture,[1,{a}]},global]],_},
  480: 			   {?MODULE,error_handling,0,_} | _]}} =
  481: 	(catch re:run("apa","p",[{capture,[1,{a}]},global])),
  482:     % And so the case of a precompiled expression together with
  483:     % a compile-option (binary and list subject):
  484:     ?line {ok,RE} = re:compile("(p)"),
  485:     ?line {match,[[{1,1},{1,1}]]} = re:run(<<"apa">>,RE,[global]),
  486:     ?line {match,[[{1,1},{1,1}]]} = re:run("apa",RE,[global]),
  487:     ?line {'EXIT',{badarg,[{re,run,
  488: 			    [<<"apa">>,
  489: 			     {re_pattern,1,0,_},
  490: 			     [global,unicode]],_},
  491: 			   {?MODULE,error_handling,0,_} | _]}} =
  492: 	(catch re:run(<<"apa">>,RE,[global,unicode])),
  493:     ?line {'EXIT',{badarg,[{re,run,
  494: 			    ["apa",
  495: 			     {re_pattern,1,0,_},
  496: 			     [global,unicode]],_},
  497: 			   {?MODULE,error_handling,0,_} | _]}} =
  498: 	(catch re:run("apa",RE,[global,unicode])),
  499:     ?line {'EXIT',{badarg,_}} = (catch re:run("apa","(p",[])),
  500:     ?line {'EXIT',{badarg,_}} = (catch re:run("apa","(p",[global])),
  501:     % The replace errors:
  502:     ?line {'EXIT',{badarg,[{re,replace,["apa",{1,2,3,4},"X",[]],_},
  503: 			   {?MODULE,error_handling,0,_} | _]}} =
  504: 	(catch re:replace("apa",{1,2,3,4},"X",[])),
  505:     ?line {'EXIT',{badarg,[{re,replace,["apa",{1,2,3,4},"X",[global]],_},
  506: 			   {?MODULE,error_handling,0,_} | _]}} =
  507: 	(catch re:replace("apa",{1,2,3,4},"X",[global])),
  508:     ?line {'EXIT',{badarg,[{re,replace,
  509: 			    ["apa",
  510: 			     {re_pattern,1,0,_},
  511: 			     "X",
  512: 			     [unicode]],_},
  513: 			   {?MODULE,error_handling,0,_} | _]}} =
  514: 	(catch re:replace("apa",RE,"X",[unicode])),
  515:     ?line <<"aXa">> = iolist_to_binary(re:replace("apa","p","X",[])),
  516:     ?line {'EXIT',{badarg,[{re,replace,
  517: 			    ["apa","p","X",[{capture,all,binary}]],_},
  518: 			   {?MODULE,error_handling,0,_} | _]}} =
  519: 	(catch iolist_to_binary(re:replace("apa","p","X",
  520: 					  [{capture,all,binary}]))),
  521:     ?line {'EXIT',{badarg,[{re,replace,
  522: 			    ["apa","p","X",[{capture,all}]],_},
  523: 			   {?MODULE,error_handling,0,_} | _]}} =
  524: 	(catch iolist_to_binary(re:replace("apa","p","X",
  525: 					  [{capture,all}]))),
  526:     ?line {'EXIT',{badarg,[{re,replace,
  527: 			    ["apa","p","X",[{return,banana}]],_},
  528: 			   {?MODULE,error_handling,0,_} | _]}} =
  529: 	(catch iolist_to_binary(re:replace("apa","p","X",
  530: 					  [{return,banana}]))),
  531:     ?line {'EXIT',{badarg,_}} = (catch re:replace("apa","(p","X",[])),
  532:     % Badarg, not compile error.
  533:     ?line {'EXIT',{badarg,[{re,replace,
  534: 			    ["apa","(p","X",[{return,banana}]],_},
  535: 			   {?MODULE,error_handling,0,_} | _]}} =
  536: 	(catch iolist_to_binary(re:replace("apa","(p","X",
  537: 					  [{return,banana}]))),
  538:     % And the split errors:
  539:     ?line [<<"a">>,<<"a">>] = (catch re:split("apa","p",[])),
  540:     ?line [<<"a">>,<<"p">>,<<"a">>] = (catch re:split("apa",RE,[])),
  541:     ?line {'EXIT',{badarg,[{re,split,["apa","p",[global]],_},
  542: 			   {?MODULE,error_handling,0,_} | _]}} =
  543: 	(catch re:split("apa","p",[global])),
  544:     ?line {'EXIT',{badarg,[{re,split,["apa","p",[{capture,all}]],_},
  545: 			   {?MODULE,error_handling,0,_} | _]}} =
  546: 	(catch re:split("apa","p",[{capture,all}])),
  547:     ?line {'EXIT',{badarg,[{re,split,["apa","p",[{capture,all,binary}]],_},
  548: 			   {?MODULE, error_handling,0,_} | _]}} =
  549: 	(catch re:split("apa","p",[{capture,all,binary}])),
  550:     ?line {'EXIT',{badarg,[{re,split,["apa",{1,2,3,4},[]],_},
  551: 			   {?MODULE,error_handling,0,_} | _]}} =
  552: 	(catch re:split("apa",{1,2,3,4})),
  553:     ?line {'EXIT',{badarg,[{re,split,["apa",{1,2,3,4},[]],_},
  554: 			   {?MODULE,error_handling,0,_} | _]}} =
  555: 	(catch re:split("apa",{1,2,3,4},[])),
  556:     ?line {'EXIT',{badarg,[{re,split,
  557: 			    ["apa",
  558: 			     RE,
  559: 			     [unicode]],_},
  560: 			   {?MODULE,error_handling,0,_} | _]}} =
  561: 	(catch re:split("apa",RE,[unicode])),
  562:     ?line {'EXIT',{badarg,[{re,split,
  563: 			    ["apa",
  564: 			     RE,
  565: 			     [{return,banana}]],_},
  566: 			   {?MODULE,error_handling,0,_} | _]}} =
  567: 	(catch re:split("apa",RE,[{return,banana}])),
  568:     ?line {'EXIT',{badarg,[{re,split,
  569: 			    ["apa",
  570: 			     RE,
  571: 			     [banana]],_},
  572: 			   {?MODULE,error_handling,0,_} | _]}} =
  573: 	(catch re:split("apa",RE,[banana])),
  574:     ?line {'EXIT',{badarg,_}} = (catch re:split("apa","(p")),
  575:     %Exception on bad argument, not compilation error
  576:     ?line {'EXIT',{badarg,[{re,split,
  577: 			    ["apa",
  578: 			     "(p",
  579: 			     [banana]],_},
  580: 			   {?MODULE,error_handling,0,_} | _]}} =
  581: 	(catch re:split("apa","(p",[banana])),
  582:     ?t:timetrap_cancel(Dog),
  583:     ok.
  584:     
  585: pcre_cve_2008_2371(doc) ->
  586:     "Fix as in http://vcs.pcre.org/viewvc?revision=360&view=revision";
  587: pcre_cve_2008_2371(Config) when is_list(Config) ->
  588:     %% Make sure it doesn't crash the emulator.
  589:     re:compile(<<"(?i)[\xc3\xa9\xc3\xbd]|[\xc3\xa9\xc3\xbdA]">>, [unicode]),
  590:     ok.
  591: 
  592: pcre_compile_workspace_overflow(doc) ->
  593:     "Patch from http://vcs.pcre.org/viewvc/code/trunk/pcre_compile.c?r1=504&r2=505&view=patch";
  594: pcre_compile_workspace_overflow(Config) when is_list(Config) ->
  595:     N = 819,
  596:     ?line {error,{"internal error: overran compiling workspace",799}} =
  597: 	re:compile([lists:duplicate(N, $(), lists:duplicate(N, $))]),
  598:     ok.
  599: re_infinite_loop(doc) ->
  600:     "Make sure matches that really loop infinitely actually fail";
  601: re_infinite_loop(Config) when is_list(Config) ->
  602:     Dog = ?t:timetrap(?t:minutes(1)),
  603:     ?line Str =
  604:         "http:/www.flickr.com/slideShow/index.gne?group_id=&user_id=69845378@N0",
  605:     ?line EMail_regex = "[a-z0-9!#$%&'*+/=?^_`{|}~-]+"
  606:         ++ "(\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*"
  607:         ++ "@.*([a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+"
  608:         ++ "([a-zA-Z]{2}|com|org|net|gov|mil"
  609:         ++ "|biz|info|mobi|name|aero|jobs|museum)",
  610:     ?line nomatch = re:run(Str, EMail_regex),
  611:     ?t:timetrap_cancel(Dog),
  612:     ok.