File 4881-stdlib-add-binary-encode_hex-2.patch of Package erlang

From a30a54d4ec5e18501868995bb965242d5d2f5072 Mon Sep 17 00:00:00 2001
From: Gilbert <gilbertwong96@icloud.com>
Date: Wed, 14 Sep 2022 11:55:30 +0800
Subject: [PATCH] stdlib: add `binary:encode_hex/2`

The `binary` module only exposes `encode_hex/1` which encodes binary to a
 hex-encoded binary. The output as the number in hexadecimal, with a
 through f is in the upper case by default. This change allows the user to
 decide to use upper case or lower case.
---
 lib/stdlib/doc/src/binary.xml                 |  20 +++-
 lib/stdlib/src/binary.erl                     | 108 ++++++++++++------
 lib/stdlib/src/erl_stdlib_errors.erl          |   8 ++
 lib/stdlib/test/Makefile                      |   1 +
 lib/stdlib/test/binary_module_SUITE.erl       |  20 +++-
 .../test/binary_property_test_SUITE.erl       |  35 ++++++
 lib/stdlib/test/property_test/binary_prop.erl |  37 ++++++
 7 files changed, 184 insertions(+), 45 deletions(-)
 create mode 100644 lib/stdlib/test/binary_property_test_SUITE.erl
 create mode 100644 lib/stdlib/test/property_test/binary_prop.erl

diff --git a/lib/stdlib/doc/src/binary.xml b/lib/stdlib/doc/src/binary.xml
index 220caaaaee..44137adafe 100644
--- a/lib/stdlib/doc/src/binary.xml
+++ b/lib/stdlib/doc/src/binary.xml
@@ -244,15 +244,23 @@
 
     <func>
       <name name="encode_hex" arity="1" since="OTP 24.0"/>
-      <fsummary>Encodes a binary into a hex encoded binary.</fsummary>
+      <name name="encode_hex" arity="2" since="OTP 25.3"/>
+      <fsummary>Encodes a binary into a hex encoded binary with specified case</fsummary>
       <desc>
-      <p>Encodes a binary into a hex encoded binary.</p>
+        <p>Encodes a binary into a hex encoded binary using the specified case for the hexadecimal digits "a" to "f".</p>
+        <p>The default case is <c>uppercase</c>.</p>
+        <p><em>Example:</em></p>
 
-      <p><em>Example:</em></p>
-
-      <code>
+        <code>
 1> binary:encode_hex(&lt;&lt;"f"&gt;&gt;).
-&lt;&lt;"66"&gt;&gt;</code>
+&lt;&lt;"66"&gt;&gt;
+2> binary:encode_hex(&lt;&lt;"/"&gt;&gt;).
+&lt;&lt;"2F"&gt;&gt;
+3> binary:encode_hex(&lt;&lt;"/"&gt;&gt;, lowercase).
+&lt;&lt;"2f"&gt;&gt;
+4> binary:encode_hex(&lt;&lt;"/"&gt;&gt;, uppercase).
+&lt;&lt;"2F"&gt;&gt;
+        </code>
       </desc>
     </func>
 
diff --git a/lib/stdlib/src/binary.erl b/lib/stdlib/src/binary.erl
index f3e2f54215..85e283e0df 100644
--- a/lib/stdlib/src/binary.erl
+++ b/lib/stdlib/src/binary.erl
@@ -20,8 +20,8 @@
 -module(binary).
 %%
 %% Implemented in this module:
--export([replace/3,replace/4,
-         encode_hex/1, decode_hex/1]).
+-export([replace/3, replace/4,
+         encode_hex/1, encode_hex/2, decode_hex/1]).
 
 -export_type([cp/0]).
 
@@ -365,48 +365,80 @@ get_opts_replace(_,_) ->
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %% Hex encoding functions
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--define(HEX(X), (hex(X)):16).
--compile({inline,[hex/1]}).
+-define(HEX(X, Off), (hex(X, OffSet)):16).
+-compile({inline, [hex/2]}).
 -spec encode_hex(Bin) -> Bin2 when
       Bin :: binary(),
       Bin2 :: <<_:_*16>>.
