auser-poolparty 0.2.66 → 0.2.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Manifest.txt +83 -41
- data/PostInstall.txt +2 -2
- data/README.txt +1 -2
- data/Rakefile +14 -1
- data/bin/cloud-start +11 -10
- data/bin/{pool-spec → pool-generate} +0 -0
- data/bin/pool-init +3 -3
- data/bin/pool-start +8 -7
- data/bin/server-update-hosts +1 -1
- data/lib/erlang/messenger/ebin/pm_client_rel-0.1.rel +1 -1
- data/lib/erlang/messenger/ebin/pm_master_rel-0.1.rel +1 -1
- data/lib/erlang/messenger/ebin/pm_node_rel-0.1.rel +1 -1
- data/lib/erlang/messenger/include/defines.hrl +7 -3
- data/lib/erlang/messenger/lib/eunit/.svn/all-wcprops +53 -0
- data/lib/erlang/messenger/lib/eunit/.svn/entries +140 -0
- data/lib/erlang/messenger/lib/eunit/.svn/format +1 -0
- data/lib/erlang/messenger/lib/eunit/.svn/prop-base/NOTES.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/.svn/text-base/AUTHORS.svn-base +2 -0
- data/lib/erlang/messenger/lib/eunit/.svn/text-base/CHANGELOG.svn-base +14 -0
- data/lib/erlang/messenger/lib/eunit/.svn/text-base/COPYING.svn-base +504 -0
- data/lib/erlang/messenger/lib/eunit/.svn/text-base/NOTES.svn-base +276 -0
- data/lib/erlang/messenger/lib/eunit/.svn/text-base/README.svn-base +3 -0
- data/lib/erlang/messenger/lib/eunit/.svn/text-base/sys.config.svn-base +9 -0
- data/lib/erlang/messenger/lib/eunit/.svn/text-base/vsn.mk.svn-base +1 -0
- data/lib/erlang/messenger/lib/eunit/doc/.svn/all-wcprops +59 -0
- data/lib/erlang/messenger/lib/eunit/doc/.svn/entries +142 -0
- data/lib/erlang/messenger/lib/eunit/doc/.svn/format +1 -0
- data/lib/erlang/messenger/lib/eunit/doc/.svn/prop-base/erlang.png.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/doc/.svn/prop-base/eunit.html.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/doc/.svn/prop-base/index.html.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/doc/.svn/prop-base/modules-frame.html.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/doc/.svn/prop-base/overview-summary.html.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/doc/.svn/prop-base/packages-frame.html.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/doc/.svn/text-base/edoc-info.svn-base +3 -0
- data/lib/erlang/messenger/lib/eunit/doc/.svn/text-base/erlang.png.svn-base +0 -0
- data/lib/erlang/messenger/lib/eunit/doc/.svn/text-base/eunit.html.svn-base +172 -0
- data/lib/erlang/messenger/lib/eunit/doc/.svn/text-base/index.html.svn-base +17 -0
- data/lib/erlang/messenger/lib/eunit/doc/.svn/text-base/modules-frame.html.svn-base +12 -0
- data/lib/erlang/messenger/lib/eunit/doc/.svn/text-base/overview-summary.html.svn-base +984 -0
- data/lib/erlang/messenger/lib/eunit/doc/.svn/text-base/overview.edoc.svn-base +980 -0
- data/lib/erlang/messenger/lib/eunit/doc/.svn/text-base/packages-frame.html.svn-base +11 -0
- data/lib/erlang/messenger/lib/eunit/doc/.svn/text-base/stylesheet.css.svn-base +55 -0
- data/lib/erlang/messenger/lib/eunit/ebin/.svn/all-wcprops +5 -0
- data/lib/erlang/messenger/lib/eunit/ebin/.svn/dir-prop-base +8 -0
- data/lib/erlang/messenger/lib/eunit/ebin/.svn/entries +28 -0
- data/lib/erlang/messenger/lib/eunit/ebin/.svn/format +1 -0
- data/lib/erlang/messenger/lib/eunit/examples/.svn/all-wcprops +23 -0
- data/lib/erlang/messenger/lib/eunit/examples/.svn/entries +66 -0
- data/lib/erlang/messenger/lib/eunit/examples/.svn/format +1 -0
- data/lib/erlang/messenger/lib/eunit/examples/.svn/prop-base/eunit_examples.erl.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/examples/.svn/prop-base/fib.erl.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/examples/.svn/text-base/eunit_examples.erl.svn-base +339 -0
- data/lib/erlang/messenger/lib/eunit/examples/.svn/text-base/fib.erl.svn-base +19 -0
- data/lib/erlang/messenger/lib/eunit/examples/.svn/text-base/tests.txt.svn-base +1 -0
- data/lib/erlang/messenger/lib/eunit/include/.svn/all-wcprops +11 -0
- data/lib/erlang/messenger/lib/eunit/include/.svn/entries +41 -0
- data/lib/erlang/messenger/lib/eunit/include/.svn/format +1 -0
- data/lib/erlang/messenger/lib/eunit/include/.svn/prop-base/eunit.hrl.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/include/.svn/text-base/eunit.hrl.svn-base +313 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/all-wcprops +113 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/entries +259 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/format +1 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/autoload.erl.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/code_monitor.erl.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit.erl.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_autoexport.erl.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_data.erl.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_internal.hrl.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_lib.erl.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_proc.erl.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_serial.erl.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_server.erl.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_striptests.erl.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_test.erl.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_tests.erl.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/eunit_tty.erl.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/prop-base/file_monitor.erl.svn-base +5 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/autoload.erl.svn-base +388 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/code_monitor.erl.svn-base +243 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit.app.src.svn-base +21 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit.appup.src.svn-base +1 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit.erl.svn-base +196 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_autoexport.erl.svn-base +102 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_data.erl.svn-base +798 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_internal.hrl.svn-base +48 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_lib.erl.svn-base +682 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_proc.erl.svn-base +552 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_serial.erl.svn-base +157 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_server.erl.svn-base +340 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_striptests.erl.svn-base +64 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_test.erl.svn-base +334 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_tests.erl.svn-base +45 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/eunit_tty.erl.svn-base +272 -0
- data/lib/erlang/messenger/lib/eunit/src/.svn/text-base/file_monitor.erl.svn-base +409 -0
- data/lib/erlang/messenger/pm_client_rel-0.1.boot +0 -0
- data/lib/erlang/messenger/pm_client_rel-0.1.script +77 -85
- data/lib/erlang/messenger/pm_master_rel-0.1.boot +0 -0
- data/lib/erlang/messenger/pm_master_rel-0.1.script +78 -85
- data/lib/erlang/messenger/pm_node_rel-0.1.boot +0 -0
- data/lib/erlang/messenger/pm_node_rel-0.1.script +77 -86
- data/lib/erlang/messenger/src/pm_node.erl +46 -9
- data/lib/erlang/messenger/src/utils.erl +7 -1
- data/lib/poolparty.rb +17 -23
- data/lib/poolparty/base_packages/poolparty.rb +1 -1
- data/lib/poolparty/core/string.rb +11 -2
- data/lib/poolparty/helpers/binary.rb +31 -0
- data/lib/poolparty/helpers/console.rb +25 -16
- data/lib/poolparty/helpers/nice_printer.rb +36 -0
- data/lib/poolparty/helpers/optioner.rb +8 -0
- data/lib/poolparty/helpers/provisioner_base.rb +7 -5
- data/lib/poolparty/helpers/provisioners/master.rb +1 -1
- data/lib/poolparty/helpers/provisioners/slave.rb +2 -1
- data/lib/poolparty/modules/cloud_resourcer.rb +1 -1
- data/lib/poolparty/modules/file_writer.rb +12 -1
- data/lib/poolparty/modules/resourcing_dsl.rb +2 -1
- data/lib/poolparty/monitors/base_monitor.rb +3 -0
- data/lib/poolparty/net/remoter.rb +13 -11
- data/lib/poolparty/pool/base.rb +25 -13
- data/lib/poolparty/pool/cloud.rb +32 -10
- data/lib/poolparty/pool/custom_resource.rb +16 -7
- data/lib/poolparty/pool/plugin_model.rb +2 -2
- data/lib/poolparty/pool/pool.rb +2 -2
- data/lib/poolparty/pool/resource.rb +25 -7
- data/lib/poolparty/pool/resources/class_package.rb +3 -2
- data/lib/poolparty/pool/resources/exec.rb +1 -1
- data/lib/poolparty/pool/resources/variable.rb +4 -0
- data/lib/poolparty/version.rb +1 -1
- data/poolparty.gemspec +13 -11
- data/spec/poolparty/core/hash_spec.rb +1 -1
- data/spec/poolparty/core/time_spec.rb +1 -1
- data/spec/poolparty/net/remote_spec.rb +1 -1
- data/spec/poolparty/pool/base_spec.rb +25 -20
- data/spec/poolparty/pool/cloud_spec.rb +50 -3
- data/spec/poolparty/pool/plugin_spec.rb +1 -0
- data/spec/poolparty/pool/resource_spec.rb +4 -3
- data/spec/poolparty/spec_helper.rb +3 -4
- data/tasks/deployment.rake +15 -3
- data/website/index.html +2 -2
- metadata +88 -46
- data/lib/erlang/messenger/Makefile +0 -15
- data/lib/erlang/messenger/lib/eunit/Makefile +0 -28
- data/lib/erlang/messenger/lib/eunit/ebin/autoload.beam +0 -0
- data/lib/erlang/messenger/lib/eunit/ebin/code_monitor.beam +0 -0
- data/lib/erlang/messenger/lib/eunit/ebin/eunit.beam +0 -0
- data/lib/erlang/messenger/lib/eunit/ebin/eunit_autoexport.beam +0 -0
- data/lib/erlang/messenger/lib/eunit/ebin/eunit_data.beam +0 -0
- data/lib/erlang/messenger/lib/eunit/ebin/eunit_lib.beam +0 -0
- data/lib/erlang/messenger/lib/eunit/ebin/eunit_proc.beam +0 -0
- data/lib/erlang/messenger/lib/eunit/ebin/eunit_serial.beam +0 -0
- data/lib/erlang/messenger/lib/eunit/ebin/eunit_server.beam +0 -0
- data/lib/erlang/messenger/lib/eunit/ebin/eunit_striptests.beam +0 -0
- data/lib/erlang/messenger/lib/eunit/ebin/eunit_test.beam +0 -0
- data/lib/erlang/messenger/lib/eunit/ebin/eunit_tests.beam +0 -0
- data/lib/erlang/messenger/lib/eunit/ebin/eunit_tty.beam +0 -0
- data/lib/erlang/messenger/lib/eunit/ebin/file_monitor.beam +0 -0
- data/lib/erlang/messenger/lib/eunit/src/Makefile +0 -46
- data/lib/poolparty/config/allowed_commands.yml +0 -1
- data/lib/poolparty/plugins/git.rb +0 -45
- data/spec/poolparty/plugins/git_spec.rb +0 -40
@@ -0,0 +1,48 @@
|
|
1
|
+
%%%-------------------------------------------------------------------
|
2
|
+
%% File: eunit_internal.hrl
|
3
|
+
%%
|
4
|
+
%% $Id:$
|
5
|
+
%%
|
6
|
+
%% @author Richard Carlsson <richardc@it.uu.se>
|
7
|
+
%% @copyright 2006 Richard Carlsson
|
8
|
+
%% @doc
|
9
|
+
|
10
|
+
-define(SERVER, eunit_server).
|
11
|
+
-define(DEFAULT_TEST_SUFFIX, "_test").
|
12
|
+
-define(DEFAULT_GENERATOR_SUFFIX, "_test_").
|
13
|
+
-define(DEFAULT_EXPORT_SUFFIX, "_exported_").
|
14
|
+
-define(DEFAULT_TESTMODULE_SUFFIX, "_tests").
|
15
|
+
-define(DEFAULT_GROUP_TIMEOUT, infinity).
|
16
|
+
-define(DEFAULT_TEST_TIMEOUT, 5000).
|
17
|
+
-define(DEFAULT_SETUP_PROCESS, spawn).
|
18
|
+
|
19
|
+
-ifdef(DEBUG).
|
20
|
+
-define(debugmsg(S),io:fwrite("\n* ~s: ~s\n", [?MODULE,S])).
|
21
|
+
-define(debugmsg1(S,As),io:fwrite("\n* ~s: " ++ S ++ "\n", [?MODULE] ++ As)).
|
22
|
+
-else.
|
23
|
+
-define(debugmsg(S),ok).
|
24
|
+
-define(debugmsg1(S,As),ok).
|
25
|
+
-endif.
|
26
|
+
|
27
|
+
|
28
|
+
%% ---------------------------------------------------------------------
|
29
|
+
%% Internal test data representation
|
30
|
+
|
31
|
+
-record(test, {f = undefined,
|
32
|
+
desc = undefined,
|
33
|
+
timeout = undefined,
|
34
|
+
module = undefined,
|
35
|
+
name = undefined,
|
36
|
+
line = 0
|
37
|
+
}).
|
38
|
+
|
39
|
+
-record(group, {desc = undefined,
|
40
|
+
order = undefined, % run in order or in parallel
|
41
|
+
timeout = undefined,
|
42
|
+
context = undefined, % setup-context record
|
43
|
+
spawn = undefined, % run group in new process
|
44
|
+
tests = undefined}).
|
45
|
+
|
46
|
+
-record(context, {setup = undefined,
|
47
|
+
cleanup = undefined,
|
48
|
+
process = local}). % spawn new process for body
|
@@ -0,0 +1,682 @@
|
|
1
|
+
%% This library is free software; you can redistribute it and/or modify
|
2
|
+
%% it under the terms of the GNU Lesser General Public License as
|
3
|
+
%% published by the Free Software Foundation; either version 2 of the
|
4
|
+
%% License, or (at your option) any later version.
|
5
|
+
%%
|
6
|
+
%% This library is distributed in the hope that it will be useful, but
|
7
|
+
%% WITHOUT ANY WARRANTY; without even the implied warranty of
|
8
|
+
%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
9
|
+
%% Lesser General Public License for more details.
|
10
|
+
%%
|
11
|
+
%% You should have received a copy of the GNU Lesser General Public
|
12
|
+
%% License along with this library; if not, write to the Free Software
|
13
|
+
%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
14
|
+
%% USA
|
15
|
+
%%
|
16
|
+
%% $Id$
|
17
|
+
%%
|
18
|
+
%% @copyright 2004-2007 Micka�l R�mond, Richard Carlsson
|
19
|
+
%% @author Micka�l R�mond <mickael.remond@process-one.net>
|
20
|
+
%% [http://www.process-one.net/]
|
21
|
+
%% @author Richard Carlsson <richardc@it.uu.se>
|
22
|
+
%% [http://user.it.uu.se/~richardc/]
|
23
|
+
%% @private
|
24
|
+
%% @see eunit
|
25
|
+
%% @doc Utility functions for eunit
|
26
|
+
|
27
|
+
-module(eunit_lib).
|
28
|
+
|
29
|
+
-include("eunit.hrl").
|
30
|
+
-include("eunit_internal.hrl").
|
31
|
+
|
32
|
+
|
33
|
+
-export([dlist_next/1, uniq/1, fun_parent/1, is_string/1, browse_fun/1,
|
34
|
+
command/1, command/2, command/3, trie_new/0, trie_store/2,
|
35
|
+
trie_match/2, split_node/1, consult_file/1, list_dir/1,
|
36
|
+
format_exit_term/1, format_exception/1, format_error/1]).
|
37
|
+
|
38
|
+
|
39
|
+
%% Type definitions for describing exceptions
|
40
|
+
%%
|
41
|
+
%% @type exception() = {exceptionClass(), Reason::term(), stackTrace()}
|
42
|
+
%%
|
43
|
+
%% @type exceptionClass() = error | exit | throw
|
44
|
+
%%
|
45
|
+
%% @type stackTrace() = [{moduleName(), functionName(),
|
46
|
+
%% arity() | argList()}]
|
47
|
+
%%
|
48
|
+
%% @type moduleName() = atom()
|
49
|
+
%% @type functionName() = atom()
|
50
|
+
%% @type arity() = integer()
|
51
|
+
%% @type mfa() = {moduleName(), functionName(), arity()}
|
52
|
+
%% @type argList() = [term()]
|
53
|
+
%% @type fileName() = string()
|
54
|
+
|
55
|
+
|
56
|
+
%% ---------------------------------------------------------------------
|
57
|
+
%% Formatting of error descriptors
|
58
|
+
|
59
|
+
format_exception({Class,Term,Trace})
|
60
|
+
when is_atom(Class), is_list(Trace) ->
|
61
|
+
case is_stacktrace(Trace) of
|
62
|
+
true ->
|
63
|
+
io_lib:format("~w:~P\n~s",
|
64
|
+
[Class, Term, 15, format_stacktrace(Trace)]);
|
65
|
+
false ->
|
66
|
+
format_term(Term)
|
67
|
+
end;
|
68
|
+
format_exception(Term) ->
|
69
|
+
format_term(Term).
|
70
|
+
|
71
|
+
format_term(Term) ->
|
72
|
+
io_lib:format("~P\n", [Term, 15]).
|
73
|
+
|
74
|
+
format_exit_term(Term) ->
|
75
|
+
{Reason, Trace} = analyze_exit_term(Term),
|
76
|
+
io_lib:format("~P~s", [Reason, 15, Trace]).
|
77
|
+
|
78
|
+
analyze_exit_term({Reason, [_|_]=Trace}=Term) ->
|
79
|
+
case is_stacktrace(Trace) of
|
80
|
+
true ->
|
81
|
+
{Reason, format_stacktrace(Trace)};
|
82
|
+
false ->
|
83
|
+
{Term, ""}
|
84
|
+
end;
|
85
|
+
analyze_exit_term(Term) ->
|
86
|
+
{Term, ""}.
|
87
|
+
|
88
|
+
is_stacktrace([]) ->
|
89
|
+
true;
|
90
|
+
is_stacktrace([{M,F,A}|Fs]) when is_atom(M), is_atom(F), is_integer(A) ->
|
91
|
+
is_stacktrace(Fs);
|
92
|
+
is_stacktrace([{M,F,As}|Fs]) when is_atom(M), is_atom(F), is_list(As) ->
|
93
|
+
is_stacktrace(Fs);
|
94
|
+
is_stacktrace(_) ->
|
95
|
+
false.
|
96
|
+
|
97
|
+
format_stacktrace(Trace) ->
|
98
|
+
format_stacktrace(Trace, "in function", "in call from").
|
99
|
+
|
100
|
+
format_stacktrace([{M,F,A}|Fs], Pre, Pre1) when is_integer(A) ->
|
101
|
+
[io_lib:fwrite(" ~s ~w:~w/~w\n", [Pre, M, F, A])
|
102
|
+
| format_stacktrace(Fs, Pre1, Pre1)];
|
103
|
+
format_stacktrace([{M,F,As}|Fs], Pre, Pre1) when is_list(As) ->
|
104
|
+
A = length(As),
|
105
|
+
C = case is_op(M,F,A) of
|
106
|
+
true when A == 1 ->
|
107
|
+
[A1] = As,
|
108
|
+
io_lib:fwrite("~s ~s", [F,format_arg(A1)]);
|
109
|
+
true when A == 2 ->
|
110
|
+
[A1, A2] = As,
|
111
|
+
io_lib:fwrite("~s ~s ~s",
|
112
|
+
[format_arg(A1),F,format_arg(A2)]);
|
113
|
+
false ->
|
114
|
+
io_lib:fwrite("~w(~s)", [F,format_arglist(As)])
|
115
|
+
end,
|
116
|
+
[io_lib:fwrite(" ~s ~w:~w/~w\n called as ~s\n",
|
117
|
+
[Pre,M,F,A,C])
|
118
|
+
| format_stacktrace(Fs,Pre1,Pre1)];
|
119
|
+
format_stacktrace([],_Pre,_Pre1) ->
|
120
|
+
"".
|
121
|
+
|
122
|
+
format_arg(A) ->
|
123
|
+
io_lib:format("~P",[A,15]).
|
124
|
+
|
125
|
+
format_arglist([A]) ->
|
126
|
+
format_arg(A);
|
127
|
+
format_arglist([A|As]) ->
|
128
|
+
[io_lib:format("~P,",[A,15]) | format_arglist(As)];
|
129
|
+
format_arglist([]) ->
|
130
|
+
"".
|
131
|
+
|
132
|
+
is_op(erlang, F, A) ->
|
133
|
+
erl_internal:arith_op(F, A)
|
134
|
+
orelse erl_internal:bool_op(F, A)
|
135
|
+
orelse erl_internal:comp_op(F, A)
|
136
|
+
orelse erl_internal:list_op(F, A)
|
137
|
+
orelse erl_internal:send_op(F, A);
|
138
|
+
is_op(_M, _F, _A) ->
|
139
|
+
false.
|
140
|
+
|
141
|
+
format_error({bad_test, Term}) ->
|
142
|
+
error_msg("bad test descriptor", "~P", [Term, 15]);
|
143
|
+
format_error({generator_failed, Exception}) ->
|
144
|
+
error_msg("test generator failed", "~s",
|
145
|
+
[format_exception(Exception)]);
|
146
|
+
format_error({no_such_function, {M,F,A}})
|
147
|
+
when is_atom(M), is_atom(F), is_integer(A) ->
|
148
|
+
error_msg(io_lib:format("no such function: ~w:~w/~w", [M,F,A]),
|
149
|
+
"", []);
|
150
|
+
format_error({module_not_found, M}) ->
|
151
|
+
error_msg("test module not found", "~p", [M]);
|
152
|
+
format_error({application_not_found, A}) when is_atom(A) ->
|
153
|
+
error_msg("application not found", "~w", [A]);
|
154
|
+
format_error({file_read_error, {_R, Msg, F}}) ->
|
155
|
+
error_msg("error reading file", "~s: ~s", [Msg, F]);
|
156
|
+
format_error({context_error, setup_failed, Exception}) ->
|
157
|
+
error_msg("context setup failed", "~s",
|
158
|
+
[format_exception(Exception)]);
|
159
|
+
format_error({context_error, cleanup_failed, Exception}) ->
|
160
|
+
error_msg("context cleanup failed", "~s",
|
161
|
+
[format_exception(Exception)]);
|
162
|
+
format_error({context_error, instantiation_failed, Exception}) ->
|
163
|
+
error_msg("instantiation of subtests failed", "~s",
|
164
|
+
[format_exception(Exception)]).
|
165
|
+
|
166
|
+
error_msg(Title, Fmt, Args) ->
|
167
|
+
Msg = io_lib:format("::"++Fmt, Args), % gets indentation right
|
168
|
+
io_lib:fwrite("*** ~s ***\n~s\n\n", [Title, Msg]).
|
169
|
+
|
170
|
+
|
171
|
+
%% ---------------------------------------------------------------------
|
172
|
+
%% Deep list iterator; accepts improper lists/sublists, and also accepts
|
173
|
+
%% non-lists on the top level. Nonempty strings (not deep strings) are
|
174
|
+
%% recognized as separate elements, even on the top level. (It is not
|
175
|
+
%% recommended to include integers in the deep list, since a list of
|
176
|
+
%% integers is likely to be interpreted as a string.). The result is
|
177
|
+
%% always presented as a list (which may be improper), which is either
|
178
|
+
%% empty or otherwise has a non-list head element.
|
179
|
+
|
180
|
+
dlist_next([X | Xs] = Xs0) when is_list(X) ->
|
181
|
+
case is_nonempty_string(X) of
|
182
|
+
true -> Xs0;
|
183
|
+
false -> dlist_next(X, Xs)
|
184
|
+
end;
|
185
|
+
dlist_next([_|_] = Xs) ->
|
186
|
+
case is_nonempty_string(Xs) of
|
187
|
+
true -> [Xs];
|
188
|
+
false -> Xs
|
189
|
+
end;
|
190
|
+
dlist_next([]) ->
|
191
|
+
[];
|
192
|
+
dlist_next(X) ->
|
193
|
+
[X].
|
194
|
+
|
195
|
+
%% the first two clauses avoid pushing empty lists on the stack
|
196
|
+
dlist_next([X], Ys) when is_list(X) ->
|
197
|
+
case is_nonempty_string(X) of
|
198
|
+
true -> [X | Ys];
|
199
|
+
false -> dlist_next(X, Ys)
|
200
|
+
end;
|
201
|
+
dlist_next([X], Ys) ->
|
202
|
+
[X | Ys];
|
203
|
+
dlist_next([X | Xs], Ys) when is_list(X) ->
|
204
|
+
case is_nonempty_string(X) of
|
205
|
+
true -> [X | [Xs | Ys]];
|
206
|
+
false -> dlist_next(X, [Xs | Ys])
|
207
|
+
end;
|
208
|
+
dlist_next([X | Xs], Ys) ->
|
209
|
+
[X | [Xs | Ys]];
|
210
|
+
dlist_next([], Xs) ->
|
211
|
+
dlist_next(Xs).
|
212
|
+
|
213
|
+
|
214
|
+
-ifdef(TEST).
|
215
|
+
dlist_test_() ->
|
216
|
+
{"deep list traversal",
|
217
|
+
[{"non-list term -> singleton list",
|
218
|
+
?_test([any] = dlist_next(any))},
|
219
|
+
{"empty list -> empty list",
|
220
|
+
?_test([] = dlist_next([]))},
|
221
|
+
{"singleton list -> singleton list",
|
222
|
+
?_test([any] = dlist_next([any]))},
|
223
|
+
{"taking the head of a flat list",
|
224
|
+
?_test([a,b,c] = dlist_next([a,b,c]))},
|
225
|
+
{"skipping an initial empty list",
|
226
|
+
?_test([a,b,c] = dlist_next([[],a,b,c]))},
|
227
|
+
{"skipping nested initial empty lists",
|
228
|
+
?_test([a,b,c] = dlist_next([[[[]]],a,b,c]))},
|
229
|
+
{"skipping a final empty list",
|
230
|
+
?_test([] = dlist_next([[]]))},
|
231
|
+
{"skipping nested final empty lists",
|
232
|
+
?_test([] = dlist_next([[[[]]]]))},
|
233
|
+
{"the first element is in a sublist",
|
234
|
+
?_test([a,b,c] = dlist_next([[a],b,c]))},
|
235
|
+
{"recognizing a naked string",
|
236
|
+
?_test(["abc"] = dlist_next("abc"))},
|
237
|
+
{"recognizing a wrapped string",
|
238
|
+
?_test(["abc"] = dlist_next(["abc"]))},
|
239
|
+
{"recognizing a leading string",
|
240
|
+
?_test(["abc",a,b,c] = dlist_next(["abc",a,b,c]))},
|
241
|
+
{"recognizing a nested string",
|
242
|
+
?_test(["abc"] = dlist_next([["abc"]]))},
|
243
|
+
{"recognizing a leading string in a sublist",
|
244
|
+
?_test(["abc",a,b,c] = dlist_next([["abc"],a,b,c]))},
|
245
|
+
{"traversing an empty list",
|
246
|
+
?_test([] = dlist_flatten([]))},
|
247
|
+
{"traversing a flat list",
|
248
|
+
?_test([a,b,c] = dlist_flatten([a,b,c]))},
|
249
|
+
{"traversing a deep list",
|
250
|
+
?_test([a,b,c] = dlist_flatten([[],[a,[b,[]],c],[]]))},
|
251
|
+
{"traversing a deep but empty list",
|
252
|
+
?_test([] = dlist_flatten([[],[[[]]],[]]))}
|
253
|
+
]}.
|
254
|
+
|
255
|
+
%% test support
|
256
|
+
dlist_flatten(Xs) ->
|
257
|
+
case dlist_next(Xs) of
|
258
|
+
[X | Xs1] -> [X | dlist_flatten(Xs1)];
|
259
|
+
[] -> []
|
260
|
+
end.
|
261
|
+
-endif.
|
262
|
+
|
263
|
+
|
264
|
+
%% ---------------------------------------------------------------------
|
265
|
+
%% Check for proper Unicode-stringness.
|
266
|
+
|
267
|
+
is_string([C | Cs]) when is_integer(C), C >= 0, C =< 16#10ffff ->
|
268
|
+
is_string(Cs);
|
269
|
+
is_string([_ | _]) ->
|
270
|
+
false;
|
271
|
+
is_string([]) ->
|
272
|
+
true;
|
273
|
+
is_string(_) ->
|
274
|
+
false.
|
275
|
+
|
276
|
+
is_nonempty_string([]) -> false;
|
277
|
+
is_nonempty_string(Cs) -> is_string(Cs).
|
278
|
+
|
279
|
+
-ifdef(TEST).
|
280
|
+
is_string_test_() ->
|
281
|
+
{"is_string",
|
282
|
+
[{"no non-lists", ?_assert(not is_string($A))},
|
283
|
+
{"no non-integer lists", ?_assert(not is_string([true]))},
|
284
|
+
{"empty string", ?_assert(is_string(""))},
|
285
|
+
{"ascii string", ?_assert(is_string(lists:seq(0, 127)))},
|
286
|
+
{"latin-1 string", ?_assert(is_string(lists:seq(0, 255)))},
|
287
|
+
{"unicode string",
|
288
|
+
?_assert(is_string([0, $A, 16#10fffe, 16#10ffff]))},
|
289
|
+
{"not above unicode range",
|
290
|
+
?_assert(not is_string([0, $A, 16#110000]))},
|
291
|
+
{"no negative codepoints", ?_assert(not is_string([$A, -1, 0]))}
|
292
|
+
]}.
|
293
|
+
-endif.
|
294
|
+
|
295
|
+
|
296
|
+
%% ---------------------------------------------------------------------
|
297
|
+
%% Splitting a full node name into basename and hostname,
|
298
|
+
%% using 'localhost' as the default hostname
|
299
|
+
|
300
|
+
split_node(N) when is_atom(N) -> split_node(atom_to_list(N));
|
301
|
+
split_node(Cs) -> split_node_1(Cs, []).
|
302
|
+
|
303
|
+
split_node_1([$@ | Cs], As) -> split_node_2(As, Cs);
|
304
|
+
split_node_1([C | Cs], As) -> split_node_1(Cs, [C | As]);
|
305
|
+
split_node_1([], As) -> split_node_2(As, "localhost").
|
306
|
+
|
307
|
+
split_node_2(As, Cs) ->
|
308
|
+
{list_to_atom(lists:reverse(As)), list_to_atom(Cs)}.
|
309
|
+
|
310
|
+
%% ---------------------------------------------------------------------
|
311
|
+
%% Get the name of the containing function for a fun. (This is encoded
|
312
|
+
%% in the name of the generated function that implements the fun.)
|
313
|
+
|
314
|
+
fun_parent(F) ->
|
315
|
+
{name, N} = erlang:fun_info(F, name),
|
316
|
+
case erlang:fun_info(F, type) of
|
317
|
+
{type, external} ->
|
318
|
+
N;
|
319
|
+
{type, local} ->
|
320
|
+
S = atom_to_list(N),
|
321
|
+
list_to_atom(string:sub_string(S, 2, string:chr(S, $/) - 1))
|
322
|
+
end.
|
323
|
+
|
324
|
+
-ifdef(TEST).
|
325
|
+
fun_parent_test() ->
|
326
|
+
fun_parent_test = fun_parent(fun () -> ok end).
|
327
|
+
-endif.
|
328
|
+
|
329
|
+
|
330
|
+
%% ---------------------------------------------------------------------
|
331
|
+
%% Ye olde uniq function
|
332
|
+
|
333
|
+
uniq([X, X | Xs]) -> uniq([X | Xs]);
|
334
|
+
uniq([X | Xs]) -> [X | uniq(Xs)];
|
335
|
+
uniq([]) -> [].
|
336
|
+
|
337
|
+
-ifdef(TEST).
|
338
|
+
uniq_test_() ->
|
339
|
+
{"uniq",
|
340
|
+
[?_assertError(function_clause, uniq(ok)),
|
341
|
+
?_assertError(function_clause, uniq([1|2])),
|
342
|
+
?_test([] = uniq([])),
|
343
|
+
?_test([1,2,3] = uniq([1,2,3])),
|
344
|
+
?_test([1,2,3] = uniq([1,2,2,3])),
|
345
|
+
?_test([1,2,3,2,1] = uniq([1,2,2,3,2,2,1])),
|
346
|
+
?_test([1,2,3] = uniq([1,1,1,2,2,2,3,3,3])),
|
347
|
+
?_test(["1","2","3"] = uniq(["1","1","2","2","3","3"]))
|
348
|
+
]}.
|
349
|
+
-endif.
|
350
|
+
|
351
|
+
|
352
|
+
%% ---------------------------------------------------------------------
|
353
|
+
%% Apply arbitrary unary function F with dummy arguments "until it
|
354
|
+
%% works". (F must be side effect free! It will be called repeatedly.)
|
355
|
+
%% No exceptions will be thrown unless the function actually crashes for
|
356
|
+
%% some other reason than being unable to match the argument.
|
357
|
+
|
358
|
+
%% @spec (F::(any()) -> any()) -> {Value::any(), Result::any()}
|
359
|
+
|
360
|
+
browse_fun(F) ->
|
361
|
+
browse_fun(F, arg_values()).
|
362
|
+
|
363
|
+
browse_fun(F, Next) ->
|
364
|
+
case Next() of
|
365
|
+
[V | Next1] ->
|
366
|
+
case try_apply(F, V) of
|
367
|
+
{ok, Result} ->
|
368
|
+
{V, Result};
|
369
|
+
{error, function_clause} ->
|
370
|
+
browse_fun(F, Next1);
|
371
|
+
{error, badarity} ->
|
372
|
+
erlang:error({badarity, {F, 1}});
|
373
|
+
{error, {Class, Reason, Trace}} ->
|
374
|
+
erlang:raise(Class, Reason, Trace)
|
375
|
+
end;
|
376
|
+
[] ->
|
377
|
+
%% tried everything - this ought to provoke an error
|
378
|
+
F(undefined)
|
379
|
+
end.
|
380
|
+
|
381
|
+
%% Apply argument to function and report whether it succeeded (and with
|
382
|
+
%% what return value), or failed due to bad arity or a simple top-level
|
383
|
+
%% function_clause error, or if it crashed in some other way.
|
384
|
+
|
385
|
+
%% @spec (F::(any()) -> any(), V::any()) ->
|
386
|
+
%% {ok, Result::any()}
|
387
|
+
%% | {error, function_clause | badarity | eunit_test:exception()}
|
388
|
+
|
389
|
+
try_apply(F, Arg) ->
|
390
|
+
case erlang:fun_info(F, arity) of
|
391
|
+
{arity, 1} ->
|
392
|
+
{module, M} = erlang:fun_info(F, module),
|
393
|
+
{name, N} = erlang:fun_info(F, name),
|
394
|
+
try_apply(F, Arg, M, N);
|
395
|
+
_ ->
|
396
|
+
{error, badarity}
|
397
|
+
end.
|
398
|
+
|
399
|
+
try_apply(F, Arg, M, N) ->
|
400
|
+
try F(Arg) of
|
401
|
+
X -> {ok, X}
|
402
|
+
catch
|
403
|
+
error:function_clause ->
|
404
|
+
case erlang:get_stacktrace() of
|
405
|
+
[{M, N, _Args} | _] ->
|
406
|
+
{error, function_clause};
|
407
|
+
Trace ->
|
408
|
+
{error, {error, function_clause, Trace}}
|
409
|
+
end;
|
410
|
+
Class:Reason ->
|
411
|
+
{error, {Class, Reason, erlang:get_stacktrace()}}
|
412
|
+
end.
|
413
|
+
|
414
|
+
%% test value producers for function browsing
|
415
|
+
|
416
|
+
arg_values() ->
|
417
|
+
Vs = [undefined, ok, true, false, 0, 1],
|
418
|
+
fun () -> arg_values(Vs) end.
|
419
|
+
|
420
|
+
arg_values([V | Vs]) ->
|
421
|
+
[V | fun () -> arg_values(Vs) end];
|
422
|
+
arg_values(_) ->
|
423
|
+
(arg_tuples())().
|
424
|
+
|
425
|
+
arg_tuples() ->
|
426
|
+
fun () -> arg_tuples(0) end.
|
427
|
+
|
428
|
+
arg_tuples(N) when N >= 0, N =< 12 ->
|
429
|
+
[erlang:make_tuple(N, undefined) | fun () -> arg_tuples(N + 1) end];
|
430
|
+
arg_tuples(_) ->
|
431
|
+
(arg_lists())().
|
432
|
+
|
433
|
+
arg_lists() ->
|
434
|
+
fun () -> arg_lists(0) end.
|
435
|
+
|
436
|
+
arg_lists(N) when N >= 0, N =< 12 ->
|
437
|
+
[lists:duplicate(N, undefined) | fun () -> arg_lists(N + 1) end];
|
438
|
+
arg_lists(_) ->
|
439
|
+
[].
|
440
|
+
|
441
|
+
-ifdef(TEST).
|
442
|
+
browse_fun_test_() ->
|
443
|
+
{"browsing funs",
|
444
|
+
[?_assertError({badarity, {_, 1}}, browse_fun(fun () -> ok end)),
|
445
|
+
?_assertError({badarity, {_, 1}}, browse_fun(fun (_,_) -> ok end)),
|
446
|
+
?_assertError(function_clause, browse_fun(fun (42) -> ok end)),
|
447
|
+
?_test({_, 17} = browse_fun(fun (_) -> 17 end)),
|
448
|
+
?_test({_, 17} = browse_fun(fun (undefined) -> 17 end)),
|
449
|
+
?_test({_, 17} = browse_fun(fun (ok) -> 17 end)),
|
450
|
+
?_test({_, 17} = browse_fun(fun (true) -> 17 end)),
|
451
|
+
?_test({_, 17} = browse_fun(fun ({}) -> 17 end)),
|
452
|
+
?_test({_, 17} = browse_fun(fun ({_}) -> 17 end)),
|
453
|
+
?_test({_, 17} = browse_fun(fun ({_,_}) -> 17 end)),
|
454
|
+
?_test({_, 17} = browse_fun(fun ({_,_,_}) -> 17 end)),
|
455
|
+
?_test({_, 17} = browse_fun(fun ([]) -> 17 end)),
|
456
|
+
?_test({_, 17} = browse_fun(fun ([_]) -> 17 end)),
|
457
|
+
?_test({_, 17} = browse_fun(fun ([_,_]) -> 17 end)),
|
458
|
+
?_test({_, 17} = browse_fun(fun ([_,_,_]) -> 17 end))
|
459
|
+
]}.
|
460
|
+
-endif.
|
461
|
+
|
462
|
+
|
463
|
+
%% ---------------------------------------------------------------------
|
464
|
+
%% Replacement for os:cmd
|
465
|
+
|
466
|
+
command(Cmd) ->
|
467
|
+
command(Cmd, "").
|
468
|
+
|
469
|
+
command(Cmd, Dir) ->
|
470
|
+
command(Cmd, Dir, []).
|
471
|
+
|
472
|
+
command(Cmd, Dir, Env) ->
|
473
|
+
CD = if Dir == "" -> [];
|
474
|
+
true -> [{cd, Dir}]
|
475
|
+
end,
|
476
|
+
SetEnv = if Env == [] -> [];
|
477
|
+
true -> [{env, Env}]
|
478
|
+
end,
|
479
|
+
Opt = CD ++ SetEnv ++ [stream, exit_status, use_stdio,
|
480
|
+
stderr_to_stdout, in, eof],
|
481
|
+
P = open_port({spawn, Cmd}, Opt),
|
482
|
+
get_data(P, []).
|
483
|
+
|
484
|
+
get_data(P, D) ->
|
485
|
+
receive
|
486
|
+
{P, {data, D1}} ->
|
487
|
+
get_data(P, [D1|D]);
|
488
|
+
{P, eof} ->
|
489
|
+
port_close(P),
|
490
|
+
receive
|
491
|
+
{P, {exit_status, N}} ->
|
492
|
+
{N, normalize(lists:flatten(lists:reverse(D)))}
|
493
|
+
end
|
494
|
+
end.
|
495
|
+
|
496
|
+
normalize([$\r, $\n | Cs]) ->
|
497
|
+
[$\n | normalize(Cs)];
|
498
|
+
normalize([$\r | Cs]) ->
|
499
|
+
[$\n | normalize(Cs)];
|
500
|
+
normalize([C | Cs]) ->
|
501
|
+
[C | normalize(Cs)];
|
502
|
+
normalize([]) ->
|
503
|
+
[].
|
504
|
+
|
505
|
+
-ifdef(TEST).
|
506
|
+
|
507
|
+
cmd_test_() ->
|
508
|
+
([?_test({0, "hello\n"} = ?_cmd_("echo hello"))]
|
509
|
+
++ case os:type() of
|
510
|
+
{unix, _} ->
|
511
|
+
unix_cmd_tests();
|
512
|
+
{win32, _} ->
|
513
|
+
win32_cmd_tests();
|
514
|
+
_ ->
|
515
|
+
[]
|
516
|
+
end).
|
517
|
+
|
518
|
+
unix_cmd_tests() ->
|
519
|
+
[{"command execution, status, and output",
|
520
|
+
[?_cmd("echo hello"),
|
521
|
+
?_assertCmdStatus(0, "true"),
|
522
|
+
?_assertCmdStatus(1, "false"),
|
523
|
+
?_assertCmd("true"),
|
524
|
+
?_assertCmdOutput("hello\n", "echo hello"),
|
525
|
+
?_assertCmdOutput("hello", "echo -n hello")
|
526
|
+
]},
|
527
|
+
{"file setup and cleanup",
|
528
|
+
setup,
|
529
|
+
fun () -> ?cmd("mktemp tmp.XXXXXXXX") end,
|
530
|
+
fun (File) -> ?cmd("rm " ++ File) end,
|
531
|
+
fun (File) ->
|
532
|
+
[?_assertCmd("echo xyzzy >" ++ File),
|
533
|
+
?_assertCmdOutput("xyzzy\n", "cat " ++ File)]
|
534
|
+
end}
|
535
|
+
].
|
536
|
+
|
537
|
+
win32_cmd_tests() ->
|
538
|
+
[{"command execution, status, and output",
|
539
|
+
[?_cmd("echo hello"),
|
540
|
+
?_assertCmdOutput("hello\n", "echo hello")
|
541
|
+
]}
|
542
|
+
].
|
543
|
+
|
544
|
+
-endif. % TEST
|
545
|
+
|
546
|
+
|
547
|
+
%% ---------------------------------------------------------------------
|
548
|
+
%% Wrapper around file:path_consult
|
549
|
+
|
550
|
+
%% @throws {file_read_error, {Reason::atom(), Message::string(),
|
551
|
+
%% fileName()}}
|
552
|
+
|
553
|
+
consult_file(File) ->
|
554
|
+
case file:path_consult(["."]++code:get_path(), File) of
|
555
|
+
{ok, Data, _Path} ->
|
556
|
+
Data;
|
557
|
+
{error, Reason} ->
|
558
|
+
Msg = file:format_error(Reason),
|
559
|
+
throw({file_read_error, {Reason, Msg, File}})
|
560
|
+
end.
|
561
|
+
|
562
|
+
%% ---------------------------------------------------------------------
|
563
|
+
%% Wrapper around file:list_dir
|
564
|
+
|
565
|
+
%% @throws {file_read_error, {Reason::atom(), Message::string(),
|
566
|
+
%% fileName()}}
|
567
|
+
|
568
|
+
list_dir(Dir) ->
|
569
|
+
case file:list_dir(Dir) of
|
570
|
+
{ok, Fs} ->
|
571
|
+
Fs;
|
572
|
+
{error, Reason} ->
|
573
|
+
Msg = file:format_error(Reason),
|
574
|
+
throw({file_read_error, {Reason, Msg, Dir}})
|
575
|
+
end.
|
576
|
+
|
577
|
+
%% ---------------------------------------------------------------------
|
578
|
+
%% A trie for remembering and checking least specific cancelled events
|
579
|
+
%% (an empty list `[]' simply represents a stored empty list, i.e., all
|
580
|
+
%% events will match, while an empty tree means that no events match).
|
581
|
+
|
582
|
+
trie_new() ->
|
583
|
+
gb_trees:empty().
|
584
|
+
|
585
|
+
trie_store([_ | _], []) ->
|
586
|
+
[];
|
587
|
+
trie_store([E | Es], T) ->
|
588
|
+
case gb_trees:lookup(E, T) of
|
589
|
+
none ->
|
590
|
+
if Es == [] ->
|
591
|
+
gb_trees:insert(E, [], T);
|
592
|
+
true ->
|
593
|
+
gb_trees:insert(E, trie_store(Es, gb_trees:empty()),
|
594
|
+
T)
|
595
|
+
end;
|
596
|
+
{value, []} ->
|
597
|
+
T; %% prefix already stored
|
598
|
+
{value, T1} ->
|
599
|
+
gb_trees:update(E, trie_store(Es, T1), T)
|
600
|
+
end;
|
601
|
+
trie_store([], _T) ->
|
602
|
+
[].
|
603
|
+
|
604
|
+
trie_match([_ | _], []) ->
|
605
|
+
prefix;
|
606
|
+
trie_match([E | Es], T) ->
|
607
|
+
case gb_trees:lookup(E, T) of
|
608
|
+
none ->
|
609
|
+
no;
|
610
|
+
{value, []} ->
|
611
|
+
if Es == [] -> exact;
|
612
|
+
true -> prefix
|
613
|
+
end;
|
614
|
+
{value, T1} ->
|
615
|
+
trie_match(Es, T1)
|
616
|
+
end;
|
617
|
+
trie_match([], []) ->
|
618
|
+
exact;
|
619
|
+
trie_match([], _T) ->
|
620
|
+
no.
|
621
|
+
|
622
|
+
-ifdef(TEST).
|
623
|
+
|
624
|
+
trie_test_() ->
|
625
|
+
[{"basic representation",
|
626
|
+
[?_assert(trie_new() == gb_trees:empty()),
|
627
|
+
?_assert(trie_store([1], trie_new())
|
628
|
+
== gb_trees:insert(1, [], gb_trees:empty())),
|
629
|
+
?_assert(trie_store([1,2], trie_new())
|
630
|
+
== gb_trees:insert(1,
|
631
|
+
gb_trees:insert(2, [],
|
632
|
+
gb_trees:empty()),
|
633
|
+
gb_trees:empty())),
|
634
|
+
?_assert([] == trie_store([1], [])),
|
635
|
+
?_assert([] == trie_store([], gb_trees:empty()))
|
636
|
+
]},
|
637
|
+
{"basic storing and matching",
|
638
|
+
[?_test(no = trie_match([], trie_new())),
|
639
|
+
?_test(exact = trie_match([], trie_store([], trie_new()))),
|
640
|
+
?_test(no = trie_match([], trie_store([1], trie_new()))),
|
641
|
+
?_test(exact = trie_match([1], trie_store([1], trie_new()))),
|
642
|
+
?_test(prefix = trie_match([1,2], trie_store([1], trie_new()))),
|
643
|
+
?_test(no = trie_match([1], trie_store([1,2], trie_new()))),
|
644
|
+
?_test(no = trie_match([1,3], trie_store([1,2], trie_new()))),
|
645
|
+
?_test(exact = trie_match([1,2,3,4,5],
|
646
|
+
trie_store([1,2,3,4,5], trie_new()))),
|
647
|
+
?_test(prefix = trie_match([1,2,3,4,5],
|
648
|
+
trie_store([1,2,3], trie_new()))),
|
649
|
+
?_test(no = trie_match([1,2,2,4,5],
|
650
|
+
trie_store([1,2,3], trie_new())))
|
651
|
+
]},
|
652
|
+
{"matching with partially overlapping patterns",
|
653
|
+
setup,
|
654
|
+
fun () ->
|
655
|
+
trie_store([1,3,2], trie_store([1,2,3], trie_new()))
|
656
|
+
end,
|
657
|
+
fun (T) ->
|
658
|
+
[?_test(no = trie_match([], T)),
|
659
|
+
?_test(no = trie_match([1], T)),
|
660
|
+
?_test(no = trie_match([1,2], T)),
|
661
|
+
?_test(no = trie_match([1,3], T)),
|
662
|
+
?_test(exact = trie_match([1,2,3], T)),
|
663
|
+
?_test(exact = trie_match([1,3,2], T)),
|
664
|
+
?_test(no = trie_match([1,2,2], T)),
|
665
|
+
?_test(no = trie_match([1,3,3], T)),
|
666
|
+
?_test(prefix = trie_match([1,2,3,4], T)),
|
667
|
+
?_test(prefix = trie_match([1,3,2,1], T))]
|
668
|
+
end},
|
669
|
+
{"matching with more general pattern overriding less general",
|
670
|
+
setup,
|
671
|
+
fun () -> trie_store([1], trie_store([1,2,3], trie_new())) end,
|
672
|
+
fun (_) -> ok end,
|
673
|
+
fun (T) ->
|
674
|
+
[?_test(no = trie_match([], T)),
|
675
|
+
?_test(exact = trie_match([1], T)),
|
676
|
+
?_test(prefix = trie_match([1,2], T)),
|
677
|
+
?_test(prefix = trie_match([1,2,3], T)),
|
678
|
+
?_test(prefix = trie_match([1,2,3,4], T))]
|
679
|
+
end}
|
680
|
+
].
|
681
|
+
|
682
|
+
-endif. % TEST
|