aboutsummaryrefslogblamecommitdiffstats
path: root/lib/asn1/test/asn1_SUITE.erl
blob: 3d3ed65a65e04333e7ea0200384a1fb1e2814d12 (plain) (tree)
1
  




















                                                                         
                       

                            
         











                                                                                

                       














                                                   

                                



                        
                      





                                                
                    





























                                                                          
                          

















































































                                                           



                       
                     
                      
































                                                                                

                                                     



                                                  
                                             






                                                                                

                               












































































                                                                                





                                                           






















                                                                              
                                                                          
                                                          

                                                  























                                                                                
                





























                                                                         




                                                                     
























                                                                   

                                                


























































                                                                                
                                                   


















































































































                                                                                
                                             



                                                         
                                                        





                                                                     



























                                                                        



                                                                     
                                        



                                                               

                                         













                                                                          
                                               



                                                              
                                            









                                                              

































                                                                               
                                           









                                                                       
                                                











                                                              
                                                 





                                                                            
                                                                  






                                                                 
                                                                   



                                          

                                                 





                                                                   

                                                 





                                                                   

                                                    




























































                                                                         
                                          















































                                                                                                         
                                                    














                                                                      
                                        



                                          



                                                                    


                  
                                       








                                                                  
                                                   






                                                           
                                                               



                                                
                                                          






                                                                      
                                                




                                                           
                                                              

                             
                                                                 

                                      
                                                              






                                                                   
                                            






















                                                                       
                  



                                                         
                                           











                                                       
                                              


                                                
                                                                    




























                                                                                  


                              
                   
                                        





                                               
                                               



                                                          
                                                









                                                                        
                                                                























































































                                                                                                      



                                 



                                 


                                            

















                                                                       

                


                                                                                

                                                                  

                                                                             



                                          







                                                  


                      
                                                                


                                                       
                                                    









                                                                           
                                                       







                                                                             
                                                       



















                                                                                       

                                                                   




































                                                                            
                                               












































































































































































                                                                                 
                                                          








                                                               
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2001-2012. 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%
%%
%% Purpose: Test suite for the ASN.1 application

-module(asn1_SUITE).

-define(only_ber(Func),
    if Rule =:= ber -> Func;
       true -> ok
    end).

-compile(export_all).

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

%%------------------------------------------------------------------------------
%% Suite definition
%%------------------------------------------------------------------------------

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

all() ->
    [{group, compile},
     {group, parallel},
     {group, app_test},
     {group, appup_test},

     % TODO: Investigate parallel running of these:
     testComment,
     testName2Number,
     ticket_7407,
     ticket7904,

     {group, performance}].

groups() ->
    [{compile, parallel([]),
      [c_syntax,
       c_string,
       c_implicit_before_choice,
       constraint_equivalence]},

     {ber, parallel([]),
      [ber_choiceinseq,
       % Uses 'SOpttest'
       ber_optional]},

     {app_test, [], [{asn1_app_test, all}]},

     {appup_test, [], [{asn1_appup_test, all}]},

     {parallel, parallel([]),
      [{group, ber},
       % Uses 'P-Record', 'Constraints', 'MEDIA-GATEWAY-CONTROL'...
       {group, [], [parse,
                    test_driver_load,
                    test_undecoded_rest,
                    test_inline,
                    specialized_decodes,
                    special_decode_performance,
                    testMegaco,
                    testConstraints,
                    testCompactBitString]},
       default,
       % Uses 'Def', 'MULTIMEDIA-SYSTEM-CONTROL', 'H323-MESSAGES', 'Prim',
       %   'Real'
       {group, [], [testPrim,
                    rtUI,
                    testPrimStrings,
                    testInvokeMod,
                    per,
                    ber_other,
                    h323test,
                    per_GeneralString]},
       testChoPrim,
       testChoExtension,
       testChoOptional,
       testChoOptionalImplicitTag,
       testChoRecursive,
       testChoTypeRefCho,
       testChoTypeRefPrim,
       testChoTypeRefSeq,
       testChoTypeRefSet,
       testMultipleLevels,
       testDef,
       testOpt,
       testSeqDefault,
       % Uses 'External'
       {group, [], [testChoExternal,
                    testPrimExternal,
                    testSeqExtension,
                    testSeqExternal,
                    testSeqOfExternal,
                    testSeqOfTag,
                    testSeqTag,
                    testSetExtension,
                    testSetExternal,
                    testSetOfExternal,
                    testSetOfTag,
                    testSetTag]},
       testSeqOptional,
       testSeqPrim,
       testSeqTypeRefCho,
       % Uses 'SeqTypeRefPrim'
       {group, [], [testSeqTypeRefPrim,
                    testTypeValueNotation]},
       testSeqTypeRefSeq,
       testSeqTypeRefSet,
       % Uses 'SeqOf'
       {group, [], [testSeqOf,
                    testSeqOfIndefinite]}, % Uses 'Mvrasn*'
       testSeqOfCho,
       testSetDefault,
       testExtensionAdditionGroup,
       testSetOptional,
       testSetPrim,
       testSetTypeRefCho,
       testSetTypeRefPrim,
       testSetTypeRefSeq,
       testSetTypeRefSet,
       testSetOf,
       testSetOfCho,
       testEnumExt,
       value_test,
       value_bad_enum_test,
       testSeq2738,
       % Uses 'Constructed'
       {group, [], [constructed,
                    ber_decode_error]},
       % Uses 'SeqSetIndefinite'
       {group, [], [testSeqIndefinite,
                    testSetIndefinite]},
       testChoiceIndefinite,
       per_open_type,
       testInfObjectClass,
       testParameterizedInfObj,
       testMergeCompile,
       testobj,
       testDeepTConstr,
       testExport,
       testImport,
       % Uses 'ParamBasic'
       {group, [], [testParamBasic,
                    testDER]},
       testMvrasn6,
       testContextSwitchingTypes,
       testOpenTypeImplicitTag,
       duplicate_tags,
       testROSE,
       testINSTANCE_OF,
       testTCAP,
       test_ParamTypeInfObj,
       test_WS_ParamClass,
       test_Defed_ObjectIdentifier,
       testSelectionType,
       testSSLspecs,
       testNortel,
       % Uses 'PKCS7'
       {group, [], [test_modified_x420,
                    testX420]},
       testTcapsystem,
       testNBAPsystem,
       test_compile_options,
       testDoubleEllipses,
       test_x691,
       ticket_6143,
       test_OTP_9688]},

     {performance, [],
      [testTimer_ber,
       testTimer_per,
       testTimer_uper,
       smp]}].

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

%%------------------------------------------------------------------------------
%% Init/end
%%------------------------------------------------------------------------------

init_per_suite(Config) ->
    PrivDir = ?config(priv_dir, Config),
    true = code:add_patha(PrivDir),
    Config.

end_per_suite(_Config) ->
    ok.

init_per_group(_GroupName, Config) ->
    Config.

end_per_group(_GroupName, Config) ->
    Config.

init_per_testcase(Func, Config) ->
    CaseDir = filename:join([?config(priv_dir, Config), ?MODULE, Func]),
    ok = filelib:ensure_dir(filename:join([CaseDir, dummy_file])),
    true = code:add_patha(CaseDir),

    Dog = case Func of
              testX420 -> ct:timetrap({minutes, 90});
              _        -> ct:timetrap({minutes, 60})
          end,
    [{case_dir, CaseDir}, {watchdog, Dog}|Config].

end_per_testcase(_Func, Config) ->
    code:del_path(?config(case_dir, Config)).

%%------------------------------------------------------------------------------
%% Test runners
%%------------------------------------------------------------------------------

test(Config, TestF) ->
    test(Config, TestF, [per,
                         uper,
                         ber]).

