aboutsummaryrefslogblamecommitdiffstats
path: root/lib/asn1/test/syntax_SUITE.erl
blob: f8d10157c0a70df5ea644e4bba3c82bfdd3cd600 (plain) (tree)

































































































































































































































































































































                                                                         
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
%%
%% %CopyrightEnd%
%%

-module(syntax_SUITE).
-export([suite/0,all/0,groups/0,
	 assignment/1,
	 class/1,
	 constraints/1,
	 exports/1,
	 header/1,
	 imports/1,
	 objects/1,
	 sequence/1,
	 syntax/1,
	 types/1,
	 values/1]).

-include_lib("test_server/include/test_server.hrl").

suite() -> [{ct_hooks, [ts_install_cth]}].

all() ->
    [{group,p}].

groups() ->
    [{p,parallel(),
      [assignment,
       class,
       constraints,
       exports,
       header,
       imports,
       objects,
       sequence,
       syntax,
       types,
       values]}].

parallel() ->
    case erlang:system_info(schedulers) > 1 of
        true  -> [parallel];
        false -> []
    end.

assignment(Config) ->
    Head = "Assignment DEFINITIONS AUTOMATIC TAGS ::=\nBEGIN\n",
    End = "\nEND\n",
    L0 = [{"42",3,{syntax_error,42}},
	  {"i",4,{syntax_error,'END'}},
	  {"i ::=",3,{syntax_error,'::='}},
	  {"i type",4,{syntax_error,'END'}},
	  {"i type ::=",3,{syntax_error,'::='}},
	  {"i TYPE",4,{syntax_error,'END'}},
	  {"i TYPE ::= ",4,{syntax_error,'END'}},
	  {"i INTEGER ::= 42 garbage",4,{syntax_error,'END'}},
	  {"i{T} Type",4,{syntax_error,'END'}},
	  {"TYPE",4,{syntax_error,'END'}},
	  {"TYPE ::=",4,{syntax_error,'END'}},
	  {"TYPE{ ::=",3,{syntax_error,'::='}},
	  {"TYPE{P, ::=",3,{syntax_error,'::='}},
	  {"TYPE{P,} ::=",3,{syntax_error,'}'}},
	  {"TYPE{Gov:} ::=",3,{syntax_error,':'}},
	  {"TYPE{A} CL ",4,{syntax_error,'END'}},
	  {"ObjSet CL",4,{syntax_error,'END'}}
	 ],
    L = [{Head++S++End,Line,E} || {S,Line,E} <- L0],
    run(L, "Assignment", Config),
    ok.

class(Config) ->
    Head = "Class DEFINITIONS AUTOMATIC TAGS ::=\n"
	"BEGIN\n"
	" CL ::= CLASS {",
    End = "\nEND\n",
    L0 = [{"id",3,{syntax_error,'id'}},
	  {"&id INTEGER",4,{syntax_error,'END'}},
	  {"&id INTEGER,",4,{syntax_error,'END'}},
	  {"&id,",3,{syntax_error,','}},
	  {"&id OPTIONAL",3,{syntax_error,'OPTIONAL'}},
	  {"&id INTEGER OPTIONAL",4,{syntax_error,'END'}},
	  {"&var &Field",4,{syntax_error,'END'}},
	  {"&Type,",4,{syntax_error,'END'}},
	  {"&Type OPTIONAL",4,{syntax_error,'END'}},
	  {"&ValueSet INTEGER OPTIONAL",4,{syntax_error,'END'}},
	  {"&ValueSet INTEGER DEFAULT",4,{syntax_error,'END'}},
	  {"&ValueSet INTEGER DEFAULT {",4,{syntax_error,'END'}},
	  {"&ValueSet INTEGER DEFAULT {a",4,{syntax_error,'END'}},
	  {"&Var &Field",4,{syntax_error,'END'}}
	 ],
    L = [{Head++S++End,Line,E} || {S,Line,E} <- L0],
    run(L, "Class", Config),
    ok.

constraints(Config) ->
    Head = "Constraints DEFINITIONS AUTOMATIC TAGS ::=\n"
	"BEGIN\n"
	" Type ::= ",
    End = "\nEND\n",
    L0 = [{"INTEGER (",4,{syntax_error,'END'}},
	  {"INTEGER (10x",3,{syntax_error,x}},
	  {"INTEGER (10|(10y",3,{syntax_error,y}},
	  {"INTEGER (CONSTRAINED BY {}",4,{syntax_error,'END'}},
	  {"INTEGER (CONSTRAINED BY {INTEGER garbage",3,
	   {syntax_error,garbage}},
	  {"INTEGER ({ObjSet",4,{syntax_error,'END'}},
	  {"INTEGER ({ObjSet}{",3,{syntax_error,'{'}},
	  {"INTEGER ({ObjSet}{@",3,{syntax_error,'{'}},
	  {"INTEGER ({ObjSet}{@x",3,{syntax_error,'{'}},
	  {"INTEGER ({ObjSet}{@x}",4,{syntax_error,'END'}},
	  {"INTEGER (10 !BOOLEAN",4,{syntax_error,'END'}},
	  {"INTEGER (10 !BOOLEAN:",4,{syntax_error,'END'}},
	  {"INTEGER (10 !BOOLEAN:FALSE",4,{syntax_error,'END'}},
	  {"SEQUENCE {} (WITH COMPONENTS { Type })",
	   3,{syntax_error,'Type'}},
	  {"SEQUENCE {} (WITH COMPONENTS { x (10)",
	   4,{syntax_error,'END'}},
	  {"SEQUENCE {} (WITH COMPONENTS { ..., x (10)",
	   4,{syntax_error,'END'}}
	 ],
    L = [{Head++S++End,Line,E} || {S,Line,E} <- L0],
    run(L, "Constraints", Config),
    ok.

