Implement CborReader.SkipToParent();
authorEirik Tsarpalis <eirik.tsarpalis@gmail.com>
Tue, 28 Apr 2020 17:54:56 +0000 (18:54 +0100)
committerEirik Tsarpalis <eirik.tsarpalis@gmail.com>
Wed, 29 Apr 2020 14:30:12 +0000 (15:30 +0100)
src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.SkipValue.cs
src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.SkipValue.cs

index a2449d6..d1a7785 100644 (file)
@@ -124,6 +124,77 @@ namespace System.Security.Cryptography.Encoding.Tests.Cbor
         }
 
         [Theory]
+        [InlineData(0)]
+        [InlineData(1)]
+        [InlineData(2)]
+        public static void SkipToParent_SimpleArray_HappyPath(int skipOffset)
+        {
+            byte[] encoding = "83010203".HexToByteArray(); // [1, 2, 3]
+            var reader = new CborReader(encoding);
+
+            reader.ReadStartArray();
+            for (int i = 0; i < skipOffset; i++)
+            {
+                reader.ReadInt32();
+            }
+
+            reader.SkipToParent();
+
+            Assert.Equal(CborReaderState.Finished, reader.PeekState());
+        }
+
+        [Theory]
+        [InlineData(0)]
+        [InlineData(1)]
+        [InlineData(2)]
+        public static void SkipToParent_NestedArray_HappyPath(int skipOffset)
+        {
+            byte[] encoding = "8283010203a0".HexToByteArray(); // [[1, 2, 3], { }]
+            var reader = new CborReader(encoding);
+
+            reader.ReadStartArray();
+            reader.ReadStartArray();
+            for (int i = 0; i < skipOffset; i++)
+            {
+                reader.ReadInt32();
+            }
+
+            reader.SkipToParent();
+            Assert.Equal(CborReaderState.StartMap, reader.PeekState());
+        }
+
+        [Theory]
+        [InlineData(0)]
+        [InlineData(1)]
+        [InlineData(2)]
+        public static void SkipToParent_NestedKey_HappyPath(int skipOffset)
+        {
+            byte[] encoding = "a17f616161626163ff80".HexToByteArray(); // { (_ "a", "b", "c") : [] }
+            var reader = new CborReader(encoding);
+
+            reader.ReadStartMap();
+            reader.ReadStartTextStringIndefiniteLength();
+            for (int i = 0; i < skipOffset; i++)
+            {
+                reader.ReadTextString();
+            }
+
+            reader.SkipToParent();
+            Assert.Equal(CborReaderState.StartArray, reader.PeekState());
+        }
+
+        [Fact]
+        public static void SkipToParent_RootContext_ShouldThrowInvalidOperationException()
+        {
+            byte[] encoding = "01".HexToByteArray();
+            var reader = new CborReader(encoding);
+
+            Assert.Throws<InvalidOperationException>(() => reader.SkipToParent());
+            reader.ReadInt32();
+            Assert.Throws<InvalidOperationException>(() => reader.SkipToParent());
+        }
+
+        [Theory]
         [InlineData(50_000)]
         public static void SkipValue_ExtremelyNestedValues_ShouldNotStackOverflow(int depth)
         {
index cc03e51..411e579 100644 (file)
@@ -2,18 +2,31 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+#nullable enable
+using System.Diagnostics;
+
 namespace System.Security.Cryptography.Encoding.Tests.Cbor
 {
     internal partial class CborReader
     {
-        public void SkipValue()
+        public void SkipValue() => SkipToAncestor(0);
+        public void SkipToParent()
+        {
+            if ((_nestedDataItems?.Count ?? 0) == 0)
+            {
+                throw new InvalidOperationException("CBOR reader is at the root context.");
+            }
+
+            SkipToAncestor(1);
+        }
+
+        private void SkipToAncestor(int depth)
         {
+            Debug.Assert(0 <= depth && depth <= (_nestedDataItems?.Count ?? 0));
             Checkpoint checkpoint = CreateCheckpoint();
 
             try
             {
-                int depth = 0;
-
                 do
                 {
                     SkipNextNode(ref depth);