test(Config, TestF, Rules) ->
    Fun = fun(C, R, O) ->
                  M = element(2, erlang:fun_info(TestF, module)),
                  F = element(2, erlang:fun_info(TestF, name)),
                  io:format("Running ~p:~p with ~p...~n", [M, F, {R, O}]),
                  try
                      TestF(C, R, O)
                  catch
                      Class:Reason ->
                          NewReason = {Reason, [{rule, R}, {options, O}]},
                          erlang:raise(Class, NewReason,
                                       erlang:get_stacktrace())
                  end
          end,
    Result = [run_case(Config, Fun, rule(Rule), opts(Rule)) || Rule <- Rules],
    case lists:usort(Result) of
        [true|_Skips] -> true; % At least one test ran
        Skips        -> {skip, [R || {skip, R} <- Skips]} % All skipped
    end.

rule(A) when is_atom(A) -> A;
rule({A, _Opts} )       -> A.

opts(Rule) when is_atom(Rule) -> [];
opts({_Rule, Opts})         -> Opts.

run_case(Config, Fun, Rule, Opts) ->
    CaseDir = ?config(case_dir, Config),
    Dir = filename:join([CaseDir, join(Rule, Opts)]),
    ok = filelib:ensure_dir(filename:join([Dir, dummy_file])),
    replace_path(CaseDir, Dir),
    NewConfig = lists:keyreplace(case_dir, 1, Config, {case_dir, Dir}),

    % Run the actual test function
    Result = Fun(NewConfig, Rule, Opts),

    replace_path(Dir, CaseDir),
    case Result of
        {skip, _Reason} -> Result;
        _               -> true
    end.

replace_path(PathA, PathB) ->
    true = code:del_path(PathA),
    true = code:add_patha(PathB).

join(Rule, Opts) ->
    string:join([atom_to_list(Rule)|lists:map(fun atom_to_list/1, Opts)], "_").

case_dir([], _Dir) ->
    exit(no_case_dir);
case_dir([{case_dir, _}|Config], Dir) ->
    [{case_dir, Dir}|Config];
case_dir([C|Config], Opt) ->
    [C|case_dir(Config, Opt)].

%%------------------------------------------------------------------------------
%% Test cases
%%------------------------------------------------------------------------------

testPrim(Config) -> test(Config, fun testPrim/3).
testPrim(Config, Rule, Opts) ->
    asn1_test_lib:compile_all(["Prim", "Real"], Config, [Rule|Opts]),
    testPrim:bool(Rule),
    testPrim:int(Rule),
    testPrim:enum(Rule),
    testPrim:obj_id(Rule),
    testPrim:rel_oid(Rule),
    testPrim:null(Rule),
    testPrim:real(Rule).

testCompactBitString(Config) -> test(Config, fun testCompactBitString/3).
testCompactBitString(Config, Rule, Opts) ->
    asn1_test_lib:compile("PrimStrings", Config,
                          [Rule, compact_bit_string|Opts]),
    testCompactBitString:compact_bit_string(Rule),
    testCompactBitString:bit_string_unnamed(Rule),
    testCompactBitString:bit_string_unnamed(Rule),
    testCompactBitString:ticket_7734(Rule),
    asn1_test_lib:compile("Constraints", Config,
			  [Rule, compact_bit_string|Opts]),
    testCompactBitString:otp_4869(Rule).

testPrimStrings(Config) -> test(Config, fun testPrimStrings/3).
testPrimStrings(Config, Rule, Opts) ->
    asn1_test_lib:compile_all(["PrimStrings", "BitStr"], Config, [Rule|Opts]),
    testPrimStrings_cases(Rule),
    ?only_ber(testPrimStrings:more_strings(Rule)).

testPrimStrings_cases(Rule) ->
    testPrimStrings:bit_string(Rule),
    testPrimStrings:bit_string_unnamed(Rule),
    testPrimStrings:octet_string(Rule),
    testPrimStrings:numeric_string(Rule),
    testPrimStrings:other_strings(Rule),
    testPrimStrings:universal_string(Rule),
    testPrimStrings:bmp_string(Rule),
    testPrimStrings:times(Rule),
    testPrimStrings:utf8_string(Rule).

testPrimExternal(Config) -> test(Config, fun testPrimExternal/3).
testPrimExternal(Config, Rule, Opts) ->
    asn1_test_lib:compile_all(["External", "PrimExternal"], Config,
                              [Rule|Opts]),
    testPrimExternal:external(Rule),
    ?only_ber(asn1_test_lib:compile_all(["PrimStrings", "BitStr"], Config,
                                            [Rule|Opts])),
    ?only_ber(testPrimStrings_cases(Rule)),
    ?only_ber(testPrimStrings:more_strings(Rule)).

testChoPrim(Config) -> test(Config, fun testChoPrim/3).
testChoPrim(Config, Rule, Opts) ->
    asn1_test_lib:compile("ChoPrim", Config, [Rule|Opts]),
    testChoPrim:bool(Rule),
    testChoPrim:int(Rule).

testChoExtension(Config) -> test(Config, fun testChoExtension/3).
testChoExtension(Config, Rule, Opts) ->
    asn1_test_lib:compile("ChoExtension", Config, [Rule|Opts]),
    testChoExtension:extension(Rule).

testChoExternal(Config) -> test(Config, fun testChoExternal/3).
testChoExternal(Config, Rule, Opts) ->
    asn1_test_lib:compile_all(["External", "ChoExternal"], Config, [Rule|Opts]),
    testChoExternal:external(Rule).

testChoOptional(Config) -> test(Config, fun testChoOptional/3).
testChoOptional(Config, Rule, Opts) ->
    asn1_test_lib:compile("ChoOptional", Config, [Rule|Opts]),
    testChoOptional:optional(Rule).

testChoOptionalImplicitTag(Config) ->
    test(Config, fun testChoOptionalImplicitTag/3,
	 [ber]).
testChoOptionalImplicitTag(Config, Rule, Opts) ->
    %% Only meaningful for ber & co
    asn1_test_lib:compile("ChoOptionalImplicitTag", Config, [Rule|Opts]),
    testChoOptionalImplicitTag:optional(Rule).

testChoRecursive(Config) -> test(Config, fun testChoRecursive/3).
testChoRecursive(Config, Rule, Opts) ->
    asn1_test_lib:compile("ChoRecursive", Config, [Rule|Opts]),
    testChoRecursive:recursive(Rule).

testChoTypeRefCho(Config) -> test(Config, fun testChoTypeRefCho/3).
testChoTypeRefCho(Config, Rule, Opts) ->
    asn1_test_lib:compile("ChoTypeRefCho", Config, [Rule|Opts]),
    testChoTypeRefCho:choice(Rule).

testChoTypeRefPrim(Config) -> test(Config, fun testChoTypeRefPrim/3).
testChoTypeRefPrim(Config, Rule, Opts) ->
    asn1_test_lib:compile("ChoTypeRefPrim", Config, [Rule|Opts]),
    testChoTypeRefPrim:prim(Rule).

testChoTypeRefSeq(Config) -> test(Config, fun testChoTypeRefSeq/3).
testChoTypeRefSeq(Config, Rule, Opts) ->
    asn1_test_lib:compile("ChoTypeRefSeq", Config, [Rule|Opts]),
    testChoTypeRefSeq:seq(Rule).

testChoTypeRefSet(Config) -> test(Config, fun testChoTypeRefSet/3).
testChoTypeRefSet(Config, Rule, Opts) ->
    asn1_test_lib:compile("ChoTypeRefSet", Config, [Rule|Opts]),
    testChoTypeRefSet:set(Rule).

testMultipleLevels(Config) -> test(Config, fun testMultipleLevels/3).
testMultipleLevels(Config, Rule, Opts) ->
    asn1_test_lib:compile("MultipleLevels", Config, [Rule|Opts]),
    testMultipleLevels:main(Rule).

testDef(Config) -> test(Config, fun testDef/3).
testDef(Config, Rule, Opts) ->
    asn1_test_lib:compile("Def", Config, [Rule|Opts]),
    testDef:main(Rule).

testOpt(Config) -> test(Config, fun testOpt/3).
testOpt(Config, Rule, Opts) ->
    asn1_test_lib:compile("Opt", Config, [Rule|Opts]),
    testOpt:main(Rule).

