Browse Source

Add tests and fix late queue

tznind 9 months ago
parent
commit
2324217397

+ 12 - 13
Terminal.Gui/ConsoleDrivers/AnsiResponseParser.cs

@@ -208,13 +208,13 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
         string cur = HeldToString ();
 
         // Look for an expected response for what is accumulated so far (since Esc)
-        if (MatchResponse (cur, expectedResponses))
+        if (MatchResponse (cur, expectedResponses, true))
         {
             return false;
         }
 
-        // Also try looking for late requests
-        if (MatchResponse (cur, lateResponses))
+        // Also try looking for late requests - in which case we do not invoke but still swallow content to avoid corrupting downstream
+        if (MatchResponse (cur, lateResponses, false))
         {
             return false;
         }
@@ -230,15 +230,20 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
         return false; // Continue accumulating
     }
 
-    private bool MatchResponse (string cur, List<(string terminator, Action<string> response)> valueTuples)
+    private bool MatchResponse (string cur, List<(string terminator, Action<string> response)> collection, bool invokeCallback)
     {
         // Check for expected responses
-        var matchingResponse = valueTuples.FirstOrDefault (r => cur.EndsWith (r.terminator));
+        var matchingResponse = collection.FirstOrDefault (r => cur.EndsWith (r.terminator));
 
         if (matchingResponse.response != null)
         {
-            DispatchResponse (matchingResponse.response);
-            expectedResponses.Remove (matchingResponse);
+
+            if (invokeCallback)
+            {
+                matchingResponse.response?.Invoke (HeldToString ());
+            }
+            ResetState ();
+            collection.Remove (matchingResponse);
 
             return true;
         }
@@ -246,12 +251,6 @@ internal abstract class AnsiResponseParserBase : IAnsiResponseParser
         return false;
     }
 
-    protected void DispatchResponse (Action<string> response)
-    {
-        response?.Invoke (HeldToString ());
-        ResetState ();
-    }
-
     /// <inheritdoc />
     public void ExpectResponse (string terminator, Action<string> response) { expectedResponses.Add ((terminator, response)); }
 

+ 34 - 2
UnitTests/ConsoleDrivers/AnsiResponseParserTests.cs

@@ -1,5 +1,4 @@
-using System.CommandLine.Parsing;
-using System.Diagnostics;
+using System.Diagnostics;
 using System.Text;
 using Xunit.Abstractions;
 
@@ -319,6 +318,39 @@ public class AnsiResponseParserTests (ITestOutputHelper output)
         AssertManualReleaseIs ("\u001b", 5);
     }
 
+    [Fact]
+    public void TestLateResponses ()
+    {
+        var p = new AnsiResponseParser ();
+
+        string? responseA = null;
+        string? responseB = null;
+
+        p.ExpectResponse ("z",(r)=>responseA=r);
+
+        // Some time goes by without us seeing a response
+        p.StopExpecting ("z");
+
+        // Send our new request
+        p.ExpectResponse ("z", (r) => responseB = r);
+
+        // Because we gave up on getting A, we should expect the response to be to our new request
+        Assert.Empty(p.ProcessInput ("\u001b[<1;2z"));
+        Assert.Null (responseA);
+        Assert.Equal ("\u001b[<1;2z", responseB);
+
+        // Oh looks like we got one late after all - swallow it
+        Assert.Empty (p.ProcessInput ("\u001b[0000z"));
+
+        // Do not expect late responses to be populated back to your variable
+        Assert.Null (responseA);
+        Assert.Equal ("\u001b[<1;2z", responseB);
+
+        // We now have no outstanding requests (late or otherwise) so new ansi codes should just fall through
+        Assert.Equal ("\u001b[111z", p.ProcessInput ("\u001b[111z"));
+
+    }
+
     private Tuple<char, int> [] StringToBatch (string batch)
     {
         return batch.Select ((k) => Tuple.Create (k, tIndex++)).ToArray ();