From 5d33ec9021ff4fa8e3ffac01bdd0228871636edd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Thu, 10 Aug 2017 14:52:31 +0200
Subject: Fix broken handling of default values in extensions for PER

Default values have never worked in extension for PER.

Note that for default values in the root part of SEQUENCE,
giving a value equal to the DEFAULT value, will result in
the same encoding as if asn1_DEFAULT was given. However,
that behavior is not promised by the documentation. The
documentation says that asn1_DEFAULT should be used for
default values. For DEFAULT in extensions, only implement
what the documentation promises and nothing more.

ERIERL-60
---
 lib/asn1/src/asn1ct_constructed_per.erl            |  6 ++-
 lib/asn1/src/asn1rtt_per_common.erl                |  1 +
 lib/asn1/test/Makefile                             |  1 +
 lib/asn1/test/asn1_SUITE.erl                       |  7 +++
 .../test/asn1_SUITE_data/ExtensionDefault.asn1     | 12 +++++
 lib/asn1/test/testExtensionDefault.erl             | 53 ++++++++++++++++++++++
 6 files changed, 78 insertions(+), 2 deletions(-)
 create mode 100644 lib/asn1/test/asn1_SUITE_data/ExtensionDefault.asn1
 create mode 100644 lib/asn1/test/testExtensionDefault.erl

diff --git a/lib/asn1/src/asn1ct_constructed_per.erl b/lib/asn1/src/asn1ct_constructed_per.erl
index 3f1be4febb..aff383479b 100644
--- a/lib/asn1/src/asn1ct_constructed_per.erl
+++ b/lib/asn1/src/asn1ct_constructed_per.erl
@@ -985,9 +985,11 @@ gen_enc_components_call1(Gen, TopType, [C|Rest], DynamicEnc, Ext) ->
 		   Imm1;
 	       'OPTIONAL' ->
 		   enc_absent(Gen, Element, [asn1_NOVALUE], Imm1);
-	       {'DEFAULT',Def} ->
+	       {'DEFAULT',Def} when Ext =:= noext ->
 		   DefValues = def_values(Type, Def),
-		   enc_absent(Gen, Element, DefValues, Imm1)
+		   enc_absent(Gen, Element, DefValues, Imm1);
+               {'DEFAULT',_} ->
+		   enc_absent(Gen, Element, [asn1_DEFAULT], Imm1)
 	   end,
     Imm = case Imm2 of
 	      [] -> [];
diff --git a/lib/asn1/src/asn1rtt_per_common.erl b/lib/asn1/src/asn1rtt_per_common.erl
index 2ecc9e4bc7..5b5f47dfee 100644
--- a/lib/asn1/src/asn1rtt_per_common.erl
+++ b/lib/asn1/src/asn1rtt_per_common.erl
@@ -542,6 +542,7 @@ extension_bitmap(_Val, Pos, Limit, Acc) when Pos >= Limit ->
 extension_bitmap(Val, Pos, Limit, Acc) ->
     Bit = case element(Pos, Val) of
 	      asn1_NOVALUE -> 0;
+	      asn1_DEFAULT -> 0;
 	      _ -> 1
 	  end,
     extension_bitmap(Val, Pos+1, Limit, (Acc bsl 1) bor Bit).
diff --git a/lib/asn1/test/Makefile b/lib/asn1/test/Makefile
index f4041fa89b..c38d1c6ebd 100644
--- a/lib/asn1/test/Makefile
+++ b/lib/asn1/test/Makefile
@@ -43,6 +43,7 @@ MODULES= \
 	testChoTypeRefSet \
 	testConstraints \
 	testDef \
+	testExtensionDefault \
 	testOpt \
 	testSeqDefault \
 	testSeqExtension \
diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl
index 5fe6945ff2..69f226bcc0 100644
--- a/lib/asn1/test/asn1_SUITE.erl
+++ b/lib/asn1/test/asn1_SUITE.erl
@@ -147,6 +147,7 @@ groups() ->
        testImport,
        testDER,
        testDEFAULT,
+       testExtensionDefault,
        testMvrasn6,
        testContextSwitchingTypes,
        testOpenTypeImplicitTag,
@@ -444,6 +445,12 @@ testDEFAULT(Config, Rule, Opts) ->
     testDef:main(Rule),
     testSeqSetDefaultVal:main(Rule, Opts).
 
+testExtensionDefault(Config) ->
+    test(Config, fun testExtensionDefault/3).
+testExtensionDefault(Config, Rule, Opts) ->
+    asn1_test_lib:compile_all(["ExtensionDefault"], Config, [Rule|Opts]),
+    testExtensionDefault:main(Rule).
+
 testMaps(Config) ->
     test(Config, fun testMaps/3,
          [{ber,[maps,no_ok_wrapper]},
diff --git a/lib/asn1/test/asn1_SUITE_data/ExtensionDefault.asn1 b/lib/asn1/test/asn1_SUITE_data/ExtensionDefault.asn1
new file mode 100644
index 0000000000..67d9cb6312
--- /dev/null
+++ b/lib/asn1/test/asn1_SUITE_data/ExtensionDefault.asn1
@@ -0,0 +1,12 @@
+ExtensionDefault DEFINITIONS AUTOMATIC TAGS ::=
+
+BEGIN
+
+Message ::= SEQUENCE {
+    id INTEGER (0..5),
+    ...,
+    priority Priority DEFAULT low
+}
+Priority ::= ENUMERATED { low(0), high(1), ... }
+
+END
diff --git a/lib/asn1/test/testExtensionDefault.erl b/lib/asn1/test/testExtensionDefault.erl
new file mode 100644
index 0000000000..cc50fa95b8
--- /dev/null
+++ b/lib/asn1/test/testExtensionDefault.erl
@@ -0,0 +1,53 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%%     http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+-module(testExtensionDefault).
+
+-export([main/1]).
+
+main(_Erule) ->
+    roundtrip('Message', {'Message',1,low}),    %Will be explicitly encoded.
+    roundtrip('Message', {'Message',1,high}),
+    roundtrip('Message', {'Message',1,asn1_DEFAULT}, {'Message',1,low}),
+
+    map_roundtrip('Message', #{id=>1,priority=>low}), %Will be explicitly encoded.
+    map_roundtrip('Message', #{id=>1,priority=>high}),
+    map_roundtrip('Message', #{id=>1}, #{id=>1,priority=>low}),
+    ok.
+
+roundtrip(Type, Value) ->
+    asn1_test_lib:roundtrip('ExtensionDefault', Type, Value).
+
+roundtrip(Type, Value, Expected) ->
+    %% asn1_test_lib:roundtrip/3 will invoke map_roundtrip/3, which will
+    %% not work in this case. Therefore, implement the roundtrip ourselves.
+    M = 'ExtensionDefault',
+    {ok,Enc} = M:encode(Type, Value),
+    {ok,Expected} = M:decode(Type, Enc),
+    ok.
+
+map_roundtrip(Type, Value) ->
+    map_roundtrip(Type, Value, Value).
+
+map_roundtrip(Type, Value, Expected) ->
+    M = 'maps_ExtensionDefault',
+    Enc = M:encode(Type, Value),
+    Expected = M:decode(Type, Enc),
+    ok.
-- 
cgit v1.2.3