testEnumExt(Config) -> test(Config, fun testEnumExt/3).
testEnumExt(Config, Rule, Opts) ->
    asn1_test_lib:compile("EnumExt", Config, [Rule|Opts]),
    testEnumExt:main(Rule).

%% Test of OTP-2523 ENUMERATED with extensionmark.
testSeqDefault(Config) -> test(Config, fun testSeqDefault/3).
testSeqDefault(Config, Rule, Opts) ->
    asn1_test_lib:compile("SeqDefault", Config, [Rule|Opts]),
    testSeqDefault:main(Rule).

testSeqExtension(Config) -> test(Config, fun testSeqExtension/3).
testSeqExtension(Config, Rule, Opts) ->
    asn1_test_lib:compile_all(["External", "SeqExtension"], Config,
                              [Rule|Opts]),
    DataDir = ?config(data_dir, Config),
    testSeqExtension:main(DataDir, [Rule|Opts]).

testSeqExternal(Config) -> test(Config, fun testSeqExternal/3).
testSeqExternal(Config, Rule, Opts) ->
    asn1_test_lib:compile_all(["External", "SeqExternal"], Config, [Rule|Opts]),
    testSeqExternal:main(Rule).

testSeqOptional(Config) -> test(Config, fun testSeqOptional/3).
testSeqOptional(Config, Rule, Opts) ->
    asn1_test_lib:compile("SeqOptional", Config, [Rule|Opts]),
    testSeqOptional:main(Rule).

testSeqPrim(Config) -> test(Config, fun testSeqPrim/3).
testSeqPrim(Config, Rule, Opts) ->
    asn1_test_lib:compile("SeqPrim", Config, [Rule|Opts]),
    testSeqPrim:main(Rule).

%% Test of OTP-2738 Detect corrupt optional component.
testSeq2738(Config) -> test(Config, fun testSeq2738/3).
testSeq2738(Config, Rule, Opts) ->
    asn1_test_lib:compile("Seq2738", Config, [Rule|Opts]),
    testSeq2738:main(Rule).

testSeqTag(Config) -> test(Config, fun testSeqTag/3).
testSeqTag(Config, Rule, Opts) ->
    asn1_test_lib:compile_all(["External", "SeqTag"], Config, [Rule|Opts]),
    testSeqTag:main(Rule).

testSeqTypeRefCho(Config) -> test(Config, fun testSeqTypeRefCho/3).
testSeqTypeRefCho(Config, Rule, Opts) ->
    asn1_test_lib:compile("SeqTypeRefCho", Config, [Rule|Opts]),
    testSeqTypeRefCho:main(Rule).

testSeqTypeRefPrim(Config) -> test(Config, fun testSeqTypeRefPrim/3).
testSeqTypeRefPrim(Config, Rule, Opts) ->
    asn1_test_lib:compile("SeqTypeRefPrim", Config, [Rule|Opts]),
    testSeqTypeRefPrim:main(Rule).

testSeqTypeRefSeq(Config) -> test(Config, fun testSeqTypeRefSeq/3).
testSeqTypeRefSeq(Config, Rule, Opts) ->
    asn1_test_lib:compile("SeqTypeRefSeq", Config, [Rule|Opts]),
    testSeqTypeRefSeq:main(Rule).

testSeqTypeRefSet(Config) -> test(Config, fun testSeqTypeRefSet/3).
testSeqTypeRefSet(Config, Rule, Opts) ->
    asn1_test_lib:compile("SeqTypeRefSet", Config, [Rule|Opts]),
    testSeqTypeRefSet:main(Rule).

testSeqOf(Config) -> test(Config, fun testSeqOf/3).
testSeqOf(Config, Rule, Opts) ->
    asn1_test_lib:compile_all(["SeqOf", "SeqOfEnum", "XSeqOf"], Config,
                              [Rule|Opts]),
    testSeqOf:main(Rule).

testSeqOfCho(Config) -> test(Config, fun testSeqOfCho/3).
testSeqOfCho(Config, Rule, Opts) ->
    asn1_test_lib:compile("SeqOfCho", Config, [Rule|Opts]),
    testSeqOfCho:main(Rule).

testSeqOfIndefinite(Config) ->
    test(Config, fun testSeqOfIndefinite/3, [ber]).
testSeqOfIndefinite(Config, Rule, Opts) ->
    Files = ["Mvrasn-Constants-1", "Mvrasn-DataTypes-1", "Mvrasn-21-4",
             "Mvrasn-20-4", "Mvrasn-19-4", "Mvrasn-18-4", "Mvrasn-17-4",
             "Mvrasn-15-4", "Mvrasn-14-4", "Mvrasn-11-4", "SeqOf"],
    asn1_test_lib:compile_all(Files, Config, [Rule|Opts]),
    testSeqOfIndefinite:main().

testSeqOfExternal(Config) -> test(Config, fun testSeqOfExternal/3).
testSeqOfExternal(Config, Rule, Opts) ->
    asn1_test_lib:compile_all(["External", "SeqOfExternal"], Config,
                              [Rule|Opts]),
    testSeqOfExternal:main(Rule).

testSeqOfTag(Config) -> test(Config, fun testSeqOfTag/3).
testSeqOfTag(Config, Rule, Opts) ->
    asn1_test_lib:compile_all(["External", "SeqOfTag"], Config, [Rule|Opts]),
    testSeqOfTag:main(Rule).

testSetDefault(Config) -> test(Config, fun testSetDefault/3).
testSetDefault(Config, Rule, Opts) ->
    asn1_test_lib:compile("SetDefault", Config, [Rule|Opts]),
    testSetDefault:main(Rule).

testParamBasic(Config) -> test(Config, fun testParamBasic/3).
testParamBasic(Config, Rule, Opts) ->
    asn1_test_lib:compile("ParamBasic", Config, [Rule|Opts]),
    testParamBasic:main(Rule).

testSetExtension(Config) -> test(Config, fun testSetExtension/3).
testSetExtension(Config, Rule, Opts) ->
    asn1_test_lib:compile_all(["External", "SetExtension"], Config,
                              [Rule|Opts]),
    testSetExtension:main(Rule).

testSetExternal(Config) -> test(Config, fun testSetExternal/3).
testSetExternal(Config, Rule, Opts) ->
    asn1_test_lib:compile_all(["External", "SetExternal"], Config, [Rule|Opts]),
    testSetExternal:main(Rule).

testSetOptional(Config) -> test(Config, fun testSetOptional/3).
testSetOptional(Config, Rule, Opts) ->
    asn1_test_lib:compile("SetOptional", Config, [Rule|Opts]),
    testSetOptional:ticket_7533(Rule),
    testSetOptional:main(Rule).

testSetPrim(Config) -> test(Config, fun testSetPrim/3).
testSetPrim(Config, Rule, Opts) ->
    asn1_test_lib:compile("SetPrim", Config, [Rule|Opts]),
    testSetPrim:main(Rule).

testSetTag(Config) -> test(Config, fun testSetTag/3).
testSetTag(Config, Rule, Opts) ->
    asn1_test_lib:compile_all(["External", "SetTag"], Config, [Rule|Opts]),
    testSetTag:main(Rule).

testSetTypeRefCho(Config) -> test(Config, fun testSetTypeRefCho/3).
testSetTypeRefCho(Config, Rule, Opts) ->
    asn1_test_lib:compile("SetTypeRefCho", Config, [Rule|Opts]),
    testSetTypeRefCho:main(Rule).

testSetTypeRefPrim(Config) -> test(Config, fun testSetTypeRefPrim/3).
testSetTypeRefPrim(Config, Rule, Opts) ->
    asn1_test_lib:compile("SetTypeRefPrim", Config, [Rule|Opts]),
    testSetTypeRefPrim:main(Rule).

testSetTypeRefSeq(Config) -> test(Config, fun testSetTypeRefSeq/3).
testSetTypeRefSeq(Config, Rule, Opts) ->
    asn1_test_lib:compile("SetTypeRefSeq", Config, [Rule|Opts]),
    testSetTypeRefSeq:main(Rule).