exports(Config) ->
    Head = "Exports DEFINITIONS AUTOMATIC TAGS ::=\n"
	"BEGIN\n"
	" EXPORTS ",
    End = "\nEND\n",
    L0 = [{"Type",4,{syntax_error,'END'}}
	 ],
    L = [{Head++S++End,Line,E} || {S,Line,E} <- L0],
    run(L, "Exports", Config),
    ok.

header(Config) ->
    L = [{"lowercase",1,{syntax_error,lowercase}},
	 {"H ",2,{syntax_error,'END-OF-FILE'}},
	 {"H-",1,{syntax_error,'-'}},
	 {"42",1,{syntax_error,42}},
	 {"H definitions",1,{syntax_error,definitions}},
	 {"H DEFINITIONS STUPID TAGS",1,{syntax_error,'STUPID'}},
	 {"H DEFINITIONS WHATEVER",1,{syntax_error,'WHATEVER'}},
	 {"H DEFINITIONS ::= BEGIN",2,{syntax_error,'END-OF-FILE'}},
	 {"BOOLEAN",1,{syntax_error,'BOOLEAN'}}
	],
    run(L, "H", Config),
    ok.

imports(Config) ->
    Head = "Imports DEFINITIONS AUTOMATIC TAGS ::=\n"
	"BEGIN\n"
	" IMPORTS ",
    End = "\nEND\n",
    L0 = [{"Type FROM X",4,{syntax_error,'END'}},
	  {"Symbols TO Y",3,{syntax_error,'TO'}}
	 ],
    L = [{Head++S++End,Line,E} || {S,Line,E} <- L0],
    run(L, "Imports", Config),
    ok.

objects(Config) ->
    Head = "Objects DEFINITIONS AUTOMATIC TAGS ::=\n"
	"BEGIN\n"
	"  object CLASS-NAME ::= ",
    End = "\nEND\n",
    L0 = [{"{",4,{syntax_error,'END'}},
	  {"{&min 1, max 10}",3,{syntax_error,max}},
	  {"{&min 1, Max 10}",3,{syntax_error,'Max'}},
	  {"{min 1, &max 10}",3,{syntax_error,'&max'}},
	  {"{min 1, &Max 10}",3,{syntax_error,'&Max'}},
	  {"{RESERVERD WORD BIT}",3,{syntax_error,'BIT'}},
	  {"{&min 1",4,{syntax_error,'END'}}
	 ],
    L = [{Head++S++End,Line,E} || {S,Line,E} <- L0],
    run(L, "Objects", Config),
    ok.

sequence(Config) ->
    Head = "Sequence DEFINITIONS AUTOMATIC TAGS ::=\n"
	"BEGIN\n"
	"  Type ::= SEQUENCE {",
    End = "\nEND\n",
    L0 = [{"",4,{syntax_error,'END'}},
	  {" UpperCase",3,{syntax_error,'UpperCase'}},
	  {" a b",4,{syntax_error,'END'}},
	  {" i INTEGER",4,{syntax_error,'END'}},
	  {" ...",4,{syntax_error,'END'}},
	  {" ..., [[",4,{syntax_error,'END'}},
	  {" ..., [[ a INTEGER ]",3,{syntax_error,']'}},
	  {" ..., [[ a INTEGER,",3,{syntax_error,','}},
	  {" ..., [[ a INTEGER, ... ]]",3,{syntax_error,','}},
	  {" ... !42 xxx",3,{syntax_error,'xxx'}},
	  {" ... !42, a INTEGER,",3,{syntax_error,','}}
	 ],
    L = [{Head++S++End,Line,E} || {S,Line,E} <- L0],
    run(L, "Sequence", Config),
    ok.

syntax(Config) ->
    Head = "Syntax DEFINITIONS AUTOMATIC TAGS ::=\n"
	"BEGIN\n"
	" CL ::= CLASS { &id INTEGER UNIQUE } WITH SYNTAX ",
    End = "\nEND\n",
    L0 = [{"{}",3,{syntax_error,'}'}},
	  {"WORD",3,{syntax_error,'WORD'}},
	  {"{ Word }",3,{syntax_error,'Word'}},
	  {"{ [ Word ] }",3,{syntax_error,'Word'}},
	  {"{ [ WORD }",3,{syntax_error,'}'}},
	  {"{ WORD;",3,{syntax_error,';'}}
	 ],
    L = [{Head++S++End,Line,E} || {S,Line,E} <- L0],
    run(L, "Syntax", Config),
    ok.

