1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2014-2018. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20%%
21
22-module(testUniqueObjectSets).
23-export([main/3]).
24
25%% Run-time function called by the generated code.
26seq_roundtrip(I, D0) ->
27    M = 'UniqueObjectSets',
28    try
29	{ok,Enc} = M:encode('Seq', {'Seq',I,D0}),
30        asn1_test_lib:map_roundtrip(M, 'Seq', Enc),
31	{ok,{'Seq',I,D}} = M:decode('Seq', Enc),
32	D
33    catch C:E:Stk ->
34	    io:format("FAILED: ~p ~p\n", [I,D0]),
35	    erlang:raise(C, E, Stk)
36    end.
37
38types() ->
39    [{"CHOICE { a INTEGER, b BIT STRING }", {b,<<42:3>>}},
40     {"INTEGER",42},
41     {"SEQUENCE {a OCTET STRING}",{'_',<<"abc">>}},
42     {"SEQUENCE {b BOOLEAN, ...}",{'_',true}},
43     {"SEQUENCE {b BOOLEAN, ..., s IA5String, ..., e ENUMERATED { x, y, z}}",
44      {'_',false,"string",y}},
45     {"SET {a BIT STRING}",{'_',<<1:17>>}},
46     {"SEQUENCE OF INTEGER",[-19,0,555,777]},
47     {"SET OF BOOLEAN",[true,false,true]},
48     {"SEQUENCE OF SEQUENCE {x INTEGER (0..7)}",[{'_',7},{'_',0}]},
49     {"SET OF SEQUENCE {x INTEGER (0..7)}",[{'_',7},{'_',0}]}
50    ].
51
52main(_,jer,_) -> ok;
53main(CaseDir, Rule, Opts) ->
54    D0 = types(),
55    {D1,_} = lists:mapfoldl(fun({T,S}, I) ->
56				    {{I,T,S},I+1}
57			    end, 1, D0),
58    Types = [gen_types(I, Type) || {I,Type,_} <- D1],
59    Set = [gen_set_items(I, T) || {I,T,_} <- D1],
60    Objs = [gen_obj(I) || {I,_,_} <- D1],
61    DupObjs = [gen_dup_obj(I, T) || {I,T,_} <- D1],
62    DupObjRefs0 = [gen_dup_obj_refs(I) || {I,_,_} <- D1],
63    DupObjRefs = lists:join(" |\n", DupObjRefs0),
64    Asn1Spec = 'UniqueObjectSets',
65    A = ["UniqueObjectSets DEFINITIONS AUTOMATIC TAGS ::=\n",
66	 "BEGIN\n\n",
67	 "TEST-UNIQUE ::= CLASS {\n"
68	 " &id   INTEGER UNIQUE,\n"
69	 " &Type OPTIONAL\n"
70	 "}\n"
71	 "WITH SYNTAX {IDENTIFIED BY &id [TYPE &Type]}\n",
72	 $\n,
73	 "DUP-CONTAINER ::= CLASS {\n"
74	 " &id   INTEGER UNIQUE,\n"
75	 " &data TEST-UNIQUE\n"
76	 "} WITH SYNTAX {\n"
77	 " ID &id, &data\n"
78	 "}\n",
79	 $\n,
80	 Types,$\n,
81	 "UniqSet TEST-UNIQUE ::= {\n",
82	 Set,
83	 " DupSet-1 |\n",
84	 " DupSet-2, ...\n",
85	 "}\n\n",
86	 Objs,$\n,
87	 DupObjs,$\n,
88	 "DupSet-1 TEST-UNIQUE ::= {\n",
89	 DupObjRefs,$\n,
90	 "}\n\n",
91	 "DupSet-2 TEST-UNIQUE ::= {\n",
92	 DupObjRefs,",...\n",
93	 "}\n\n",
94	 "Seq ::= SEQUENCE {\n"
95	 "  id TEST-UNIQUE.&id ({UniqSet}),\n"
96	 "  type TEST-UNIQUE.&Type ({UniqSet}{@id})\n"
97	 "}\n"
98	 "END\n"],
99    Asn1File = filename:join(CaseDir, atom_to_list(Asn1Spec)++".asn1"),
100    ok = file:write_file(Asn1File, A),
101
102    TestModule = 'unique_object_sets',
103    Test0 = [gen_test(I, Data) || {I,_,Data} <- D1],
104    Test = ["-module(",atom_to_list(TestModule),").\n"
105	    "-export([main/1]).\n"
106	    "\n"
107	    "main(SeqRoundtrip) ->\n",
108	    "  ",atom_to_list(Rule)," = '",atom_to_list(Asn1Spec),
109	    "':encoding_rule(),\n",
110	    Test0,
111	    "  ok.\n"
112	    ],
113    ErlFile = filename:join(CaseDir, atom_to_list(TestModule)++".erl"),
114    ok = file:write_file(ErlFile, Test),
115
116    io:format("~s\n~s\n", [Asn1File,ErlFile]),
117    case Rule of
118	per ->
119	    io:put_chars([A,$\n,Test,$\n]);
120	_ ->
121	    ok
122    end,
123
124    ok = asn1ct:compile(Asn1File, [Rule,{outdir,CaseDir}|Opts]),
125    {ok,TestModule} = c:c(ErlFile, [{outdir,CaseDir}]),
126    TestModule:main(fun seq_roundtrip/2),
127    ok.
128
129gen_types(I, Type) ->
130    io_lib:format("AType~p ::= ~s\n", [I,Type]).
131
132gen_set_items(I, T) ->
133    io_lib:format(" {IDENTIFIED BY ~p TYPE AType~p} |\n"
134		  " {IDENTIFIED BY ~p TYPE AType~p} |\n"
135		  " {IDENTIFIED BY ~p TYPE ~s} |\n"
136		  " obj-~p |\n\n",
137		  [I,I,I,I,I,T,I]).
138
139gen_obj(I) ->
140    io_lib:format("obj-~p TEST-UNIQUE ::= {IDENTIFIED BY ~p TYPE AType~p}\n",
141		  [I,I,I]).
142
143gen_dup_obj(I, T) ->
144    io_lib:format("dup-obj-~p DUP-CONTAINER ::= "
145		  "{ID ~p, {IDENTIFIED BY ~p TYPE ~s}}\n",
146		  [I,I,I+1000,T]).
147
148gen_dup_obj_refs(I) ->
149    io_lib:format("dup-obj-~p.&data", [I]).
150
151gen_test(I, Data) ->
152    io_lib:format("  ~s = SeqRoundtrip(~p, ~p),\n",
153		  [match_term(Data),I,Data]).
154
155match_term('_') ->
156    "_";
157match_term([H|T]=L) ->
158    case is_intlist(L) of
159	true ->
160	    io_lib:format("~p", [L]);
161	false ->
162	    ["[",match_term(H),"|",match_term(T),"]"]
163    end;
164match_term(Tuple) when is_tuple(Tuple) ->
165    ["{",match_term_tuple(Tuple, 1),"}"];
166match_term(Other) ->
167    io_lib:format("~p", [Other]).
168
169match_term_tuple(T, I) when I =< tuple_size(T) ->
170    [match_term(element(I, T)),
171     if I < tuple_size(T) -> ",";
172	true -> "" end|match_term_tuple(T, I+1)];
173match_term_tuple(_, _) ->
174    [].
175
176is_intlist(L) ->
177    lists:all(fun is_integer/1, L).
178