Skip to content

Commit 3bfac50

Browse files
Improve ShellStream Expect (#1315)
1 parent dec04f2 commit 3bfac50

File tree

2 files changed

+21
-21
lines changed

2 files changed

+21
-21
lines changed

src/Renci.SshNet/ShellStream.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,9 @@ public void Expect(TimeSpan timeout, params ExpectAction[] expectActions)
268268
if (match.Success)
269269
{
270270
var result = text.Substring(0, match.Index + match.Length);
271+
var charCount = _encoding.GetByteCount(result);
271272

272-
for (var i = 0; i < match.Index + match.Length && _incoming.Count > 0; i++)
273+
for (var i = 0; i < charCount && _incoming.Count > 0; i++)
273274
{
274275
// Remove processed items from the queue
275276
_ = _incoming.Dequeue();
@@ -348,23 +349,26 @@ public string Expect(Regex regex)
348349
/// </returns>
349350
public string Expect(Regex regex, TimeSpan timeout)
350351
{
351-
var text = string.Empty;
352+
var result = string.Empty;
352353

353354
while (true)
354355
{
355356
lock (_incoming)
356357
{
357358
if (_incoming.Count > 0)
358359
{
359-
text = _encoding.GetString(_incoming.ToArray(), 0, _incoming.Count);
360+
result = _encoding.GetString(_incoming.ToArray(), 0, _incoming.Count);
360361
}
361362

362-
var match = regex.Match(text);
363+
var match = regex.Match(result);
363364

364365
if (match.Success)
365366
{
367+
result = result.Substring(0, match.Index + match.Length);
368+
var charCount = _encoding.GetByteCount(result);
369+
366370
// Remove processed items from the queue
367-
for (var i = 0; i < match.Index + match.Length && _incoming.Count > 0; i++)
371+
for (var i = 0; i < charCount && _incoming.Count > 0; i++)
368372
{
369373
_ = _incoming.Dequeue();
370374
}
@@ -386,7 +390,7 @@ public string Expect(Regex regex, TimeSpan timeout)
386390
}
387391
}
388392

389-
return text;
393+
return result;
390394
}
391395

392396
/// <summary>
@@ -471,6 +475,7 @@ public IAsyncResult BeginExpect(TimeSpan timeout, AsyncCallback callback, object
471475
if (match.Success)
472476
{
473477
var result = text.Substring(0, match.Index + match.Length);
478+
var charCount = _encoding.GetByteCount(result);
474479

475480
for (var i = 0; i < match.Index + match.Length && _incoming.Count > 0; i++)
476481
{

test/Renci.SshNet.Tests/Classes/ShellStreamTest_ReadExpect.cs

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -159,15 +159,6 @@ public void ReadLine_NoData_ReturnsNullAfterClose()
159159
}
160160

161161
[TestMethod]
162-
[Ignore] // Fails because it returns the whole buffer i.e. "Hello World!\r\n12345"
163-
// We might actually want to keep that behaviour, but just make the documentation clearer.
164-
// The Expect documentation says:
165-
// "The text available in the shell that contains all the text that ends with expected expression."
166-
// Does that mean
167-
// 1. the returned string ends with the expected expression; or
168-
// 2. the returned string is all the text in the buffer, which is guaranteed to contain the expected expression?
169-
// The current behaviour is closer to 2. I think the documentation implies 1.
170-
// Either way, there are bugs.
171162
public void Expect()
172163
{
173164
_channelSessionStub.Receive(Encoding.UTF8.GetBytes("Hello "));
@@ -181,10 +172,6 @@ public void Expect()
181172
// Case 1 above.
182173
Assert.AreEqual("Hello World!\r\n123", _shellStream.Expect("123")); // Fails, returns "Hello World!\r\n12345"
183174
Assert.AreEqual("45", _shellStream.Read()); // Passes, but should probably fail and return ""
184-
185-
// Case 2 above.
186-
Assert.AreEqual("Hello World!\r\n12345", _shellStream.Expect("123")); // Passes
187-
Assert.AreEqual("", _shellStream.Read()); // Fails, returns "45"
188175
}
189176

190177
[TestMethod]
@@ -213,7 +200,6 @@ public void ReadLine_MultiByte()
213200
}
214201

215202
[TestMethod]
216-
[Ignore]
217203
public void Expect_Regex_MultiByte()
218204
{
219205
_channelSessionStub.Receive(Encoding.UTF8.GetBytes("𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟"));
@@ -223,7 +209,6 @@ public void Expect_Regex_MultiByte()
223209
}
224210

225211
[TestMethod]
226-
[Ignore]
227212
public void Expect_String_MultiByte()
228213
{
229214
_channelSessionStub.Receive(Encoding.UTF8.GetBytes("hello 你好"));
@@ -232,6 +217,16 @@ public void Expect_String_MultiByte()
232217
Assert.AreEqual("", _shellStream.Read());
233218
}
234219

220+
[TestMethod]
221+
public void Expect_String_non_ASCII_characters()
222+
{
223+
_channelSessionStub.Receive(Encoding.UTF8.GetBytes("Hello, こんにちは, Bonjour"));
224+
225+
Assert.AreEqual("Hello, こ", _shellStream.Expect(new Regex(@"[^\u0000-\u007F]")));
226+
227+
Assert.AreEqual("んにちは, Bonjour", _shellStream.Read());
228+
}
229+
235230
[TestMethod]
236231
public void Expect_Timeout()
237232
{

0 commit comments

Comments
 (0)