1#!/usr/bin/env escript
2%% -*- Mode: Erlang; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3%%! -smp enable
4
5% Licensed under the Apache License, Version 2.0 (the "License"); you may not
6% use this file except in compliance with the License. You may obtain a copy of
7% the License at
8%
9%   http://www.apache.org/licenses/LICENSE-2.0
10%
11% Unless required by applicable law or agreed to in writing, software
12% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14% License for the specific language governing permissions and limitations under
15% the License.
16
17thread_counts() ->
18    [
19     erlang:system_info(schedulers),
20     erlang:system_info(schedulers) * 2,
21     erlang:system_info(schedulers) * 5,
22     erlang:system_info(schedulers) * 11
23    ].
24
25main(_) ->
26    test_util:init_code_path(),
27
28    etap:plan(length(expectations()) + lists:sum(thread_counts())),
29    case (catch test()) of
30        ok ->
31            etap:end_tests();
32        Other ->
33            etap:diag(io_lib:format("Test died abnormally: ~p", [Other])),
34            etap:bail(Other)
35    end,
36    ok.
37
38
39test() ->
40    couch_set_view_test_util:start_server(<<"set_view_raw_collator">>),
41
42    etap:diag("Running single thread tests"),
43    single_thread(),
44
45    lists:foreach(fun(C) ->
46        etap:diag("Running tests with " ++ integer_to_list(C) ++ " threads"),
47        multiple_threads(C)
48    end, thread_counts()),
49
50    couch_set_view_test_util:stop_server(),
51    ok.
52
53
54single_thread() ->
55    lists:foreach(fun({Key1, Key2, Expected}) ->
56        etap:is(couch_ejson_compare:less_json(Key1, Key2),
57                Expected,
58                assertion_string(Key1, Key2, Expected))
59    end, expectations()).
60
61
62multiple_threads(NumThreads) ->
63    Expectations = lists:flatten(
64        lists:duplicate(8, expectations() ++ lists:reverse(expectations()))),
65    ThreadFun = fun() ->
66         lists:foreach(fun({Key1, Key2, Expected}) ->
67             AssertionString = assertion_string(Key1, Key2, Expected),
68             case (catch couch_ejson_compare:less_json(Key1, Key2)) == Expected of
69             true ->
70                 ok;
71             false ->
72                 exit({failed, AssertionString})
73             end
74         end, Expectations),
75         exit(ok)
76     end,
77    Pids = lists:map(fun(_N) -> spawn_monitor(ThreadFun) end,
78                     lists:seq(1, NumThreads)),
79    lists:foreach(fun({Pid, Ref}) ->
80        receive
81        {'DOWN', Ref, process, Pid, Reason} ->
82            etap:is(Reason, ok, "Thread finished successfully")
83        after 60000 ->
84            etap:bail("Timeout waiting for thread to finish")
85        end
86    end, Pids),
87    ok.
88
89
90assertion_string(Key1, Key2, Expected) ->
91    lists:flatten(io_lib:format("less_json(~p, ~p) == ~p", [Key1, Key2, Expected])).
92
93
94expectations() ->
95    [
96     {<<"null">>, <<"null">>, 0},
97     {<<"null">>, <<"true">>, -1},
98     {<<"null">>, <<"false">>, -1},
99     {<<"false">>, <<"false">>, 0},
100     {<<"false">>, <<"true">>, -1},
101     {<<"true">>, <<"false">>, 1},
102     {<<"true">>, <<"true">>, 0},
103     {<<"null">>, <<"111">>, -1},
104     {<<"111">>, <<"null">>, 1},
105     {<<"111">>, <<"true">>, 1},
106     {<<"false">>, <<"111">>, -1},
107     {<<"123">>, <<"1">>, 1},
108     {<<"1">>, <<"123">>, -1},
109     {<<"123">>, <<"123">>, 0},
110     {<<"123">>, <<"-123">>, 1},
111     {<<"-123">>, <<"-123">>, 0},
112     {<<"-123">>, <<"123">>, -1},
113     {<<"123">>, <<"123.0001">>, -1},
114     {<<"123.0001">>, <<"123">>, 1},
115     {<<"-123.1">>, <<"123">>, -1},
116     {<<"-123.1">>, <<"123.2">>, -1},
117     {<<"123">>, <<"123e1">>, -1},
118     {<<"123">>, <<"123e0">>, 0},
119     {<<"0">>, <<"3.1415">>, -1},
120     {<<"123456">>, <<"[]">>, -1},
121     {<<"[]">>, <<"123456">>, 1},
122     {<<"[1,2,3,4]">>, <<"123456">>, 1},
123     {<<"[null,true,false]">>, <<"123456">>, 1},
124     {<<"123456">>, <<"[1,2,3,4]">>, -1},
125     {<<"123456">>, <<"[null,true,false]">>, -1},
126     {<<"[]">>, <<"[]">>, 0},
127     {<<"[1,2,3]">>, <<"[1,2,3]">>, 0},
128     {<<"[1,2]">>, <<"[1,2,3]">>, -1},
129     {<<"[1,2]">>, <<"[1,2,0]">>, -1},
130     {<<"[1,2,3]">>, <<"[1,2]">>, 1},
131     {<<"[1,2,0]">>, <<"[1,2]">>, 1},
132     {<<"[1,2,0]">>, <<"[1,2.1]">>, -1},
133     {<<"[1,2.1]">>, <<"[1,2,0]">>, 1},
134     {<<"[1,2.1,true]">>, <<"[1,2.1,null]">>, 1},
135     {<<"[1,2.1,true]">>, <<"[1,2.1,null,0]">>, 1},
136     {<<"[1,2.1,true,55]">>, <<"[1,2.1,null,0]">>, 1},
137     {<<"[1,2.1,null,0]">>, <<"[1,2.1,true,55]">>, -1},
138     {<<"[1,2.1,true,55]">>, <<"[1,2.1,true,55]">>, 0},
139     {<<"\"\"">>, <<"null">>, 1},
140     {<<"null">>, <<"\"\"">>, -1},
141     {<<"\"\"">>, <<"false">>, 1},
142     {<<"false">>, <<"\"\"">>, -1},
143     {<<"125">>, <<"\"\"">>, -1},
144     {<<"125.4e3">>, <<"\"\"">>, -1},
145     {<<"\"\"">>, <<"\"\"">>, 0},
146     {<<"\"abc\"">>, <<"\"abc\"">>, 0},
147     {<<"[\"abc\"]">>, <<"[\"abc\"]">>, 0},
148     {<<"[\"abc\",\"\"]">>, <<"[\"abc\",\"\"]">>, 0},
149     {<<"[\"abc\",\"1a\"]">>, <<"[\"abc\",\"\"]">>, 1},
150     {<<"[\"abc\",\"\"]">>, <<"[\"abc\",\"1a\"]">>, -1},
151     {<<"\"abcdefghijklmniopqrstuvwxyz1234567890\"">>,
152      <<"\"abcdefghijklmniopqrstuvwxyz1234567890\"">>, 0},
153     {<<"\"abcdefghijklmniopqrstuvwxyz1234567891\"">>,
154      <<"\"abcdefghijklmniopqrstuvwxyz1234567890\"">>, 1},
155     {<<"\"abcdefghijklmniopqrstuvwxyz1234567890X\"">>,
156      <<"\"abcdefghijklmniopqrstuvwxyz1234567890\"">>, 1},
157     {<<"\"abcdefghijklmniopqrstuvwxyz1234567890\"">>,
158      <<"\"abcdefghijklmniopqrstuvwxyz1234567891\"">>, -1},
159     {<<"\"abcdefghijklmniopqrstuvwxyz1234567890\"">>,
160      <<"\"abcdefghijklmniopqrstuvwxyz1234567890X\"">>, -1},
161     {<<"\"Os cágados voadores que atacaram as vacas do senhor engenheiro Bairrão!\""/utf8>>,
162      <<"\"Os cágados voadores que atacaram as vacas do senhor engenheiro Bairrão!\""/utf8>>,
163      0},
164     % NOTE vmx: 2014-05-02: The handling of UTF-8 binaries within escripts is
165     % broken in Erlang < 17.0, hence these comparisons are disabled for now.
166     % See MB-11023 (http://www.couchbase.com/issues/browse/MB-11023) for more
167     % information.
168     %{<<"\"Os cagádos voadores que atacaram as vacas do senhor engenheiro Bairrão!\""/utf8>>,
169     % <<"\"Os cágados voadores que atacaram as vacas do senhor engenheiro Bairrão!\""/utf8>>,
170     % -1},
171     %{<<"\"Os cágados voadores que atacaram as vacas do senhor engenheiro Bairrão!\""/utf8>>,
172     % <<"\"Os cagádos voadores que atacaram as vacas do senhor engenheiro Bairrão!\""/utf8>>,
173     % 1},
174     % MB-12967
175     %{<<"\"法\""/utf8>>, <<"\"法、\""/utf8>>, -1},
176     {<<"\"\\\\u00e1\"">>, <<"\"\"">>, 1},
177     {<<"\"\\\\U00e1\"">>, <<"\"\"">>, 1},
178     {<<"\"h\\\\u00e1\"">>, <<"\"\\\\u00e1\"">>, 1},
179     {<<"\"\\\\u00e1\"">>, <<"\"h\\\\u00e1\"">>, -1},
180     {<<"\"h\\\\u00e1 \\\\u00e2\"">>, <<"\"h\\\\u00e1 \\\\u00e2\"">>, 0},
181     {<<"\"h\\\\u00e1 \\\\u00e1\"">>, <<"\"h\\\\u00e1 \\\\u00e2\"">>, -1},
182     {<<"\"h\\\\u00e1 \\\\u00e2\"">>, <<"\"h\\\\u00e1 \\\\u00e1\"">>, 1},
183     {<<"{}">>, <<"[]">>, 1},
184     {<<"{}">>, <<"{}">>, 0},
185     {<<"[]">>, <<"{}">>, -1},
186     {<<"{}">>, <<"321">>, 1},
187     {<<"{}">>, <<"321.123">>, 1},
188     {<<"{}">>, <<"true">>, 1},
189     {<<"{}">>, <<"\"foo bar\"">>, 1},
190     {<<"\"foo bar\"">>, <<"{}">>, -1},
191     {<<"321">>, <<"{}">>, -1},
192     {<<"321.123">>, <<"{}">>, -1},
193     {<<"{}">>, <<"{\"prop1\":null}">>, -1},
194     {<<"{}">>, <<"{\"prop1\":7777}">>, -1},
195     {<<"{\"prop1\":123}">>, <<"{\"prop1\":7777}">>, -1},
196     {<<"{\"prop1\":123}">>, <<"{\"prop1\":123}">>, 0},
197     {<<"{\"prop1\":7777}">>, <<"{\"prop1\":123}">>, 1},
198     {<<"{\"prop1\":123}">>, <<"{\"prop1\":123,\"prop2\":\"abc\"}">>, -1},
199     {<<"{\"prop1\":123,\"prop2\":\"aba\"}">>, <<"{\"prop1\":123,\"prop2\":\"abc\"}">>, -1},
200     {<<"{\"prop1\":123,\"prop2\":\"abc\"}">>, <<"{\"prop1\":123,\"prop2\":\"abc\"}">>, 0},
201     {<<"{\"prop1\":123,\"prop2\":\"abc\"}">>, <<"{\"prop1\":123,\"prop2\":\"aba\"}">>, 1}
202    ].
203