testSetTypeRefSet(Config) -> test(Config, fun testSetTypeRefSet/3).
testSetTypeRefSet(Config, Rule, Opts) ->
    asn1_test_lib:compile("SetTypeRefSet", Config, [Rule|Opts]),
    testSetTypeRefSet:main(Rule).

testSetOf(Config) -> test(Config, fun testSetOf/3).
testSetOf(Config, Rule, Opts) ->
    asn1_test_lib:compile("SetOf", Config, [Rule|Opts]),
    testSetOf:main(Rule).

testSetOfCho(Config) -> test(Config, fun testSetOfCho/3).
testSetOfCho(Config, Rule, Opts) ->
    asn1_test_lib:compile("SetOfCho", Config, [Rule|Opts]),
    testSetOfCho:main(Rule).

testSetOfExternal(Config) -> test(Config, fun testSetOfExternal/3).
testSetOfExternal(Config, Rule, Opts) ->
    asn1_test_lib:compile_all(["External", "SetOfExternal"], Config,
                              [Rule|Opts]),
    testSetOfExternal:main(Rule).

testSetOfTag(Config) -> test(Config, fun testSetOfTag/3).
testSetOfTag(Config, Rule, Opts) ->
    asn1_test_lib:compile_all(["External", "SetOfTag"], Config, [Rule|Opts]),
    testSetOfTag:main(Rule).

c_syntax(Config) ->
    DataDir = ?config(data_dir, Config),
    [{error, _} = asn1ct:compile(filename:join(DataDir, F))
     || F <-["Syntax",
             "BadTypeEnding",
             "BadValueAssignment1",
             "BadValueAssignment2",
             "BadValueSet",
             "ChoiceBadExtension",
             "EnumerationBadExtension",
             "Example",
             "Export1",
             "MissingEnd",
             "SequenceBadComma",
             "SequenceBadComponentName",
             "SequenceBadComponentType",
             "SeqBadComma"]].

c_string(Config) ->
    test(Config, fun c_string/3, [per, ber]).
c_string(Config, Rule, Opts) ->
    asn1_test_lib:compile("String", Config, [Rule|Opts]).

c_implicit_before_choice(Config) ->
    test(Config, fun c_implicit_before_choice/3, [ber]).
c_implicit_before_choice(Config, Rule, Opts) ->
    DataDir = ?config(data_dir, Config),
    CaseDir = ?config(case_dir, Config),
    {error, _R2} = asn1ct:compile(filename:join(DataDir, "CCSNARG3"),
                                  [Rule, {outdir, CaseDir}|Opts]).

constraint_equivalence(Config) ->
    DataDir = ?config(data_dir, Config),
    CaseDir = ?config(case_dir, Config),
    Asn1Spec = "ConstraintEquivalence",
    Asn1Src = filename:join(DataDir, Asn1Spec),
    ok = asn1ct:compile(Asn1Src, [abs,{outdir,CaseDir}]),
    AbsFile = filename:join(CaseDir, Asn1Spec++".abs"),
    {ok,Terms} = file:consult(AbsFile),
    Cs = [begin
	      'INTEGER' = element(3, Type),	%Assertion.
	      Constraints = element(4, Type),
	      Name1 = atom_to_list(Name0),
	      {Name,_} = lists:splitwith(fun(C) -> C =/= $X end, Name1),
	      {Name,Constraints}
	  end || {typedef,_,_,Name0,Type} <- Terms],
    R = sofs:relation(Cs, [{name,constraint}]),
    F0 = sofs:relation_to_family(R),
    F = sofs:to_external(F0),
    Diff = [E || {_,L}=E <- F, length(L) > 1],
    case Diff of
	[] ->
	    ok;
	[_|_] ->
	    io:put_chars("Not equivalent:\n"),
	    [io:format("~s: ~p\n", [N,D]) || {N,D} <- Diff],
	    test_server:fail(length(Diff))
    end.

parse(Config) ->
    [asn1_test_lib:compile(M, Config, [abs]) || M <- test_modules()].

per(Config) ->
    test(Config, fun per/3, [per,uper]).
per(Config, Rule, Opts) ->
    [module_test(M, Config, Rule, Opts) || M <- per_modules()].

ber_other(Config) ->
    test(Config, fun ber_other/3, [ber]).

ber_other(Config, Rule, Opts) ->
    [module_test(M, Config, Rule, Opts) || M <- ber_modules()].


module_test(M, Config, Rule, Opts) ->
    asn1_test_lib:compile(M, Config, [Rule|Opts]),
    case asn1ct:test(list_to_atom(M), [{i, ?config(case_dir, Config)}]) of
        ok    -> ok;
        Error ->
            erlang:error({test_failed, M, Opts, Error})
    end.


ber_choiceinseq(Config) ->
    test(Config, fun ber_choiceinseq/3, [ber]).
ber_choiceinseq(Config, Rule, Opts) ->
    asn1_test_lib:compile("ChoiceInSeq", Config, [Rule|Opts]).

ber_optional(Config) ->
    test(Config, fun ber_optional/3, [ber]).
ber_optional(Config, Rule, Opts) ->
    asn1_test_lib:compile("SOpttest", Config, [Rule|Opts]),
    V = {'S', {'A', 10, asn1_NOVALUE, asn1_NOVALUE},
              {'B', asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE},
              {'C', asn1_NOVALUE, 111, asn1_NOVALUE}},
    {ok, B} = asn1_wrapper:encode('SOpttest', 'S', V),
    Bytes = lists:flatten(B),
    V2 = asn1_wrapper:decode('SOpttest', 'S', Bytes),
    V = element(2, V2).

%% records used by test-case default
-record('Def1', {bool0,
                 bool1 = asn1_DEFAULT,
                 bool2 = asn1_DEFAULT,
                 bool3 = asn1_DEFAULT}).

default(Config) -> test(Config, fun default/3).
default(Config, Rule, Opts) ->
    asn1_test_lib:compile("Def", Config, [Rule|Opts]),
    {ok, Bytes1} = asn1_wrapper:encode('Def', 'Def1', #'Def1'{bool0 = true}),
    {ok, {'Def1', true, false, false, false}} =
        asn1_wrapper:decode('Def', 'Def1', lists:flatten(Bytes1)),

    {ok, Bytes2} = asn1_wrapper:encode('Def', 'Def1', #'Def1'{bool0 = true,
                                                              bool2 = false}),
    {ok, {'Def1', true, false, false, false}} =
        asn1_wrapper:decode('Def', 'Def1', lists:flatten(Bytes2)).

value_test(Config) -> test(Config, fun value_test/3).
value_test(Config, Rule, Opts) ->
    asn1_test_lib:compile("ObjIdValues", Config, [Rule|Opts]),
    {ok, _} = asn1ct:test('ObjIdValues', 'ObjIdType',
                          'ObjIdValues':'mobileDomainId'()).

value_bad_enum_test(Config) ->
    case ?MODULE of
        asn1_SUITE ->
            {error, _} = asn1ct:compile(?config(data_dir, Config)
                                            ++ "BadEnumValue1",
                                        [{outdir, ?config(case_dir, Config)}]);
        _ -> {skip, "Runs in asn1_SUITE only"}
    end.

constructed(Config) ->
    test(Config, fun constructed/3, [ber]).
constructed(Config, Rule, Opts) ->
    asn1_test_lib:compile("Constructed", Config, [Rule|Opts]),
    {ok, B} = asn1_wrapper:encode('Constructed', 'S', {'S', false}),
    [40, 3, 1, 1, 0] = lists:flatten(B),
    {ok, B1} = asn1_wrapper:encode('Constructed', 'S2', {'S2', false}),
    [40, 5, 48, 3, 1, 1, 0] = lists:flatten(B1),
    {ok, B2} = asn1_wrapper:encode('Constructed', 'I', 10),
    [136, 1, 10] = lists:flatten(B2).