types(Config) ->
    Head = "Types DEFINITIONS AUTOMATIC TAGS ::=\n"
	"BEGIN\n"
	"  Type ::= ",
    End = "\nEND\n",
    L0 = [{"BIT STRING garbage",4,{syntax_error,'END'}},
	  {"BIT STRING {",4,{syntax_error,'END'}},
	  {"BIT STRING { a(42",3,{syntax_error,42}},
	  {"BIT STRING { a(0)",4,{syntax_error,'END'}},
	  {"CHOICE {",4,{syntax_error,'END'}},
	  {"CHOICE { ..., a}",3,{syntax_error,'...'}},
	  {"CHOICE { UpperCase",3,{syntax_error,'UpperCase'}},
	  {"CHOICE { i INTEGER",4,{syntax_error,'END'}},
	  {"CHOICE { ..., i INTEGER }",3,{syntax_error,'...'}},
	  {"CHOICE { b BOOLEAN, ..., i INTEGER",
	   4,{syntax_error,'END'}},
	  {"CHOICE { b BOOLEAN, ..., [[ e BOOLEAN, ...]]}",
	   3,{syntax_error,','}},
	  {"CHOICE { b BOOLEAN, ..., i INTEGER, ..., x BIT STRING}",
	   3,{syntax_error,','}},
	  {"ENUMERATED {",4,{syntax_error,'END'}},
	  {"ENUMERATED { 42 }",3,{syntax_error,42}},
	  {"ENUMERATED { a, b",4,{syntax_error,'END'}},
	  {"ENUMERATED { a, }",3,{syntax_error,','}},
	  {"ENUMERATED { a, ...,\nb, ..., c }",4,{syntax_error,','}},
	  {"INTEGER {",4,{syntax_error,'END'}},
	  {"INTEGER { a(42)",4,{syntax_error,'END'}},
	  {"SEQUENCE",3,{syntax_error,'SEQUENCE'}},
	  %% More tests for SEQUENCE in sequence/1.
	  {"SEQUENCE SIZE (1..10)",4,{syntax_error,'END'}},
	  {"SEQUENCE (SIZE (1..10))",4,{syntax_error,'END'}},
	  {"SET { i INTEGER",4,{syntax_error,'END'}},
	  {"SET { ...",4,{syntax_error,'END'}},
	  {"SET SIZE (1..10)",4,{syntax_error,'END'}},
	  {"SET (SIZE (1..10))",4,{syntax_error,'END'}},
	  {"SET { ... !42 xxx",3,{syntax_error,'xxx'}},
	  {"SET { ... !42, a INTEGER,",3,{syntax_error,','}},
	  {"[",4,{syntax_error,'END'}},
	  {"[42",4,{syntax_error,'END'}}
	 ],
    L = [{Head++S++End,Line,E} || {S,Line,E} <- L0],
    run(L, "Types", Config),
    ok.

values(Config) ->
    Head = "Values DEFINITIONS AUTOMATIC TAGS ::=\n"
	"BEGIN\n"
	"  value Type ::= ",
    End = "\nEND\n",
    L0 = [{"",4,{syntax_error,'END'}}
	 ],
    L = [{Head++S++End,Line,E} || {S,Line,E} <- L0],
    run(L, "Values", Config),
    ok.

run(List, File0, Config) ->
    Base = File0 ++ ".asn1",
    File = filename:join(?config(priv_dir, Config), Base),
    case run_1(List, Base, File, 0) of
	0 -> ok;
	Errors -> ?t:fail(Errors)
    end.

run_1([{Source,Line,Error}=Exp|T], Base, File, N) ->
    M = asn1ct_parser2,
    ok = file:write_file(File, Source),
    io:format("~s", [Source]),
    case asn1ct:compile(File) of
	{error,[{structured_error,{Base,L},M,E}]} ->
	    case {L,E} of
		{Line,Error} ->
		    run_1(T, Base, File, N);
		{Line,OtherError} ->
		    io:format("*** Wrong error: ~p, expected ~p ***\n",
			      [OtherError,Error]),
		    run_1(T, Base, File, N+1);
		{OtherLine,Error} ->
		    io:format("*** Wrong line: ~p, expected ~p ***\n",
			      [OtherLine,Line]),
		    run_1(T, Base, File, N+1);
		{_,_} ->
		    io:format("*** Wrong line: ~p, expected ~p ***",
			      [L,Line]),
		    io:format("*** Wrong error: ~p, expected ~p ***\n",
			      [E,Error]),
		    run_1(T, Base, File, N+1)
	    end;
	Other ->
	    io:format("~p\nGOT: ~p", [Exp,Other])
    end;
run_1([], _, _, N) ->
    N.