1: %% -*- coding: utf-8 -*-
    2: %%
    3: %% %CopyrightBegin%
    4: %%
    5: %% Copyright Ericsson AB 2004-2013. 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(nc_SUITE).
   21: 
   22: 
   23: -include_lib("common_test/include/ct.hrl").
   24: -include("test_server_line.hrl").
   25: 
   26: -define(VERSION_MAGIC,       131).
   27: 
   28: -define(ATOM_EXT,            100).
   29: -define(REFERENCE_EXT,       101).
   30: -define(PORT_EXT,            102).
   31: -define(PID_EXT,             103).
   32: -define(NEW_REFERENCE_EXT,   114).
   33: -define(ATOM_UTF8_EXT,       118).
   34: -define(SMALL_ATOM_UTF8_EXT, 119).
   35: 
   36: -export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
   37: 	 init_per_suite/1,
   38: 	 end_per_suite/1,
   39: 	 init_per_testcase/2,
   40: 	 end_per_testcase/2]).
   41: 
   42: -export([pid_roundtrip/1,
   43: 	 port_roundtrip/1,
   44: 	 ref_roundtrip/1,
   45: 	 new_float/1,
   46: 	 old_stuff/1,
   47: 	 binary_roundtrip/1,
   48: 	 decompress_roundtrip/1,
   49: 	 compress_roundtrip/1,
   50: 	 integer_roundtrip/1,
   51: 	 fun_roundtrip/1,
   52: 	 lists_roundtrip/1,
   53: 	 lists_roundtrip_2/1,
   54: 	 lists_iterator/1,
   55: 	 unicode/1,
   56: 	 unicode_list_to_string/1,
   57: 	 unicode_string_to_list/1,
   58: 	 utf8_atom/1,
   59: 	 utf8_pid/1,
   60: 	 utf8_port/1,
   61: 	 utf8_ref/1,
   62: 	 connect/1]).
   63: 
   64: 
   65: %% Top of cases
   66: 
   67: suite() -> [{ct_hooks,[ts_install_cth]}].
   68: 
   69: all() -> 
   70:     [pid_roundtrip, port_roundtrip, ref_roundtrip,
   71:      new_float, old_stuff, binary_roundtrip,
   72:      decompress_roundtrip, compress_roundtrip,
   73:      integer_roundtrip, fun_roundtrip, lists_roundtrip,
   74:      lists_roundtrip_2, lists_iterator, unicode,
   75:      unicode_list_to_string, unicode_string_to_list,
   76:      utf8_atom, utf8_pid, utf8_port, utf8_ref,
   77:      connect].
   78: 
   79: groups() -> 
   80:     [].
   81: 
   82: init_per_group(_GroupName, Config) ->
   83:     Config.
   84: 
   85: end_per_group(_GroupName, Config) ->
   86:     Config.
   87: 
   88: init_per_suite(Config) when is_list(Config) ->
   89:     case case code:priv_dir(jinterface) of
   90: 	     {error,bad_name} -> false;
   91: 	     P -> filelib:is_dir(P) end of
   92: 	true ->
   93: 	    jitu:init_all(Config);
   94: 	false ->
   95: 	    {skip,"No jinterface application"}
   96:     end.
   97: 
   98: end_per_suite(Config) ->
   99:     jitu:finish_all(Config).
  100: 
  101: 
  102: 
  103: %% Add/remove watchdog before/after each test case.
  104: %%
  105: init_per_testcase(Case, Config) ->
  106:     T = case atom_to_list(Case) of
  107: 	    "unicode"++_ -> 240;
  108: 	    _ -> 120
  109: 	end,
  110:     WatchDog = test_server:timetrap(test_server:seconds(T)),
  111:     [{watchdog, WatchDog}| Config].
  112: 
  113: end_per_testcase(_Case, Config) ->
  114:     jitu:kill_all_jnodes(),
  115:     WatchDog = ?config(watchdog, Config),
  116:     test_server:timetrap_cancel(WatchDog).
  117: 
  118: 
  119: %%
  120: %% Test cases
  121: %%
  122: 
  123: pid_roundtrip(doc) -> [];
  124: pid_roundtrip(suite) -> [];
  125: pid_roundtrip(Config) when is_list(Config)->
  126:     ThisNode = {node(), erlang:system_info(creation)},
  127:     RemNode = {gurka@sallad, 2},
  128:     do_echo([self(),
  129: 	     mk_pid(ThisNode, 4711, 4711),
  130: 	     mk_pid(ThisNode, 32767, 8191),
  131: 	     mk_pid(RemNode, 4711, 4711),
  132: 	     mk_pid(RemNode, 32767, 8191)],
  133: 	    Config).
  134: 
  135: fun_roundtrip(doc) -> [];
  136: fun_roundtrip(suite) -> [];
  137: fun_roundtrip(Config) when is_list(Config)->
  138:     do_echo([fun(A, B) -> A + B end,
  139: 	     fun(A) -> lists:reverse(A) end,
  140: 	     fun() -> ok end,
  141: 	     fun fun_roundtrip/1],
  142: 	    Config).
  143: 
  144: port_roundtrip(doc) -> [];
  145: port_roundtrip(suite) -> [];
  146: port_roundtrip(Config) when is_list(Config)->
  147:     ThisNode = {node(), erlang:system_info(creation)},
  148:     RemNode = {gurka@sallad, 2},
  149:     do_echo([hd(erlang:ports()),
  150: 	     mk_port(ThisNode, 4711),
  151: 	     mk_port(ThisNode, 268435455),
  152: 	     mk_port(RemNode, 4711),
  153: 	     mk_port(RemNode, 268435455)],
  154: 	    Config).
  155: 
  156: ref_roundtrip(doc) -> [];
  157: ref_roundtrip(suite) -> [];
  158: ref_roundtrip(Config) when is_list(Config)->
  159:     ThisNode = {node(), erlang:system_info(creation)},
  160:     RemNode = {gurka@sallad, 2},
  161:     do_echo([make_ref(),
  162: 	     mk_ref(ThisNode, [4711]),
  163: 	     mk_ref(ThisNode, [4711, 4711, 4711]),
  164: 	     mk_ref(ThisNode, [262143, 4294967295, 4294967295]),
  165: 	     mk_ref(RemNode, [4711]),
  166: 	     mk_ref(RemNode, [4711, 4711, 4711]),
  167: 	     mk_ref(RemNode, [262143, 4294967295, 4294967295])],
  168: 	    Config).
  169: 
  170: new_float(doc) -> [];
  171: new_float(suite) -> [];
  172: new_float(Config) when is_list(Config)->
  173:     Two16 = float(1 bsl 16),
  174:     X = math:sqrt(2),
  175:     Floats = lists:reverse(seq(1/X, 63, fun(Y) -> Y / Two16 end),
  176: 			   [0.0|seq(X, 63, fun(Y) -> Y * Two16 end)]),
  177:     io:format("~w", [Floats]),
  178:     do_echo(Floats, Config).
  179: 
  180: old_stuff(doc) -> [];
  181: old_stuff(suite) -> [];
  182: old_stuff(Config) when is_list(Config)->
  183:     Terms = [0.0,math:sqrt(2)],
  184:     OutTrans =
  185: 	fun (D) ->
  186: 		{self(),term_to_binary(D, [{minor_version,0}]),binary}
  187: 	end,
  188:     InTrans =
  189: 	fun (Echoer, D, {Echoer,D,binary}) ->
  190: 		ok
  191: 	end,
  192:     do_echo(Terms, Config, OutTrans, InTrans).
  193: 
  194: binary_roundtrip(doc) -> [];
  195: binary_roundtrip(suite) -> [];
  196: binary_roundtrip(Config) when is_list(Config) ->
  197:     do_echo([<<17>>,
  198: 	     <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17>>,
  199: 	     <<3:2>>,
  200: 	     <<3,7:3>>,
  201: 	     <<>>],
  202: 	    Config).
  203: 
  204: decompress_roundtrip(doc) -> [];
  205: decompress_roundtrip(suite) -> [];
  206: decompress_roundtrip(Config) when is_list(Config) ->
  207: 	RandomBin = erlang:term_to_binary(lists:seq(1, 5 * 1024 * 1024)), % roughly 26MB
  208: 	<<RandomBin1k:1024/binary,_/binary>> = RandomBin,
  209: 	<<RandomBin1M:1048576/binary,_/binary>> = RandomBin,
  210: 	<<RandomBin10M:10485760/binary,_/binary>> = RandomBin,
  211:     Terms =
  212: 	[{},
  213: 	 {a,b,c},
  214: 	 [],
  215: 	 0.0,
  216: 	 math:sqrt(2),
  217: 	 <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,31:5>>,
  218: 	 RandomBin1k,
  219: 	 RandomBin1M,
  220: 	 RandomBin10M,
  221: 	 RandomBin,
  222: 	 make_ref()],
  223:     OutTrans =
  224: 	fun (D) ->
  225: 		{self(),term_to_binary(D, [compressed]),binary}
  226: 	end,
  227:     InTrans =
  228: 	fun (Echoer, D, {Echoer,D,binary}) ->
  229: 		ok
  230: 	end,
  231:     do_echo(Terms, Config, OutTrans, InTrans).
  232: 
  233: compress_roundtrip(doc) -> [];
  234: compress_roundtrip(suite) -> [];
  235: compress_roundtrip(Config) when is_list(Config) ->
  236: 	RandomBin = erlang:term_to_binary(lists:seq(1, 5 * 1024 * 1024)), % roughly 26MB
  237: 	<<RandomBin1k:1024/binary,_/binary>> = RandomBin,
  238: 	<<RandomBin1M:1048576/binary,_/binary>> = RandomBin,
  239: 	<<RandomBin10M:10485760/binary,_/binary>> = RandomBin,
  240:     Terms =
  241: 	[{},
  242: 	 {a,b,c},
  243: 	 [],
  244: 	 0.0,
  245: 	 math:sqrt(2),
  246: 	 <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,31:5>>,
  247: 	 RandomBin1k,
  248: 	 RandomBin1M,
  249: 	 RandomBin10M,
  250: 	 RandomBin,
  251: 	 make_ref()],
  252:     OutTrans =
  253: 	fun (D) ->
  254: 		{self(),D,compress}
  255: 	end,
  256:     InTrans =
  257: 	fun (Echoer, D, {Echoer,B,compress}) ->
  258: 		D = binary_to_term(B)
  259: 	end,
  260:     do_echo(Terms, Config, OutTrans, InTrans).
  261: 
  262: 
  263: 
  264: integer_roundtrip(doc) -> [];
  265: integer_roundtrip(suite) -> [];
  266: integer_roundtrip(Config) when is_list(Config) ->
  267:     Xs = [1 bsl X || X <- [26,27,28,29,30,31,32,33,
  268: 			   62,63,64,65,
  269: 			   126,127,128,129]],
  270:     Terms = [0,1,-1,-2]
  271: 	++lists:flatmap(fun (X) -> [X-2,X-1,X,-X+1,-X,-X-1] end,
  272: 			Xs),
  273:     io:format("~w", [Terms]),
  274:     OutTrans =
  275: 	fun (V) ->
  276: 		{self(),V,bigint}
  277: 	end,
  278:     InTrans =
  279: 	fun (Echoer, V, {Echoer,{V,W,X,L,U},bigint}) ->
  280: 		Bitlength = bitlength(V),
  281: 		{w,W} = {w,signum(V) * Bitlength},
  282: 		Y = V band 16#FFFFffffFFFFffff,
  283: 		{y,Y} = {y,X band 16#FFFFffffFFFFffff},
  284: 		{l,L} = {l,if  V =:= X, Bitlength < 64 -> 1;
  285: 			       true                    -> 0  end},
  286: 		{u,U} = {u,if  V =:= Y, V >= 0, Bitlength =< 64 -> 1;
  287: 			       true                             -> 0  end}
  288: 	end,
  289:     do_echo(Terms, Config, OutTrans, InTrans).
  290: 
  291: signum(V) when is_integer(V), V > 0 ->  1;
  292: signum(V) when is_integer(V), V < 0 -> -1;
  293: signum(0) ->                            0.
  294: 
  295: bitlength(0) ->
  296:     0;
  297: bitlength(-1) ->
  298:     0;
  299: bitlength(V) when is_integer(V) ->
  300:     1 + bitlength(V bsr 1).
  301: 
  302: 
  303: 
  304: lists_roundtrip(doc) -> [];
  305: lists_roundtrip(suite) -> [];
  306: lists_roundtrip(Config) when is_list(Config) ->
  307:     Ls = [lists:seq(1,10),
  308: 	  lists:seq(11,17)++last_tail,
  309: 	  [{default}],
  310: 	  [car|cdr],
  311: 	  [[]],
  312: 	  []],
  313:     do_echo(Ls, Config).
  314: 
  315: 
  316: 
  317: lists_roundtrip_2(doc) -> [];
  318: lists_roundtrip_2(suite) -> [];
  319: lists_roundtrip_2(Config) when is_list(Config) ->
  320:     Ls = [{[a,b],tail},
  321: 	  {[c,d,e],tail},
  322: 	  {[],tail},
  323: 	  {[f],tail},
  324: 	  {[g,h|i],tail},
  325: 	  {[j,k,l|m],tail},
  326: 	  {[n|o],tail},
  327: 	  {[z,1,2,3,4],tail3},
  328: 	  {[z,5,6,7],tail3},
  329: 	  {[z,8,9],tail3},
  330: 	  {[z,10],tail3},
  331: 	  {[],tail3},
  332: 	  {[z,11,12,13,14|15],tail3},
  333: 	  {[z,16,17,18|19],tail3},
  334: 	  {[z,20,21|22],tail3},
  335: 	  {[z,23|24],tail3},
  336: 	  {[z|25],tail3},
  337: 	  {"abc123",sub3atom},
  338: 	  {"abc",sub3atom},
  339: 	  {"abcdefg",codepointBug}
  340: 	 ],
  341:     Trans =
  342: 	fun ([_|T], tail) ->
  343: 		T;
  344: 	    (L, tail) when is_list(L) ->
  345: 		null;
  346: 	    ([_,_,_|T], tail3) ->
  347: 		T;
  348: 	    (L, tail3) when is_list(L) ->
  349: 		null;
  350: 	    ([_,_,_|L], sub3atom) ->
  351: 		list_to_atom(L);
  352: 	    (L, codepointBug) ->
  353: 		L
  354: 	end,
  355:     OutTrans =
  356: 	fun ({L,Twist}) ->
  357: 		{self(),L,Twist}
  358: 	end,
  359:     InTrans =
  360: 	fun (Echoer, {L,Twist}, {Echoer,X,Twist}) ->
  361: 		Y = Trans(L, Twist),
  362: 		io:format("## ~w ~w ~w ~w~n", [L,Twist,X,Y]),
  363: 		X = Y
  364: 	end,
  365:     do_echo(Ls, Config, OutTrans, InTrans).
  366: 
  367: 
  368: 
  369: 
  370: lists_iterator(doc) -> [];
  371: lists_iterator(suite) -> [];
  372: lists_iterator(Config) when is_list(Config) ->
  373:     Ls = [["able ","was ","I ","ere ","I ","saw ","elba"]],
  374:     do_echo(Ls, Config,
  375: 	    fun (L) -> {self(),L,strcat} end,
  376: 	    fun (Echoer, L, {Echoer,X,strcat}) ->
  377: 		    io:format("## ~p ~p~n", [L,X]),
  378: 		    X = lists:flatten(L)
  379: 	    end).
  380: 
  381: 
  382: 
  383: unicode(doc) -> [];
  384: unicode(suite) -> [];
  385: unicode(Config) when is_list(Config) ->
  386:     S1 = "plain ascii",
  387:     S2 = "iso-latin åäö ñ",
  388:     S3 = "Codepoints... åäö \x{1000}",
  389:     S4 = [0,1,31,32,63,64,127,128,255],
  390:     S5 = [0,1,127,128,255,256,16#d7ff,
  391: 	  16#e000,16#fffd,16#10000,16#10ffff],
  392:     Ss = [S1,S2,S3,S4,S5],
  393:     do_echo(unicode_cp_gen([{S,valid} || S <- Ss] ++ cp_gen(71)), Config,
  394: 	    fun ({L,invalid}) -> {self(),L,utf8};
  395: 		({L,Tag}) -> {self(),L,Tag};
  396: 		({L})     -> {self(),L}
  397: 	    end,
  398: 	    fun (Echoer, {L,invalid}=Out, {Echoer,X,utf8}=In) ->
  399: 		    case L of
  400: 			X -> ok;
  401: 			_ ->
  402: 			    ?t:fail({mismatch,Out,In})
  403: 		    end;
  404: 		(Echoer, {L,Tag}=Out, {Echoer,X,Tag}=In) ->
  405: 		    case unicode:characters_to_binary(L, utf8) of
  406: 			X -> ok;
  407: 			_ ->
  408: 			    ?t:fail({mismatch,Out,In})
  409: 		    end;
  410: 		(Echoer, {L}=Out, {Echoer,X}=In) ->
  411: 		    case L of
  412: 			X -> ok;
  413: 			_ ->
  414: 			    ?t:fail({mismatch,Out,In})
  415: 		    end
  416: 	    end, ["unicode"]).
  417: 
  418: %% Lazy wrapper to lazy list
  419: unicode_cp_gen([{S,valid}|Ss]) ->
  420:     [{S,utf8},{S}|unicode_cp_gen(Ss)];
  421: unicode_cp_gen([{S,invalid}=St|Ss]) ->
  422:     [St,{S}|unicode_cp_gen(Ss)];
  423: unicode_cp_gen([]) ->
  424:     [];
  425: unicode_cp_gen(Cont) when is_function(Cont, 0) ->
  426:     fun () ->
  427: 	    unicode_cp_gen(Cont())
  428:     end.
  429: 
  430: 
  431: 
  432: unicode_list_to_string(doc) -> [];
  433: unicode_list_to_string(suite) -> [];
  434: unicode_list_to_string(Config) when is_list(Config) ->
  435:     do_echo(cp_gen(73), Config,
  436: 	    fun ({L,_}) -> {self(),L,to_string_neg_int_list} end,
  437: 	    fun (Echoer, {L,invalid}=Out, {Echoer,X,_}=In) ->
  438: 		    case L of
  439: 			X -> ok;
  440: 			_ ->
  441: 			    ?t:fail({mismatch,Out,In})
  442: 		    end;
  443: 		(Echoer, {L,valid}=Out, {Echoer,X,_}=In) ->
  444: 		    B = unicode:characters_to_binary(L, unicode, {utf16,big}),
  445: 		    case [-D || <<D:16/big>> <= B] of
  446: 			X -> ok;
  447: 			_ ->
  448: 			    ?t:fail({mismatch,Out,In})
  449: 		    end
  450: 	    end).
  451: 
  452: 
  453: 
  454: unicode_string_to_list(doc) -> [];
  455: unicode_string_to_list(suite) -> [];
  456: unicode_string_to_list(Config) when is_list(Config) ->
  457:     do_echo(cp_gen(79), Config,
  458: 	    fun ({L,_}) -> {self(),L,to_neg_int_list} end,
  459: 	    fun (Echoer, {L,invalid}=Out, {Echoer,X,_}=In) ->
  460: 		    case L of
  461: 			X -> ok;
  462: 			_ ->
  463: 			    ?t:fail({mismatch,Out,In})
  464: 		    end;
  465: 		(Echoer, {L,valid}=Out, {Echoer,X,_}=In) ->
  466: 		    case [-C || C <- L] of
  467: 			X -> ok;
  468: 			_ ->
  469: 			    ?t:fail({mismatch,Out,In})
  470: 		    end
  471: 	    end, ["unicode"]).
  472: 
  473: 
  474: evil_smiley() ->
  475:     <<240,159,152,136>>.
  476: 
  477: evil_smileys(0) ->
  478:     [];
  479: evil_smileys(N) ->
  480:     [evil_smiley() | evil_smileys(N-1)].
  481: 
  482: utf8_atom(Config) when is_list(Config) ->
  483:     ES = evil_smiley(),
  484:     SmallUA = binary_to_term(list_to_binary([?VERSION_MAGIC,
  485: 					     ?SMALL_ATOM_UTF8_EXT,
  486: 					     size(ES),
  487: 					     ES])),
  488:     true = is_atom(SmallUA),
  489:     NoESs = 300 div size(ES),
  490:     ESs = evil_smileys(NoESs),
  491:     LargeUA = binary_to_term(list_to_binary([?VERSION_MAGIC,
  492: 					     ?ATOM_UTF8_EXT,
  493: 					     uint16_be(NoESs*size(ES)),
  494: 					     ESs])),
  495:     true = is_atom(LargeUA),
  496:     erlang:display({atom, SmallUA, LargeUA}),
  497:     do_echo([SmallUA, LargeUA], Config).
  498: 
  499: utf8_nodenames_ext() ->
  500:     H = "@host",
  501:     ES = evil_smiley(),
  502:     SmallUANodeExt = list_to_binary([?SMALL_ATOM_UTF8_EXT,
  503: 				     size(ES)+length(H),
  504: 				     ES,
  505: 				     H]),
  506:     NoESs = 300 div size(ES),
  507:     ESs = evil_smileys(NoESs),
  508:     LargeUANodeExt = list_to_binary([?ATOM_UTF8_EXT,
  509: 				     uint16_be(NoESs*size(ES)+length(H)),
  510: 				     ESs,
  511: 				     H]),
  512:     {SmallUANodeExt, LargeUANodeExt}.
  513: 
  514: utf8_pid(Config) when is_list(Config) ->
  515:     {SmallUANodeExt, LargeUANodeExt} = utf8_nodenames_ext(),
  516:     SmallPid = mk_pid({SmallUANodeExt, 2}, 4711, 4711),
  517:     LargePid = mk_pid({LargeUANodeExt, 2}, 4711, 4711),
  518:     erlang:display({pid, SmallPid, node(SmallPid)}),
  519:     erlang:display({pid, LargePid, node(LargePid)}),
  520:     do_echo([SmallPid, LargePid], Config).
  521: 
  522: utf8_port(Config) when is_list(Config) ->
  523:     {SmallUANodeExt, LargeUANodeExt} = utf8_nodenames_ext(),
  524:     SmallPort = mk_port({SmallUANodeExt, 2}, 4711),
  525:     erlang:display({port, SmallPort, node(SmallPort)}),
  526:     LargePort = mk_port({LargeUANodeExt, 2}, 4711),
  527:     erlang:display({port, LargePort, node(LargePort)}),
  528:     do_echo([SmallPort, LargePort], Config).
  529: 
  530: utf8_ref(Config) when is_list(Config) ->
  531:     {SmallUANodeExt, LargeUANodeExt} = utf8_nodenames_ext(),
  532:     SmallRef = mk_ref({SmallUANodeExt, 2}, [4711, 4711, 4711]),
  533:     erlang:display({ref, SmallRef, node(SmallRef)}),
  534:     LargeRef = mk_ref({LargeUANodeExt, 2}, [4711, 4711, 4711]),
  535:     erlang:display({ref, LargeRef, node(LargeRef)}),
  536:     do_echo([SmallRef, LargeRef], Config).
  537:     
  538: 
  539: %% Lazy list
  540: cp_gen(N) ->
  541:     cp_gen(N, -1, 16#110000).
  542: 
  543: cp_gen(N, Start, End) ->
  544:     cp_gen(N, Start, End, cp_validity(Start), [], 0, [], 0).
  545: 
  546: cp_gen(N, U, End, PrevValidity, Acc, Len, Ss, Ls) when Len >= N ->
  547:     cp_gen(N, U, End, PrevValidity, [], 0, [{Acc,PrevValidity}|Ss], Ls+1);
  548: cp_gen(N, U, End, PrevValidity, Acc, Len, Ss, Ls) when Ls >= N ->
  549:     Ss ++ fun () ->
  550: 		  cp_gen(N, U, End, PrevValidity, Acc, Len, [], 0)
  551: 	  end;
  552: cp_gen(_, U, End, _, Acc, _, Ss, _) when U > End ->
  553:     [{Acc,valid}|Ss];
  554: cp_gen(N, U, End, PrevValidity, Acc, Len, Ss, Ls) ->
  555:     Validity = cp_validity(U),
  556:     NextU = U+1,
  557:     {NextAcc,NextLen} =	case Validity of
  558: 			    valid -> {[U|Acc],Len+1};
  559: 			    invalid -> {Acc,Len}
  560: 			end,
  561:     {NextSs,NextLs} = case Validity of
  562: 			  PrevValidity -> {Ss,Ls};
  563: 			  valid -> {[{[U-1],PrevValidity}|Ss],Ls+1};
  564: 			  invalid -> {[{[U],Validity}|Ss],Ls+1}
  565: 		      end,
  566:     cp_gen(N, NextU, End, Validity, NextAcc, NextLen, NextSs, NextLs).
  567: 
  568: cp_validity(UnicodeCP) ->
  569:     try <<UnicodeCP/big-utf32>> of
  570: 	_ -> valid
  571:     catch
  572: 	error:_ -> invalid
  573:     end.
  574: 
  575: 
  576: 
  577: connect(doc) -> [];
  578: connect(suite) -> [];
  579: connect(Config) when is_list(Config) ->
  580:     WD = filename:dirname(code:which(?MODULE)),
  581:     {ok,Other} = ?t:start_node(make_name(), slave, [{args,"-pa "++WD}]),
  582:     Action =
  583: 	fun (Pid) ->
  584: 		JName = node(Pid),
  585: 		Hidden = [JName],
  586: 		Pid ! {self(),Other},
  587: 		receive
  588: 		    {Pid,Other,true} ->
  589: 			ok;
  590: 		    Unexpected1 ->
  591: 			?t:fail({result,Unexpected1})
  592: 		end,
  593: 		Hidden = erlang:nodes(hidden),
  594: 		Hidden = rpc:call(Other, erlang, nodes, [hidden]),
  595: 		true =
  596: 		    rpc:call(Other, erlang, disconnect_node, [JName]),
  597: 		[] =
  598: 		    rpc:call(Other, erlang, nodes, [hidden]),
  599: 		Hidden = erlang:nodes(hidden),
  600: 		%% Again
  601: 		receive after 2000 -> ok end,
  602: 		%% We have no way of knowing when the Java node
  603: 		%% detects the nodedown.
  604: 		Pid ! {self(),Other},
  605: 		receive
  606: 		    {Pid,Other,true} ->
  607: 			ok;
  608: 		    Unexpected2->
  609: 			?t:fail({result,Unexpected2})
  610: 		end,
  611: 		Hidden = rpc:call(Other, erlang, nodes, [hidden])
  612: 	end,
  613:     run_server(connection_server, Config, Action, []).
  614: 
  615: 
  616: 
  617: seq(_, 0, _) ->
  618:     [];
  619: seq(X, N, Fun) ->
  620:     [X|seq(Fun(X), N-1, Fun)].
  621: 
  622: do_echo(DataList, Config) ->
  623:     do_echo(DataList, Config,
  624: 	    fun (D) -> % OutTrans
  625: 		    {self(),D}
  626: 	    end,
  627: 	    fun (Echoer, D, {Echoer,D}) -> % InTrans
  628: 		    ok
  629: 	    end, []).
  630: 
  631: do_echo(DataList, Config, OutTrans, InTrans) ->
  632:     do_echo(DataList, Config, OutTrans, InTrans, []).
  633: 
  634: do_echo(DataList, Config, OutTrans, InTrans, ExtraArgs)
  635:   when is_list(DataList), is_list(Config) ->
  636:     run_server(echo_server, Config,
  637: 	       fun (Echoer) ->
  638: 		       echo_loop(DataList, Echoer, OutTrans, InTrans, [])
  639: 	       end,
  640: 	       ExtraArgs).
  641: 
  642: echo_loop([D|Ds], Echoer, OutTrans, InTrans, TermAcc) ->
  643:     OutMsg = OutTrans(D),
  644:     Echoer ! OutMsg,
  645:     io:format("echo_server ~p: ~p ! ~P~n", [self(),Echoer,OutMsg,10]),
  646:     receive
  647: 	Reply ->
  648: 	    io:format("echo_server ~p: receive ~P~n",
  649: 		      [self(),Reply,10]),
  650: 	    InTrans(Echoer, D, Reply)
  651:     end,
  652:     Term = case OutMsg of
  653: 	       {_, T, _} -> T;
  654: 	       {_, T} -> T
  655: 	   end,
  656:     echo_loop(Ds, Echoer, OutTrans, InTrans, [Term | TermAcc]);
  657: echo_loop([], Echoer, _, _, TermAcc) ->
  658:     check_terms(Echoer, TermAcc);
  659: %% Lazy list
  660: echo_loop(Cont, Echoer, OutTrans, InTrans, TermAcc)
  661:   when is_function(Cont, 0) ->
  662:     check_terms(Echoer, TermAcc),
  663:     OutMsg = Echoer ! {self(),undefined,hash_clear},
  664:     io:format("echo_server ~p: ~p ! ~P~n", [self(),Echoer,OutMsg,10]),
  665:     receive
  666: 	{Echoer,hash_cleared,hash_clear}=Reply ->
  667: 	    io:format("echo_server ~p: receive ~P~n",
  668: 		      [self(),Reply,10]),
  669: 	    ok;
  670: 	Other ->
  671: 	    io:format("echo_server_terms unexpected ~p: receive ~P~n",
  672: 		      [self(),Other,10]),
  673: 	    ?t:fail({unexpected, Other})
  674:     end,
  675:     echo_loop(Cont(), Echoer, OutTrans, InTrans, []).
  676: 
  677: check_terms(Echoer, [Term | Rest]) ->
  678:     OutMsg = {self(),Term,hash_lookup},
  679:     Echoer ! OutMsg,
  680:     io:format("check_terms ~p: ~p ! ~P~n", [self(),Echoer,OutMsg,10]),
  681:     receive
  682: 	{Echoer,true,hash_lookup} = ReplyMsg ->
  683: 	    io:format("check_terms ~p: receive ~P~n",
  684: 		      [self(),ReplyMsg,10]),
  685: 	    check_terms(Echoer, Rest);
  686: 	Other ->
  687: 	    io:format("check_terms unexpected ~p: receive ~P~n",
  688: 		      [self(),Other,10]),
  689: 	    ?t:fail({unexpected, Other})
  690:     end;
  691: check_terms(_, []) ->
  692:     ok.
  693: 
  694: run_server(Server, Config, Action, ExtraArgs) ->
  695:     Name = make_name(),
  696:     true = register(Name, self()),
  697:     JName = make_name(),
  698:     spawn_link(fun () ->
  699: 		       %% Setting max memory to 256. This is due to
  700: 		       %% echo_server sometimes failing with
  701: 		       %% OutOfMemoryException one some test machines.
  702: 		       ok = jitu:java(?config(java, Config),
  703: 				      ?config(data_dir, Config),
  704: 				      atom_to_list(Server),
  705: 				      [JName,
  706: 				       erlang:get_cookie(),
  707: 				       node(),
  708: 				       Name]++ExtraArgs,
  709: 				      " -Xmx256m"),
  710: 				      %% " -Xmx256m -DOtpConnection.trace=3"),
  711: 		       Name ! {done, JName}
  712: 	       end),
  713:     receive
  714: 	{Server, JName, Pid} ->
  715: 	    ?t:format("~w: ~p (~p)~n",
  716: 		      [Server, Pid, node(Pid)]),
  717: 	    ?t:format("nodes(hidden): ~p~n",
  718: 		      [nodes(hidden)]),
  719: 	    Action(Pid),
  720: 	    Pid ! bye,
  721: 	    receive
  722: 		{done, JName} ->
  723: 		    ok
  724: 	    end;
  725: 	Other ->
  726: 	    ?t:fail({unexpected,Other})
  727:     end.
  728: 
  729: %%
  730: %% Utils...
  731: %%
  732: 
  733: make_name() ->
  734:     {A, B, C} = now(),
  735:     list_to_atom(atom_to_list(?MODULE)
  736: 		 ++ "-" ++ integer_to_list(A)
  737: 		 ++ "-" ++ integer_to_list(B)
  738: 		 ++ "-" ++ integer_to_list(C)).
  739: 
  740: uint32_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 32 ->
  741:     [(Uint bsr 24) band 16#ff,
  742:      (Uint bsr 16) band 16#ff,
  743:      (Uint bsr 8) band 16#ff,
  744:      Uint band 16#ff];
  745: uint32_be(Uint) ->
  746:     exit({badarg, uint32_be, [Uint]}).
  747: 
  748: 
  749: uint16_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 16 ->
  750:     [(Uint bsr 8) band 16#ff,
  751:      Uint band 16#ff];
  752: uint16_be(Uint) ->
  753:     exit({badarg, uint16_be, [Uint]}).
  754: 
  755: uint8(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 8 ->
  756:     Uint band 16#ff;
  757: uint8(Uint) ->
  758:     exit({badarg, uint8, [Uint]}).
  759: 
  760: 
  761: 
  762: mk_pid({NodeName, Creation}, Number, Serial) when is_atom(NodeName) ->
  763:     <<?VERSION_MAGIC, NodeNameExt/binary>> = term_to_binary(NodeName),
  764:     mk_pid({NodeNameExt, Creation}, Number, Serial);
  765: mk_pid({NodeNameExt, Creation}, Number, Serial) ->
  766:     case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
  767: 					      ?PID_EXT,
  768: 					      NodeNameExt,
  769: 					      uint32_be(Number),
  770: 					      uint32_be(Serial),
  771: 					      uint8(Creation)])) of
  772: 	Pid when is_pid(Pid) ->
  773: 	    Pid;
  774: 	{'EXIT', {badarg, _}} ->
  775: 	    exit({badarg, mk_pid, [{NodeNameExt, Creation}, Number, Serial]});
  776: 	Other ->
  777: 	    exit({unexpected_binary_to_term_result, Other})
  778:     end.
  779: 
  780: mk_port({NodeName, Creation}, Number) when is_atom(NodeName) ->
  781:     <<?VERSION_MAGIC, NodeNameExt/binary>> = term_to_binary(NodeName),
  782:     mk_port({NodeNameExt, Creation}, Number);
  783: mk_port({NodeNameExt, Creation}, Number) ->
  784:     case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
  785: 					      ?PORT_EXT,
  786: 					      NodeNameExt,
  787: 					      uint32_be(Number),
  788: 					      uint8(Creation)])) of
  789: 	Port when is_port(Port) ->
  790: 	    Port;
  791: 	{'EXIT', {badarg, _}} ->
  792: 	    exit({badarg, mk_port, [{NodeNameExt, Creation}, Number]});
  793: 	Other ->
  794: 	    exit({unexpected_binary_to_term_result, Other})
  795:     end.
  796: 
  797: mk_ref({NodeName, Creation}, [Number] = NL) when is_atom(NodeName),
  798: 						 is_integer(Creation),
  799: 						 is_integer(Number) ->
  800:     <<?VERSION_MAGIC, NodeNameExt/binary>> = term_to_binary(NodeName),
  801:     mk_ref({NodeNameExt, Creation}, NL);
  802: mk_ref({NodeNameExt, Creation}, [Number]) when is_integer(Creation),
  803: 					       is_integer(Number) ->
  804:     case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
  805: 					      ?REFERENCE_EXT,
  806: 					      NodeNameExt,
  807: 					      uint32_be(Number),
  808: 					      uint8(Creation)])) of
  809: 	Ref when is_reference(Ref) ->
  810: 	    Ref;
  811: 	{'EXIT', {badarg, _}} ->
  812: 	    exit({badarg, mk_ref, [{NodeNameExt, Creation}, [Number]]});
  813: 	Other ->
  814: 	    exit({unexpected_binary_to_term_result, Other})
  815:     end;
  816: mk_ref({NodeName, Creation}, Numbers) when is_atom(NodeName),
  817: 					   is_integer(Creation),
  818: 					   is_list(Numbers) ->
  819:     <<?VERSION_MAGIC, NodeNameExt/binary>> = term_to_binary(NodeName),
  820:     mk_ref({NodeNameExt, Creation}, Numbers);
  821: mk_ref({NodeNameExt, Creation}, Numbers) when is_integer(Creation),
  822: 					      is_list(Numbers) ->
  823:     case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
  824: 					      ?NEW_REFERENCE_EXT,
  825: 					      uint16_be(length(Numbers)),
  826: 					      NodeNameExt,
  827: 					      uint8(Creation),
  828: 					      lists:map(fun (N) ->
  829: 								uint32_be(N)
  830: 							end,
  831: 							Numbers)])) of
  832: 	Ref when is_reference(Ref) ->
  833: 	    Ref;
  834: 	{'EXIT', {badarg, _}} ->
  835: 	    exit({badarg, mk_ref, [{NodeNameExt, Creation}, Numbers]});
  836: 	Other ->
  837: 	    exit({unexpected_binary_to_term_result, Other})
  838:     end.