ber_decode_error(Config) ->
    test(Config, fun ber_decode_error/3, [ber]).
ber_decode_error(Config, Rule, Opts) ->
    asn1_test_lib:compile("Constructed", Config, [Rule|Opts]),
    ber_decode_error:run(Opts).

h323test(Config) -> test(Config, fun h323test/3).
h323test(Config, Rule, Opts) ->
    Files = ["H235-SECURITY-MESSAGES", "H323-MESSAGES",
             "MULTIMEDIA-SYSTEM-CONTROL"],
    asn1_test_lib:compile_all(Files, Config, [Rule|Opts]),
    h323test:run(Rule).

per_GeneralString(Config) ->
    test(Config, fun per_GeneralString/3, [per]).
per_GeneralString(Config, Rule, Opts) ->
    asn1_test_lib:compile("MULTIMEDIA-SYSTEM-CONTROL", Config, [Rule|Opts]),
    UI = [109, 64, 1, 57],
    {ok, _V} = asn1_wrapper:decode('MULTIMEDIA-SYSTEM-CONTROL',
                                   'MultimediaSystemControlMessage', UI).

per_open_type(Config) -> test(Config, fun per_open_type/3, [per]).
per_open_type(Config, Rule, Opts) ->
    asn1_test_lib:compile("OpenType", Config, [Rule|Opts]),
    {ok, _} = asn1ct:test('OpenType', 'Ot', {'Stype', 10, true}).

testConstraints(Config) -> test(Config, fun testConstraints/3).
testConstraints(Config, Rule, Opts) ->
    asn1_test_lib:compile("Constraints", Config, [Rule|Opts]),
    asn1_test_lib:compile("LargeConstraints", Config, [Rule|Opts]),
    testConstraints:int_constraints(Rule).


testSeqIndefinite(Config) ->
    test(Config, fun testSeqIndefinite/3, [ber]).

testSeqIndefinite(Config, Rule, Opts) ->
    asn1_test_lib:compile("SeqSetIndefinite", Config, [Rule|Opts]),
    testSeqIndefinite:main(Rule).


testSetIndefinite(Config) ->
    test(Config, fun testSetIndefinite/3, [ber]).

testSetIndefinite(Config, Rule, Opts) ->
    asn1_test_lib:compile("SeqSetIndefinite", Config, [Rule|Opts]),
    testSetIndefinite:main(Rule).


testChoiceIndefinite(Config) ->
    test(Config, fun testChoiceIndefinite/3, [ber]).

testChoiceIndefinite(Config, Rule, Opts) ->
    asn1_test_lib:compile("ChoiceIndef", Config, [Rule|Opts]),
    testChoiceIndefinite:main(Rule).

testInfObjectClass(Config) -> test(Config, fun testInfObjectClass/3).
testInfObjectClass(Config, Rule, Opts) ->
    Files       = ["ErrorClass", "InfClass"],
    InfObjFiles = ["RANAPextract1", "InfObj", "MAP-ExtensionDataTypes",
                   "Objects", "INAPv2extract"],
    RANAPFiles  = ["RANAP-CommonDataTypes", "RANAP-Constants",
                   "RANAP-Containers", "RANAP-IEs", "RANAP-PDU-Contents",
                   "RANAP-PDU-Descriptions"],
    asn1_test_lib:compile_all(Files ++ InfObjFiles ++ RANAPFiles, Config,
                              [Rule|Opts]),
    testInfObjectClass:main(Rule),
    testInfObj:main(Rule).

testParameterizedInfObj(Config) ->
    test(Config, fun testParameterizedInfObj/3).
testParameterizedInfObj(Config, Rule, Opts) ->
    asn1_test_lib:compile("Param", Config, [Rule|Opts]),
    testParameterizedInfObj:main(Rule).

testMergeCompile(Config) -> test(Config, fun testMergeCompile/3).
testMergeCompile(Config, Rule, Opts) ->
    Files = ["MS.set.asn", "RANAPSET.set.asn1", "Mvrasn4.set.asn",
             "Mvrasn6.set.asn"],
    asn1_test_lib:compile_all(Files, Config, [Rule|Opts]),
    testMergeCompile:main(Rule),
    testMergeCompile:mvrasn(Rule).

testobj(Config) -> test(Config, fun testobj/3).
testobj(Config, Rule, Opts) ->
    asn1_test_lib:compile("RANAP", Config, [Rule|Opts]),
    asn1_test_lib:compile_erlang("testobj", Config, []),
    ok = testobj:run(),
    ok = testParameterizedInfObj:ranap(Rule).

testDeepTConstr(Config) -> test(Config, fun testDeepTConstr/3).
testDeepTConstr(Config, Rule, Opts) ->
    asn1_test_lib:compile_all(["TConstrChoice", "TConstr"], Config,
                              [Rule|Opts]),
    testDeepTConstr:main(Rule).

testInvokeMod(Config) -> test(Config, fun testInvokeMod/3).
testInvokeMod(Config, Rule, Opts) ->
    asn1_test_lib:compile("PrimStrings", Config, [Rule|Opts]),
    {ok, _Result2} = 'PrimStrings':encode('Bs1', [1, 0, 1, 0]).

testExport(Config) ->
    case ?MODULE of
        asn1_SUITE ->
            {error, {asn1, _Reason}} =
                asn1ct:compile(filename:join(?config(data_dir, Config),
                                             "IllegalExport"),
                               [{outdir, ?config(case_dir, Config)}]);
        _ ->
            {skip, "Runs in asn1_SUITE only"}
    end.

testImport(Config) ->
    test(Config, fun testImport/3, [ber]).
testImport(Config, Rule, Opts) ->
    {error, _} = asn1ct:compile(filename:join(?config(data_dir, Config),
                                              "ImportsFrom"),
                                [Rule, {outdir, ?config(priv_dir, Config)}
                                 |Opts]).

testMegaco(Config) -> test(Config, fun testMegaco/3).
testMegaco(Config, Rule, Opts) ->
    {ok, Module1, Module2} = testMegaco:compile(Config, Rule, Opts),
    ok = testMegaco:main(Module1, Config),
    ok = testMegaco:main(Module2, Config).

testMvrasn6(Config) -> test(Config, fun testMvrasn6/3).
testMvrasn6(Config, Rule, Opts) ->
    asn1_test_lib:compile_all(["Mvrasn-21-4", "Mvrasn-20-6", "Mvrasn-19-6",
                               "Mvrasn-15-6", "Mvrasn-18-6", "Mvrasn-14-6",
                               "Mvrasn-11-6"], Config, [Rule|Opts]).

testContextSwitchingTypes(Config) ->
    test(Config, fun testContextSwitchingTypes/3).
testContextSwitchingTypes(Config, Rule, Opts) ->
    asn1_test_lib:compile("ContextSwitchingTypes", Config, [Rule|Opts]),
    testContextSwitchingTypes:test(Config).

testTypeValueNotation(Config) -> test(Config, fun testTypeValueNotation/3).
testTypeValueNotation(Config, Rule, Opts) ->
    asn1_test_lib:compile_all(["SeqTypeRefPrim", "ValueTest"], Config,
                              [Rule|Opts]),
    testTypeValueNotation:main(Rule, Opts).

testOpenTypeImplicitTag(Config) ->
    test(Config, fun testOpenTypeImplicitTag/3).
testOpenTypeImplicitTag(Config, Rule, Opts) ->
    asn1_test_lib:compile("OpenTypeImplicitTag", Config, [Rule|Opts]),
    testOpenTypeImplicitTag:main(Rule).

duplicate_tags(Config) ->
    case ?MODULE of
        asn1_SUITE ->
            DataDir = ?config(data_dir, Config),
            CaseDir = ?config(case_dir, Config),
            {error, {asn1, [{error, {type, _, _, 'SeqOpt1Imp', {asn1, {duplicates_of_the_tags, _}}}}]}} =
            asn1ct:compile(filename:join(DataDir, "SeqOptional2"),
                           [abs, {outdir, CaseDir}]);
        _ ->
            {skip, "Runs in asn1_SUITE only"}
    end.