-encode_hex(Data) when byte_size(Data) rem 8 =:= 0 ->
-    << <<?HEX(A),?HEX(B),?HEX(C),?HEX(D),?HEX(E),?HEX(F),?HEX(G),?HEX(H)>> || <<A,B,C,D,E,F,G,H>> <= Data >>;
-encode_hex(Data) when byte_size(Data) rem 7 =:= 0 ->
-    << <<?HEX(A),?HEX(B),?HEX(C),?HEX(D),?HEX(E),?HEX(F),?HEX(G)>> || <<A,B,C,D,E,F,G>> <= Data >>;
-encode_hex(Data) when byte_size(Data) rem 6 =:= 0 ->
-    << <<?HEX(A),?HEX(B),?HEX(C),?HEX(D),?HEX(E),?HEX(F)>> || <<A,B,C,D,E,F>> <= Data >>;
-encode_hex(Data) when byte_size(Data) rem 5 =:= 0 ->
-    << <<?HEX(A),?HEX(B),?HEX(C),?HEX(D),?HEX(E)>> || <<A,B,C,D,E>> <= Data >>;
-encode_hex(Data) when byte_size(Data) rem 4 =:= 0 ->
-    << <<?HEX(A),?HEX(B),?HEX(C),?HEX(D)>> || <<A,B,C,D>> <= Data >>;
-encode_hex(Data) when byte_size(Data) rem 3 =:= 0 ->
-    << <<?HEX(A),?HEX(B),?HEX(C)>> || <<A,B,C>> <= Data >>;
-encode_hex(Data) when byte_size(Data) rem 2 =:= 0 ->
-    << <<?HEX(A),?HEX(B)>> || <<A,B>> <= Data >>;
-encode_hex(Data) when is_binary(Data) ->
-    << <<?HEX(N)>> || <<N>> <= Data >>;
 encode_hex(Bin) ->
-    badarg_with_info([Bin]).
+    encode_hex(Bin, uppercase).
 
