Jelajahi Sumber

Improve ShellStream Expect (#1315)

Wojciech Nagórski 1 tahun lalu
induk
melakukan
3bfac50ad0

+ 11 - 6
src/Renci.SshNet/ShellStream.cs

@@ -268,8 +268,9 @@ namespace Renci.SshNet
                             if (match.Success)
                             {
                                 var result = text.Substring(0, match.Index + match.Length);
+                                var charCount = _encoding.GetByteCount(result);
 
-                                for (var i = 0; i < match.Index + match.Length && _incoming.Count > 0; i++)
+                                for (var i = 0; i < charCount && _incoming.Count > 0; i++)
                                 {
                                     // Remove processed items from the queue
                                     _ = _incoming.Dequeue();
@@ -348,7 +349,7 @@ namespace Renci.SshNet
         /// </returns>
         public string Expect(Regex regex, TimeSpan timeout)
         {
-            var text = string.Empty;
+            var result = string.Empty;
 
             while (true)
             {
@@ -356,15 +357,18 @@ namespace Renci.SshNet
                 {
                     if (_incoming.Count > 0)
                     {
-                        text = _encoding.GetString(_incoming.ToArray(), 0, _incoming.Count);
+                        result = _encoding.GetString(_incoming.ToArray(), 0, _incoming.Count);
                     }
 
-                    var match = regex.Match(text);
+                    var match = regex.Match(result);
 
                     if (match.Success)
                     {
+                        result = result.Substring(0, match.Index + match.Length);
+                        var charCount = _encoding.GetByteCount(result);
+
                         // Remove processed items from the queue
-                        for (var i = 0; i < match.Index + match.Length && _incoming.Count > 0; i++)
+                        for (var i = 0; i < charCount && _incoming.Count > 0; i++)
                         {
                             _ = _incoming.Dequeue();
                         }
@@ -386,7 +390,7 @@ namespace Renci.SshNet
                 }
             }
 
-            return text;
+            return result;
         }
 
         /// <summary>
@@ -471,6 +475,7 @@ namespace Renci.SshNet
                                     if (match.Success)
                                     {
                                         var result = text.Substring(0, match.Index + match.Length);
+                                        var charCount = _encoding.GetByteCount(result);
 
                                         for (var i = 0; i < match.Index + match.Length && _incoming.Count > 0; i++)
                                         {

+ 10 - 15
test/Renci.SshNet.Tests/Classes/ShellStreamTest_ReadExpect.cs

@@ -159,15 +159,6 @@ namespace Renci.SshNet.Tests.Classes
         }
 
         [TestMethod]
-        [Ignore] // Fails because it returns the whole buffer i.e. "Hello World!\r\n12345"
-        // We might actually want to keep that behaviour, but just make the documentation clearer.
-        // The Expect documentation says:
-        // "The text available in the shell that contains all the text that ends with expected expression."
-        // Does that mean
-        // 1. the returned string ends with the expected expression; or
-        // 2. the returned string is all the text in the buffer, which is guaranteed to contain the expected expression?
-        // The current behaviour is closer to 2. I think the documentation implies 1.
-        // Either way, there are bugs.
         public void Expect()
         {
             _channelSessionStub.Receive(Encoding.UTF8.GetBytes("Hello "));
@@ -181,10 +172,6 @@ namespace Renci.SshNet.Tests.Classes
             // Case 1 above.
             Assert.AreEqual("Hello World!\r\n123", _shellStream.Expect("123")); // Fails, returns "Hello World!\r\n12345"
             Assert.AreEqual("45", _shellStream.Read()); // Passes, but should probably fail and return ""
-
-            // Case 2 above.
-            Assert.AreEqual("Hello World!\r\n12345", _shellStream.Expect("123")); // Passes
-            Assert.AreEqual("", _shellStream.Read()); // Fails, returns "45"
         }
 
         [TestMethod]
@@ -213,7 +200,6 @@ namespace Renci.SshNet.Tests.Classes
         }
 
         [TestMethod]
-        [Ignore]
         public void Expect_Regex_MultiByte()
         {
             _channelSessionStub.Receive(Encoding.UTF8.GetBytes("𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟"));
@@ -223,7 +209,6 @@ namespace Renci.SshNet.Tests.Classes
         }
 
         [TestMethod]
-        [Ignore]
         public void Expect_String_MultiByte()
         {
             _channelSessionStub.Receive(Encoding.UTF8.GetBytes("hello 你好"));
@@ -232,6 +217,16 @@ namespace Renci.SshNet.Tests.Classes
             Assert.AreEqual("", _shellStream.Read());
         }
 
+        [TestMethod]
+        public void Expect_String_non_ASCII_characters()
+        {
+            _channelSessionStub.Receive(Encoding.UTF8.GetBytes("Hello, こんにちは, Bonjour"));
+
+            Assert.AreEqual("Hello, こ", _shellStream.Expect(new Regex(@"[^\u0000-\u007F]")));
+
+            Assert.AreEqual("んにちは, Bonjour", _shellStream.Read());
+        }
+
         [TestMethod]
         public void Expect_Timeout()
         {