rtUI(Config) -> test(Config, fun rtUI/3, [per,ber]).
rtUI(Config, Rule, Opts) ->
    asn1_test_lib:compile("Prim", Config, [Rule|Opts]),
    {ok, _} = asn1rt:info('Prim').

testROSE(Config) -> test(Config, fun testROSE/3).
testROSE(Config, Rule, Opts) ->
    asn1_test_lib:compile("Remote-Operations-Merged.set.asn1", Config,
                          [Rule|Opts]).

testINSTANCE_OF(Config) -> test(Config, fun testINSTANCE_OF/3).
testINSTANCE_OF(Config, Rule, Opts) ->
    asn1_test_lib:compile("INSTANCEOF.asn1", Config, [Rule|Opts]),
    testINSTANCE_OF:main(Rule).

testTCAP(Config) ->
    test(Config, fun testTCAP/3, [ber]).
testTCAP(Config, Rule, Opts) ->
    testTCAP:compile(Config, [Rule|Opts]),
    testTCAP:test(Rule, Config),
    case Rule of
        ber ->
	    testTCAP:compile_asn1config(Config, [Rule, asn1config]),
	    testTCAP:test_asn1config();
        _ -> ok
    end.

testDER(Config) ->
    test(Config, fun testDER/3, [ber]).
testDER(Config, Rule, Opts) ->
    asn1_test_lib:compile("DERSpec", Config, [Rule, der|Opts]),
    testDER:test(),
    asn1_test_lib:compile("ParamBasic", Config, [Rule, der|Opts]),
    testParamBasic:main(der),
    asn1_test_lib:compile("Default", Config, [Rule, der|Opts]),
    testSeqSetDefaultVal:main(Rule).

specialized_decodes(Config) ->
    test(Config, fun specialized_decodes/3, [ber]).
specialized_decodes(Config, Rule, Opts) ->
    asn1_test_lib:compile_all(["PartialDecSeq.asn",
                               "PartialDecSeq2.asn",
                               "PartialDecSeq3.asn",
                               "PartialDecMyHTTP.asn",
                               "MEDIA-GATEWAY-CONTROL.asn",
                               "P-Record"],
                              Config, [Rule, asn1config|Opts]),
    test_partial_incomplete_decode:test(Config),
    test_selective_decode:test().

special_decode_performance(Config) ->
    test(Config, fun special_decode_performance/3, [ber]).
special_decode_performance(Config, Rule, Opts) ->
    Files = ["MEDIA-GATEWAY-CONTROL", "PartialDecSeq"],
    asn1_test_lib:compile_all(Files, Config, [Rule, asn1config|Opts]),
    test_special_decode_performance:go(all).


test_driver_load(Config) ->
    test(Config, fun test_driver_load/3, [per]).
test_driver_load(Config, Rule, Opts) ->
    asn1_test_lib:compile("P-Record", Config, [Rule|Opts]),
    test_driver_load:test(5).

test_ParamTypeInfObj(Config) ->
    asn1_test_lib:compile("IN-CS-1-Datatypes", Config, [ber]).

test_WS_ParamClass(Config) ->
    asn1_test_lib:compile("InformationFramework", Config, [ber]).

test_Defed_ObjectIdentifier(Config) ->
    asn1_test_lib:compile("UsefulDefinitions", Config, [ber]).

testSelectionType(Config) -> test(Config, fun testSelectionType/3).
testSelectionType(Config, Rule, Opts) ->
    asn1_test_lib:compile("SelectionType", Config, [Rule|Opts]),
    {ok, _}  = testSelectionTypes:test().

testSSLspecs(Config) ->
    test(Config, fun testSSLspecs/3, [ber]).
testSSLspecs(Config, Rule, Opts) ->
    ok = testSSLspecs:compile(Config,
                              [Rule, compact_bit_string, der|Opts]),
    testSSLspecs:run(Rule),

    case code:which(asn1ct) of
       cover_compiled ->
           ok;
       _ ->
           ok = testSSLspecs:compile_inline(Config, Rule),
           ok = testSSLspecs:run_inline(Rule)
    end.

testNortel(Config) -> test(Config, fun testNortel/3).
testNortel(Config, Rule, Opts) ->
    asn1_test_lib:compile("Nortel", Config, [Rule|Opts]).

test_undecoded_rest(Config) -> test(Config, fun test_undecoded_rest/3).
test_undecoded_rest(Config, Rule, Opts) ->
    asn1_test_lib:compile("P-Record", Config, [Rule|Opts]),
    ok = test_undecoded_rest:test([], Config),
    asn1_test_lib:compile("P-Record", Config, [Rule,undec_rest|Opts]),
    case Rule of
        ber -> ok;
        _ -> test_undecoded_rest:test(undec_rest, Config)
    end.

test_inline(Config) ->
    test(Config, fun test_inline/3, [ber]).
test_inline(Config, Rule, Opts) ->
    case code:which(asn1ct) of
        cover_compiled ->
            {skip, "Not runnable when cover compiled"};
        _  ->
            test_inline:compile(Config, Opts),
            test_inline:main(Config, Rule),
            test_inline:inline1(Config, Rule, Opts),
            test_inline:performance2()
    end.

testTcapsystem(Config) ->
    test(Config, fun testTcapsystem/3, [ber]).
testTcapsystem(Config, Rule, Opts) ->
    testTcapsystem:compile(Config, [Rule|Opts]).

testNBAPsystem(Config) -> test(Config, fun testNBAPsystem/3, [per]).
testNBAPsystem(Config, Rule, Opts) ->
    testNBAPsystem:compile(Config, [Rule|Opts]),
    testNBAPsystem:test(Rule, Config).

test_compile_options(Config) ->
    case code:which(asn1ct) of
        cover_compiled ->
            {skip, "Not runnable when cover compiled"};
        _  ->
            ok = test_compile_options:wrong_path(Config),
            ok = test_compile_options:path(Config),
            ok = test_compile_options:noobj(Config),
            ok = test_compile_options:record_name_prefix(Config),
            ok = test_compile_options:verbose(Config),
            ok = test_compile_options:warnings_as_errors(Config)
    end.

testDoubleEllipses(Config) -> test(Config, fun testDoubleEllipses/3).
testDoubleEllipses(Config, Rule, Opts) ->
    asn1_test_lib:compile("DoubleEllipses", Config, [Rule|Opts]),
    testDoubleEllipses:main(Rule).

test_modified_x420(Config) ->
    Files = [filename:join(modified_x420, F) || F <- ["PKCS7",
                                                      "InformationFramework",
                                                      "AuthenticationFramework"]],
    asn1_test_lib:compile_all(Files, Config, [der]),
    test_modified_x420:test_io(Config).


testX420() ->
    [{timetrap,{minutes,90}}].
testX420(Config) ->
    test(Config, fun testX420/3, [ber]).
testX420(Config, Rule, Opts) ->
    testX420:compile(Rule, [der|Opts], Config),
    ok = testX420:ticket7759(Rule, Config),
    testX420:compile(Rule, Opts, Config).

test_x691(Config) ->
    test(Config, fun test_x691/3, [per, uper]).
test_x691(Config, Rule, Opts) ->
    Files = ["P-RecordA1", "P-RecordA2", "P-RecordA3"],
    asn1_test_lib:compile_all(Files, Config, [Rule|Opts]),
    test_x691:cases(Rule, case Rule of
                              uper -> unaligned;
                              _ -> aligned
                          end),
    asn1_test_lib:ticket_7708(Config, []),
    asn1_test_lib:ticket_7763(Config).

ticket_6143(Config) ->
    ok = test_compile_options:ticket_6143(Config).

testExtensionAdditionGroup(Config) ->
    %% FIXME problems with automatic tags [ber_bin], [ber_bin, optimize]
    test(Config, fun testExtensionAdditionGroup/3, [per, uper]).