-hex(X) ->
+-spec encode_hex(Bin, Case) -> Bin2 when
+      Bin :: binary(),
+      Case :: lowercase | uppercase,
+      Bin2 :: <<_:_*16>>.
+encode_hex(Bin, uppercase) when is_binary(Bin) ->
+    encode_hex1(Bin, 1);
+encode_hex(Bin, lowercase) when is_binary(Bin) ->
+    encode_hex1(Bin, 257);
+encode_hex(Bin, Case) ->
+    error_with_info(badarg, [Bin, Case]).
+
+-spec encode_hex1(binary(), 1 | 257) -> <<_:_*16>>.
+encode_hex1(Data, OffSet) when byte_size(Data) rem 8 =:= 0 ->
+    << <<?HEX(A, OffSet),?HEX(B, OffSet),?HEX(C, OffSet),?HEX(D, OffSet),?HEX(E, OffSet),?HEX(F, OffSet),?HEX(G, OffSet),?HEX(H, OffSet)>> || <<A,B,C,D,E,F,G,H>> <= Data >>;
+encode_hex1(Data, OffSet) when byte_size(Data) rem 7 =:= 0 ->
+    << <<?HEX(A, OffSet),?HEX(B, OffSet),?HEX(C, OffSet),?HEX(D, OffSet),?HEX(E, OffSet),?HEX(F, OffSet),?HEX(G, OffSet)>> || <<A,B,C,D,E,F,G>> <= Data >>;
+encode_hex1(Data, OffSet) when byte_size(Data) rem 6 =:= 0 ->
+    << <<?HEX(A, OffSet),?HEX(B, OffSet),?HEX(C, OffSet),?HEX(D, OffSet),?HEX(E, OffSet),?HEX(F, OffSet)>> || <<A,B,C,D,E,F>> <= Data >>;
+encode_hex1(Data, OffSet) when byte_size(Data) rem 5 =:= 0 ->
+    << <<?HEX(A, OffSet),?HEX(B, OffSet),?HEX(C, OffSet),?HEX(D, OffSet),?HEX(E, OffSet)>> || <<A,B,C,D,E>> <= Data >>;
+encode_hex1(Data, OffSet) when byte_size(Data) rem 4 =:= 0 ->
+    << <<?HEX(A, OffSet),?HEX(B, OffSet),?HEX(C, OffSet),?HEX(D, OffSet)>> || <<A,B,C,D>> <= Data >>;
+encode_hex1(Data, OffSet) when byte_size(Data) rem 3 =:= 0 ->
+    << <<?HEX(A, OffSet),?HEX(B, OffSet),?HEX(C, OffSet)>> || <<A,B,C>> <= Data >>;
+encode_hex1(Data, OffSet) when byte_size(Data) rem 2 =:= 0 ->
+    << <<?HEX(A, OffSet),?HEX(B, OffSet)>> || <<A,B>> <= Data >>;
+encode_hex1(Data, OffSet) when is_binary(Data) ->
+    << <<?HEX(N, OffSet)>> || <<N>> <= Data >>.
+
+hex(X, Offset) ->
     element(
-      X+1, {16#3030, 16#3031, 16#3032, 16#3033, 16#3034, 16#3035, 16#3036, 16#3037, 16#3038, 16#3039, 16#3041, 16#3042, 16#3043, 16#3044, 16#3045, 16#3046,
-            16#3130, 16#3131, 16#3132, 16#3133, 16#3134, 16#3135, 16#3136, 16#3137, 16#3138, 16#3139, 16#3141, 16#3142, 16#3143, 16#3144, 16#3145, 16#3146,
-            16#3230, 16#3231, 16#3232, 16#3233, 16#3234, 16#3235, 16#3236, 16#3237, 16#3238, 16#3239, 16#3241, 16#3242, 16#3243, 16#3244, 16#3245, 16#3246,
-            16#3330, 16#3331, 16#3332, 16#3333, 16#3334, 16#3335, 16#3336, 16#3337, 16#3338, 16#3339, 16#3341, 16#3342, 16#3343, 16#3344, 16#3345, 16#3346,
-            16#3430, 16#3431, 16#3432, 16#3433, 16#3434, 16#3435, 16#3436, 16#3437, 16#3438, 16#3439, 16#3441, 16#3442, 16#3443, 16#3444, 16#3445, 16#3446,
-            16#3530, 16#3531, 16#3532, 16#3533, 16#3534, 16#3535, 16#3536, 16#3537, 16#3538, 16#3539, 16#3541, 16#3542, 16#3543, 16#3544, 16#3545, 16#3546,
-            16#3630, 16#3631, 16#3632, 16#3633, 16#3634, 16#3635, 16#3636, 16#3637, 16#3638, 16#3639, 16#3641, 16#3642, 16#3643, 16#3644, 16#3645, 16#3646,
-            16#3730, 16#3731, 16#3732, 16#3733, 16#3734, 16#3735, 16#3736, 16#3737, 16#3738, 16#3739, 16#3741, 16#3742, 16#3743, 16#3744, 16#3745, 16#3746,
-            16#3830, 16#3831, 16#3832, 16#3833, 16#3834, 16#3835, 16#3836, 16#3837, 16#3838, 16#3839, 16#3841, 16#3842, 16#3843, 16#3844, 16#3845, 16#3846,
-            16#3930, 16#3931, 16#3932, 16#3933, 16#3934, 16#3935, 16#3936, 16#3937, 16#3938, 16#3939, 16#3941, 16#3942, 16#3943, 16#3944, 16#3945, 16#3946,
-            16#4130, 16#4131, 16#4132, 16#4133, 16#4134, 16#4135, 16#4136, 16#4137, 16#4138, 16#4139, 16#4141, 16#4142, 16#4143, 16#4144, 16#4145, 16#4146,
-            16#4230, 16#4231, 16#4232, 16#4233, 16#4234, 16#4235, 16#4236, 16#4237, 16#4238, 16#4239, 16#4241, 16#4242, 16#4243, 16#4244, 16#4245, 16#4246,
-            16#4330, 16#4331, 16#4332, 16#4333, 16#4334, 16#4335, 16#4336, 16#4337, 16#4338, 16#4339, 16#4341, 16#4342, 16#4343, 16#4344, 16#4345, 16#4346,
-            16#4430, 16#4431, 16#4432, 16#4433, 16#4434, 16#4435, 16#4436, 16#4437, 16#4438, 16#4439, 16#4441, 16#4442, 16#4443, 16#4444, 16#4445, 16#4446,
-            16#4530, 16#4531, 16#4532, 16#4533, 16#4534, 16#4535, 16#4536, 16#4537, 16#4538, 16#4539, 16#4541, 16#4542, 16#4543, 16#4544, 16#4545, 16#4546,
-            16#4630, 16#4631, 16#4632, 16#4633, 16#4634, 16#4635, 16#4636, 16#4637, 16#4638, 16#4639, 16#4641, 16#4642, 16#4643, 16#4644, 16#4645, 16#4646}).
+      X + Offset, {
+                   %% Used for Uppercase
+                   16#3030, 16#3031, 16#3032, 16#3033, 16#3034, 16#3035, 16#3036, 16#3037, 16#3038, 16#3039, 16#3041, 16#3042, 16#3043, 16#3044, 16#3045, 16#3046,
+                   16#3130, 16#3131, 16#3132, 16#3133, 16#3134, 16#3135, 16#3136, 16#3137, 16#3138, 16#3139, 16#3141, 16#3142, 16#3143, 16#3144, 16#3145, 16#3146,
+                   16#3230, 16#3231, 16#3232, 16#3233, 16#3234, 16#3235, 16#3236, 16#3237, 16#3238, 16#3239, 16#3241, 16#3242, 16#3243, 16#3244, 16#3245, 16#3246,
+                   16#3330, 16#3331, 16#3332, 16#3333, 16#3334, 16#3335, 16#3336, 16#3337, 16#3338, 16#3339, 16#3341, 16#3342, 16#3343, 16#3344, 16#3345, 16#3346,
+                   16#3430, 16#3431, 16#3432, 16#3433, 16#3434, 16#3435, 16#3436, 16#3437, 16#3438, 16#3439, 16#3441, 16#3442, 16#3443, 16#3444, 16#3445, 16#3446,
+                   16#3530, 16#3531, 16#3532, 16#3533, 16#3534, 16#3535, 16#3536, 16#3537, 16#3538, 16#3539, 16#3541, 16#3542, 16#3543, 16#3544, 16#3545, 16#3546,
+                   16#3630, 16#3631, 16#3632, 16#3633, 16#3634, 16#3635, 16#3636, 16#3637, 16#3638, 16#3639, 16#3641, 16#3642, 16#3643, 16#3644, 16#3645, 16#3646,
+                   16#3730, 16#3731, 16#3732, 16#3733, 16#3734, 16#3735, 16#3736, 16#3737, 16#3738, 16#3739, 16#3741, 16#3742, 16#3743, 16#3744, 16#3745, 16#3746,
+                   16#3830, 16#3831, 16#3832, 16#3833, 16#3834, 16#3835, 16#3836, 16#3837, 16#3838, 16#3839, 16#3841, 16#3842, 16#3843, 16#3844, 16#3845, 16#3846,
+                   16#3930, 16#3931, 16#3932, 16#3933, 16#3934, 16#3935, 16#3936, 16#3937, 16#3938, 16#3939, 16#3941, 16#3942, 16#3943, 16#3944, 16#3945, 16#3946,
+                   16#4130, 16#4131, 16#4132, 16#4133, 16#4134, 16#4135, 16#4136, 16#4137, 16#4138, 16#4139, 16#4141, 16#4142, 16#4143, 16#4144, 16#4145, 16#4146,
+                   16#4230, 16#4231, 16#4232, 16#4233, 16#4234, 16#4235, 16#4236, 16#4237, 16#4238, 16#4239, 16#4241, 16#4242, 16#4243, 16#4244, 16#4245, 16#4246,
+                   16#4330, 16#4331, 16#4332, 16#4333, 16#4334, 16#4335, 16#4336, 16#4337, 16#4338, 16#4339, 16#4341, 16#4342, 16#4343, 16#4344, 16#4345, 16#4346,
+                   16#4430, 16#4431, 16#4432, 16#4433, 16#4434, 16#4435, 16#4436, 16#4437, 16#4438, 16#4439, 16#4441, 16#4442, 16#4443, 16#4444, 16#4445, 16#4446,
+                   16#4530, 16#4531, 16#4532, 16#4533, 16#4534, 16#4535, 16#4536, 16#4537, 16#4538, 16#4539, 16#4541, 16#4542, 16#4543, 16#4544, 16#4545, 16#4546,
+                   16#4630, 16#4631, 16#4632, 16#4633, 16#4634, 16#4635, 16#4636, 16#4637, 16#4638, 16#4639, 16#4641, 16#4642, 16#4643, 16#4644, 16#4645, 16#4646,
+                   %% Used for Lowercase 
+                   16#3030, 16#3031, 16#3032, 16#3033, 16#3034, 16#3035, 16#3036, 16#3037, 16#3038, 16#3039, 16#3061, 16#3062, 16#3063, 16#3064, 16#3065, 16#3066,
+                   16#3130, 16#3131, 16#3132, 16#3133, 16#3134, 16#3135, 16#3136, 16#3137, 16#3138, 16#3139, 16#3161, 16#3162, 16#3163, 16#3164, 16#3165, 16#3166,
+                   16#3230, 16#3231, 16#3232, 16#3233, 16#3234, 16#3235, 16#3236, 16#3237, 16#3238, 16#3239, 16#3261, 16#3262, 16#3263, 16#3264, 16#3265, 16#3266,
+                   16#3330, 16#3331, 16#3332, 16#3333, 16#3334, 16#3335, 16#3336, 16#3337, 16#3338, 16#3339, 16#3361, 16#3362, 16#3363, 16#3364, 16#3365, 16#3366,
+                   16#3430, 16#3431, 16#3432, 16#3433, 16#3434, 16#3435, 16#3436, 16#3437, 16#3438, 16#3439, 16#3461, 16#3462, 16#3463, 16#3464, 16#3465, 16#3466,
+                   16#3530, 16#3531, 16#3532, 16#3533, 16#3534, 16#3535, 16#3536, 16#3537, 16#3538, 16#3539, 16#3561, 16#3562, 16#3563, 16#3564, 16#3565, 16#3566,
+                   16#3630, 16#3631, 16#3632, 16#3633, 16#3634, 16#3635, 16#3636, 16#3637, 16#3638, 16#3639, 16#3661, 16#3662, 16#3663, 16#3664, 16#3665, 16#3666,
+                   16#3730, 16#3731, 16#3732, 16#3733, 16#3734, 16#3735, 16#3736, 16#3737, 16#3738, 16#3739, 16#3761, 16#3762, 16#3763, 16#3764, 16#3765, 16#3766,
+                   16#3830, 16#3831, 16#3832, 16#3833, 16#3834, 16#3835, 16#3836, 16#3837, 16#3838, 16#3839, 16#3861, 16#3862, 16#3863, 16#3864, 16#3865, 16#3866,
+                   16#3930, 16#3931, 16#3932, 16#3933, 16#3934, 16#3935, 16#3936, 16#3937, 16#3938, 16#3939, 16#3961, 16#3962, 16#3963, 16#3964, 16#3965, 16#3966,
+                   16#6130, 16#6131, 16#6132, 16#6133, 16#6134, 16#6135, 16#6136, 16#6137, 16#6138, 16#6139, 16#6161, 16#6162, 16#6163, 16#6164, 16#6165, 16#6166,
+                   16#6230, 16#6231, 16#6232, 16#6233, 16#6234, 16#6235, 16#6236, 16#6237, 16#6238, 16#6239, 16#6261, 16#6262, 16#6263, 16#6264, 16#6265, 16#6266,
+                   16#6330, 16#6331, 16#6332, 16#6333, 16#6334, 16#6335, 16#6336, 16#6337, 16#6338, 16#6339, 16#6361, 16#6362, 16#6363, 16#6364, 16#6365, 16#6366,
+                   16#6430, 16#6431, 16#6432, 16#6433, 16#6434, 16#6435, 16#6436, 16#6437, 16#6438, 16#6439, 16#6461, 16#6462, 16#6463, 16#6464, 16#6465, 16#6466,
+                   16#6530, 16#6531, 16#6532, 16#6533, 16#6534, 16#6535, 16#6536, 16#6537, 16#6538, 16#6539, 16#6561, 16#6562, 16#6563, 16#6564, 16#6565, 16#6566,
+                   16#6630, 16#6631, 16#6632, 16#6633, 16#6634, 16#6635, 16#6636, 16#6637, 16#6638, 16#6639, 16#6661, 16#6662, 16#6663, 16#6664, 16#6665, 16#6666}).
 
 -spec decode_hex(Bin) -> Bin2 when
       Bin :: <<_:_*16>>,
diff --git a/lib/stdlib/src/erl_stdlib_errors.erl b/lib/stdlib/src/erl_stdlib_errors.erl
index 36af07e1ac..b0daca1838 100644
--- a/lib/stdlib/src/erl_stdlib_errors.erl
+++ b/lib/stdlib/src/erl_stdlib_errors.erl
@@ -73,6 +73,8 @@ format_binary_error(encode_unsigned, [Subject, Endianness], _) ->
     [must_be_non_neg_integer(Subject), must_be_endianness(Endianness)];
 format_binary_error(encode_hex, [Subject], _) ->
     [must_be_binary(Subject)];
+format_binary_error(encode_hex, [Subject, Case], _) ->
+    [must_be_binary(Subject), must_be_hex_case(Case)];
 format_binary_error(decode_hex, [Subject], _) ->
     if
         is_binary(Subject), byte_size(Subject) rem 2 == 1 ->
@@ -916,6 +918,10 @@ must_be_binary(Bin, Error) when is_binary(Bin) -> Error;
 must_be_binary(Bin, _Error) when is_bitstring(Bin) -> bitstring;
 must_be_binary(_, _) -> not_binary.
 
+must_be_hex_case(uppercase) -> [];
+must_be_hex_case(lowercase) -> [];
+must_be_hex_case(_) -> bad_hex_case.
+
 must_be_endianness(little) -> [];
 must_be_endianness(big) -> [];
 must_be_endianness(_) -> bad_endianness.
@@ -1072,6 +1078,8 @@ expand_error(not_atom) ->
     <<"not an atom">>;
 expand_error(not_binary) ->
     <<"not a binary">>;
+expand_error(bad_hex_case) ->
+    <<"not uppercase or lowercase">>;
 expand_error(not_compiled_regexp) ->
     <<"not a compiled regular expression">>;
 expand_error(not_iodata) ->
diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile
index a12b2213ec..5d4ffcf86e 100644
--- a/lib/stdlib/test/Makefile
+++ b/lib/stdlib/test/Makefile
@@ -11,6 +11,7 @@ MODULES= \
 	base64_property_test_SUITE \
 	beam_lib_SUITE \
 	binary_module_SUITE \
+	binary_property_test_SUITE \
 	binref \
 	c_SUITE \
 	calendar_SUITE \
diff --git a/lib/stdlib/test/binary_module_SUITE.erl b/lib/stdlib/test/binary_module_SUITE.erl
index 99f3566eab..b32f974c66 100644
--- a/lib/stdlib/test/binary_module_SUITE.erl
+++ b/lib/stdlib/test/binary_module_SUITE.erl
@@ -1462,7 +1462,8 @@ error_info(_Config) ->
          {split, [<<1,2,3>>, {bm,make_ref()}, []]},
          {split, [<<1,2,3>>, <<"2">>, [bad_option]]},
 
-         {encode_hex, [{no,a,binary}]},
+         {encode_hex, [{no,a,binary}], [allow_rename]},
+         {encode_hex, [<<"foobar">>, othercase]},
          {decode_hex, [{no,a,binary}]},
          {decode_hex, [<<"000">>],[allow_rename]},
          {decode_hex, [<<"GG">>],[allow_rename]}
@@ -1479,6 +1480,23 @@ hex_encoding(Config) when is_list(Config) ->
     <<"666F6F6261">> = binary:encode_hex(<<"fooba">>),
     <<"666F6F626172">> = binary:encode_hex(<<"foobar">>),
 
+
+    <<>> = binary:encode_hex(<<>>, uppercase),
+    <<"66">> = binary:encode_hex(<<"f">>, uppercase),
+    <<"666F">> = binary:encode_hex(<<"fo">>, uppercase),
+    <<"666F6F">> = binary:encode_hex(<<"foo">>, uppercase),
+    <<"666F6F62">> = binary:encode_hex(<<"foob">>, uppercase),
+    <<"666F6F6261">> = binary:encode_hex(<<"fooba">>, uppercase),
+    <<"666F6F626172">> = binary:encode_hex(<<"foobar">>, uppercase),
+
+    <<>> = binary:encode_hex(<<>>, lowercase),
+    <<"66">> = binary:encode_hex(<<"f">>, lowercase),
+    <<"666f">> = binary:encode_hex(<<"fo">>, lowercase),
+    <<"666f6f">> = binary:encode_hex(<<"foo">>, lowercase),
+    <<"666f6f62">> = binary:encode_hex(<<"foob">>, lowercase),
+    <<"666f6f6261">> = binary:encode_hex(<<"fooba">>, lowercase),
+    <<"666f6f626172">> = binary:encode_hex(<<"foobar">>, lowercase),
+
     <<>> = binary:decode_hex(<<>>),
     <<"f">> = binary:decode_hex(<<"66">>),
     <<"fo">> = binary:decode_hex(<<"666F">>),
diff --git a/lib/stdlib/test/binary_property_test_SUITE.erl b/lib/stdlib/test/binary_property_test_SUITE.erl
new file mode 100644
index 0000000000..4ec1ba67ab
--- /dev/null
+++ b/lib/stdlib/test/binary_property_test_SUITE.erl
@@ -0,0 +1,35 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2022. 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(binary_property_test_SUITE).
+
+-compile([export_all, nowarn_export_all]).
+
+all() ->
+    [encode_hex_case].
+
+init_per_suite(Config) ->
+    ct_property_test:init_per_suite(Config).
+
+end_per_suite(Config) ->
+    Config.
+
+encode_hex_case(Config) ->
+    ct_property_test:quickcheck(binary_prop:prop_hex_encode_2(), Config).
+
diff --git a/lib/stdlib/test/property_test/binary_prop.erl b/lib/stdlib/test/property_test/binary_prop.erl
new file mode 100644
index 0000000000..00efa77b8c
--- /dev/null
+++ b/lib/stdlib/test/property_test/binary_prop.erl
@@ -0,0 +1,37 @@
+-module(binary_prop).
+
+-export([prop_hex_encode_2/0]).
+
+-compile([export_all, nowarn_export_all]).
+
+-include_lib("common_test/include/ct_property_test.hrl").
+
+prop_hex_encode_2() ->
+    ?FORALL(Data, data(),
+        begin
+            UpperHex = binary:encode_hex(Data, uppercase),
+            LowerHex = binary:encode_hex(Data, lowercase),
+            binary:decode_hex(LowerHex) =:= Data andalso
+            binary:decode_hex(UpperHex) =:= Data andalso
+            check_hex_encoded(Data, UpperHex, LowerHex)
+        end).
+
+data() ->
+    ?SIZED(Size, resize(Size * 2, binary())).
+
+
+%% @doc Credit to the <a href="https://github.com/erlang/otp/pull/6297#discussion_r1034771450">comment</a> of @Maria-12648430
+-spec check_hex_encoded(Data :: binary(), UpperHex :: binary(), LoweHex :: binary()) -> boolean().
+check_hex_encoded(<<I1:4, I2:4, Ins/binary>>, <<U1:8, U2:8, UCs/binary>>, <<L1:8, L2:8, LCs/binary>>) ->
+    check_hex_chars_match(I1, U1, L1) andalso
+    check_hex_chars_match(I2, U2, L2) andalso
+    check_hex_encoded(Ins, UCs, LCs);
+check_hex_encoded(<<>>, <<>>, <<>>) ->
+    true;
+check_hex_encoded(_, _, _) ->
+    false.
+
+check_hex_chars_match(X, U, L) when X < 10 ->
+    (U =:= $0 + X) andalso (L =:= $0 + X);
+check_hex_chars_match(X, U, L) ->
+    (U =:= $A + X -10) andalso (L =:= $a + X -10).
-- 
2.35.3

openSUSE Build Service is sponsored by