testExtensionAdditionGroup(Config, Rule, Opts) ->
    asn1_test_lib:compile("Extension-Addition-Group", Config, [Rule|Opts]),
    asn1_test_lib:compile_erlang("extensionAdditionGroup", Config,
                                 [debug_info]),
    extensionAdditionGroup:run([Rule|Opts]),
    extensionAdditionGroup:run2([Rule|Opts]),
    asn1_test_lib:compile("EUTRA-RRC-Definitions", Config, [Rule, {record_name_prefix, "RRC-"}|Opts]),
    extensionAdditionGroup:run3([Rule|Opts]).

% parse_modules() ->
%   ["ImportsFrom"].

per_modules() ->
    [X || X <- test_modules()].

ber_modules() ->
    [X || X <- test_modules(),
          X =/= "CommonDataTypes",
          X =/= "DS-EquipmentUser-CommonFunctionOrig-TransmissionPath",
          X =/= "H323-MESSAGES",
          X =/= "H235-SECURITY-MESSAGES",
          X =/= "MULTIMEDIA-SYSTEM-CONTROL"].

test_modules() ->
    ["BitStr",
     "CAP",
     "CommonDataTypes",
     "Constraints",
     "ContextSwitchingTypes",
     "DS-EquipmentUser-CommonFunctionOrig-TransmissionPath",
     "Enum",
     "From",
     "H235-SECURITY-MESSAGES",
     "H323-MESSAGES",
     "Import",
     "Int",
     "MAP-commonDataTypes",
     "Null",
     "Octetstr",
     "One",
     "P-Record",
     "P",
     "Person",
     "PrimStrings",
     "Real",
     "XSeq",
     "XSeqOf",
     "XSet",
     "XSetOf",
     "String",
     "SwCDR",
     "Time",
     "SeqSetLib", % must be compiled before Seq and Set
     "Seq",
     "Set",
     "SetOf",
     "SeqOf",
     "Prim",
     "Cho",
     "Def",
     "Opt",
     "ELDAPv3",
     "LDAP"].

test_OTP_9688(Config) ->
    PrivDir = ?config(case_dir, Config),
    Data = "
OTP-9688 DEFINITIONS ::= BEGIN

 foo INTEGER ::= 1
 bar INTEGER ::= 42

 Baz ::= INTEGER {x-y-z1(foo), x-y-z2(bar)}
 Qux ::= SEQUENCE {flerpInfo SEQUENCE {x INTEGER (-10 | -9 | (0..4))} OPTIONAL}

END
",
    File = filename:join(PrivDir, "OTP-9688.asn1"),
    ok = file:write_file(File, Data),
    %% Does it compile with changes to asn1ct_check and asn1ct_gen_per_rt2ct?
    %% (see ticket)
    ok = asn1ct:compile(File, [{outdir, PrivDir}]).


timer_compile(Config, Rule, Opts) ->
    asn1_test_lib:compile_all(["H235-SECURITY-MESSAGES", "H323-MESSAGES"],
                              Config, [Rule|Opts]).

testTimer_ber(Config) ->
    timer_compile(Config,ber,[]),
    testTimer:go(Config,ber).

testTimer_per(Config) ->
    timer_compile(Config,per,[]),
    testTimer:go(Config,per).

testTimer_uper(Config) ->
    timer_compile(Config,uper,[]),
    {comment,_} = testTimer:go(Config,uper).

%% Test of multiple-line comment, OTP-8043
testComment(suite) -> [];
testComment(Config) ->
    asn1_test_lib:compile("Comment", Config, []),
    {ok,Enc} = asn1_wrapper:encode('Comment','Seq',{'Seq',12,true}),
    {ok,{'Seq',12,true}} = asn1_wrapper:decode('Comment','Seq',Enc),
    ok.

testName2Number(suite) -> [];
testName2Number(Config) ->
    N2NOptions = [{n2n,Type} || Type <- ['CauseMisc', 'CauseProtocol',
                                         'CauseRadioNetwork',
                                         'CauseTransport','CauseNas']],
    asn1_test_lib:compile("S1AP-IEs", Config, N2NOptions),

    0 = 'S1AP-IEs':name2num_CauseMisc('control-processing-overload'),
    'unknown-PLMN' = 'S1AP-IEs':num2name_CauseMisc(5),

    %% OTP-10144
    %% Test that n2n option generates name2num and num2name functions supporting
    %% values not within the extension root if the enumeration type has an
    %% extension marker.
    N2NOptionsExt = [{n2n, 'NoExt'}, {n2n, 'Ext'}, {n2n, 'Ext2'}],
    asn1_test_lib:compile("EnumN2N", Config, N2NOptionsExt),
    %% Previously, name2num and num2name was not generated if the type didn't
    %% have an extension marker:
    0 = 'EnumN2N':name2num_NoExt('blue'),
    2 = 'EnumN2N':name2num_NoExt('green'),
    blue = 'EnumN2N':num2name_NoExt(0),
    green = 'EnumN2N':num2name_NoExt(2),

    %% Test enumeration extension:
    7 = 'EnumN2N':name2num_Ext2('orange'),
    orange = 'EnumN2N':num2name_Ext2(7),
    %% 7 is not defined in Ext, only in Ext2.
    {asn1_enum, 7} = 'EnumN2N':num2name_Ext(7),
    7 = 'EnumN2N':name2num_Ext({asn1_enum, 7}),
    42 = 'EnumN2N':name2num_Ext2({asn1_enum, 42}),
    ok.

ticket_7407(Config) ->
    asn1_test_lib:compile("EUTRA-extract-7407", Config, [uper]),
    asn1_test_lib:ticket_7407_code(true),

    asn1_test_lib:compile("EUTRA-extract-7407", Config,
                          [uper, no_final_padding]),
    asn1_test_lib:ticket_7407_code(false).

smp(suite) -> [];
smp(Config)  ->
    case erlang:system_info(smp_support) of
        true ->
            NumOfProcs = erlang:system_info(schedulers),
            io:format("smp starting ~p workers\n",[NumOfProcs]),

            Msg = {initiatingMessage, testNBAPsystem:cell_setup_req_msg()},
            ok = testNBAPsystem:compile(Config, [per]),

            enc_dec(NumOfProcs,Msg,2),

            N = 10000,

            {Time1,ok} = timer:tc(?MODULE,enc_dec,[NumOfProcs,Msg, N]),
            {Time1S,ok} = timer:tc(?MODULE,enc_dec,[1, Msg, NumOfProcs * N]),

            ok = testNBAPsystem:compile(Config, [ber]),
            {Time3,ok} = timer:tc(?MODULE,enc_dec,[NumOfProcs,Msg, N]),

            {Time3S,ok} = timer:tc(?MODULE,enc_dec,[1, Msg, NumOfProcs * N]),

            {comment,lists:flatten(
                       io_lib:format(
                         "Encode/decode time parallell with ~p cores: ~p [microsecs]~n"
                         "Encode/decode time sequential: ~p [microsecs]",
                         [NumOfProcs,Time1+Time3,Time1S+Time3S]))};
        false ->
            {skipped,"No smp support"}
    end.

per_performance(Config) ->
    PrivDir = proplists:get_value(priv_dir, Config),
    NifDir = filename:join(PrivDir,"nif"),
    ErlDir = filename:join(PrivDir,"erl"),
    file:make_dir(NifDir),file:make_dir(ErlDir),

    Msg = {initiatingMessage, testNBAPsystem:cell_setup_req_msg()},
    ok = testNBAPsystem:compile([{priv_dir,NifDir}|Config], [per]),
    ok = testNBAPsystem:compile([{priv_dir,ErlDir}|Config], [per]),

    Modules = ['NBAP-CommonDataTypes',
               'NBAP-Constants',
               'NBAP-Containers',
               'NBAP-IEs',
               'NBAP-PDU-Contents',
               'NBAP-PDU-Discriptions'],


    PreNif = fun() ->
                     code:add_patha(NifDir),
                     lists:foreach(fun(M) ->
                                           code:purge(M),
                                           code:load_file(M)
                                   end,Modules)
             end,

    PreErl = fun() ->
                     code:add_patha(ErlDir),
                     lists:foreach(fun(M) ->
                                           code:purge(M),
                                           code:load_file(M)
                                   end,Modules)
             end,

    Func = fun() ->
                   element(1,timer:tc(
                               asn1_wrapper,encode,['NBAP-PDU-Discriptions',
                                                    'NBAP-PDU',
                                                    Msg]))
           end,

    nif_vs_erlang_performance({{{PreNif,Func},{PreErl,Func}},100000,32}).

ber_performance(Config) ->

    Msg = {initiatingMessage, testNBAPsystem:cell_setup_req_msg()},
    ok = testNBAPsystem:compile(Config, [ber]),


    BerFun = fun() ->
                     {ok,B} = asn1_wrapper:encode('NBAP-PDU-Discriptions',
                                                  'NBAP-PDU', Msg),
                     asn1_wrapper:decode(
                        'NBAP-PDU-Discriptions',
                        'NBAP-PDU',
                        B)
             end,
    nif_vs_erlang_performance({BerFun,100000,32}).

cert_pem_performance(Config) when is_list(Config) ->
    cert_pem_performance({100000, 32});
cert_pem_performance({N,S}) ->
    nif_vs_erlang_performance({fun pem_performance:cert_pem/0,N,S}).

dsa_pem_performance(Config) when is_list(Config) ->
    dsa_pem_performance({100000, 32});
dsa_pem_performance({N,S}) ->
    nif_vs_erlang_performance({fun pem_performance:dsa_pem/0,N,S}).


nif_vs_erlang_performance({{TC1,TC2},N,Sched}) ->
    random:seed({123,456,789}),
    io:format("Running a ~p sample with ~p max procs...~n~n",[N,Sched]),

    {True,False} = exec(TC1,TC2,Sched,N+1),

    io:format("~ndone!~n"),

    io:format("~n"),TStats = print_stats(strip(True,N div 20)),
    io:format("~n"),FStats = print_stats(strip(False,N div 20)),
    Str = io_lib:format("~nNifs are ~.3f% faster than erlang!~n",
                        [(element(2,FStats) - element(2,TStats)) /
                             element(2,FStats) * 100]),
    io:format(Str),
    {comment, lists:flatten(Str)};
nif_vs_erlang_performance({T,N,Sched}) ->
    PTC1 = fun() ->
                  application:set_env(asn1, nif_loadable, true)
           end,
    PTC2 = fun() ->
                  application:set_env(asn1, nif_loadable, false)
           end,
    TC = fun() ->
                 element(1,timer:tc(T))
         end,
    nif_vs_erlang_performance({{{PTC1,TC},{PTC2,TC}},N,Sched}).


print_stats(Data) ->
    Length = length(Data),
    Mean = lists:sum(Data) / Length,
    Variance = lists:foldl(fun(N,Acc) -> math:pow(N - Mean, 2)+Acc end, 0, Data),
    StdDev = math:sqrt(Variance / Length),
    Median = lists:nth(round(Length/2),Data),
    Min = lists:min(Data),
    Max = lists:max(Data),
    if Length < 20 ->
            io:format("Data: ~w~n",[Data]);
       true ->
            ok
    end,
    io:format("Length: ~p~nMean: ~p~nStdDev: ~p~nMedian: ~p~nMin: ~p~nMax: ~p~n",
              [Length,Mean,StdDev,Median,Min,Max]),
    {Length,Mean,StdDev,Median,Min,Max}.

collect(Acc) ->
    receive
        {Tag,Val} ->
            Prev = proplists:get_value(Tag,Acc,[]),
            collect(lists:keystore(Tag,1,Acc,{Tag,[Val|Prev]}))
    after 100 ->
            Acc
    end.

exec(One,Two,Max,N) ->
    exec(One,Two,Max,N,{[],[]}).
exec(_,_,_,1,{D1,D2}) ->
    {lists:flatten(D1),lists:flatten(D2)};
exec({PreOne,One} = O,{PreTwo,Two} = T,MaxProcs, N, {D1,D2}) ->
    Num = random:uniform(round(N/2)),
    if Num rem 3 == 0 ->
            timer:sleep(Num rem 1000);
       true ->
            ok
    end,
    Procs = random:uniform(MaxProcs),
    io:format("\tBatch: ~p items in ~p processes, ~p left~n",[Num,Procs,N-Num]),
    if Num rem 2 == 1 ->
            erlang:garbage_collect(),
            PreOne(),
            MoreOne = pexec(One, Num, Procs, []),
            erlang:garbage_collect(),
            PreTwo(),
            MoreTwo = pexec(Two, Num, Procs, []);
       true ->
            erlang:garbage_collect(),
            PreTwo(),
            MoreTwo = pexec(Two, Num, Procs, []),
            erlang:garbage_collect(),
            PreOne(),
            MoreOne = pexec(One, Num, Procs, [])
    end,
    exec(O,T,MaxProcs,N-Num,{[MoreOne|D1],
                             [MoreTwo|D2]}).

pexec(_Fun, _, 0, []) ->
    [];
pexec(Fun, _, 0, [{Ref,Pid}|Rest]) ->
    receive
        {data,D} ->
            [D|pexec(Fun,0,0,[{Ref,Pid}|Rest])];
        {'DOWN', Ref, process, Pid, normal} ->
            pexec(Fun, 0,0,Rest)
    end;
pexec(Fun, 0, 1, AccProcs) ->
    pexec(Fun, 0, 0, AccProcs);
pexec(Fun, N, 1, AccProcs) ->
    [Fun()|pexec(Fun, N - 1, 1, AccProcs)];
pexec(Fun, N, Procs, AccProcs) ->
    S = self(),
    Pid = spawn(fun() ->
                        S ! {data,pexec(Fun,N,1,[])}
                end),
    Ref = erlang:monitor(process, Pid),
    pexec(Fun, N, Procs - 1, [{Ref,Pid}|AccProcs]).

strip(Data,Num) ->
    {_,R} = lists:split(Num,lists:sort(Data)),
    element(2,lists:split(Num,lists:reverse(R))).

faster(A,B) ->
    (B - A)/B * 100.

enc_dec(1, Msg, N) ->
    worker_loop(N, Msg);
enc_dec(NumOfProcs,Msg, N) ->
    pforeach(fun(_) ->
                     worker_loop(N, Msg)
             end, [I || I <- lists:seq(1,NumOfProcs)]).

worker_loop(0, _Msg) ->
    ok;
worker_loop(N, Msg) ->
    {ok,B}=asn1_wrapper:encode('NBAP-PDU-Discriptions',
                                     'NBAP-PDU',
                                     Msg),
    {ok,_Msg}=asn1_wrapper:decode('NBAP-PDU-Discriptions',
                                        'NBAP-PDU',
                                        B),
    worker_loop(N - 1, Msg).


pforeach(Fun, List) ->
    pforeach(Fun, List, []).
pforeach(Fun, [], [{Pid,Ref}|Pids]) ->
    receive
        {'DOWN', Ref, process, Pid, normal} ->
            pforeach(Fun, [], Pids)
    end;
pforeach(Fun, [H|T], Pids) ->
    Pid = spawn(fun() -> Fun(H) end),
    Ref = erlang:monitor(process, Pid),
    pforeach(Fun, T, [{Pid, Ref}|Pids]);
pforeach(_Fun,[],[]) ->
    ok.

-record('InitiatingMessage',{procedureCode,criticality,value}).
-record('Iu-ReleaseCommand',{first,second}).

ticket7904(Config) ->
    asn1_test_lib:compile("RANAPextract1", Config, [per]),

    Val1 = #'InitiatingMessage'{procedureCode=1,
                                criticality=ignore,
                                value=#'Iu-ReleaseCommand'{
                                  first=13,
                                  second=true}},

    {ok,_} = 'RANAPextract1':encode('InitiatingMessage', Val1),
    {ok,_} = 'RANAPextract1':encode('InitiatingMessage', Val1).