mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
tidyup and streamline naming
This commit is contained in:
@@ -2,45 +2,31 @@
|
||||
|
||||
namespace Terminal.Gui;
|
||||
|
||||
// Enum to manage the parser's state
|
||||
public enum ParserState
|
||||
{
|
||||
Normal,
|
||||
ExpectingBracket,
|
||||
InResponse
|
||||
}
|
||||
internal abstract class AnsiResponseParserBase : IAnsiResponseParser
|
||||
{
|
||||
protected readonly List<(string terminator, Action<string> response)> expectedResponses = new ();
|
||||
private AnsiResponseParserState _state = AnsiResponseParserState.Normal;
|
||||
|
||||
public interface IAnsiResponseParser
|
||||
// Current state of the parser
|
||||
public AnsiResponseParserState State
|
||||
{
|
||||
void ExpectResponse (string terminator, Action<string> response);
|
||||
}
|
||||
|
||||
internal abstract class AnsiResponseParserBase : IAnsiResponseParser
|
||||
{
|
||||
protected readonly List<(string terminator, Action<string> response)> expectedResponses = new ();
|
||||
private ParserState _state = ParserState.Normal;
|
||||
|
||||
// Current state of the parser
|
||||
public ParserState State
|
||||
get => _state;
|
||||
protected set
|
||||
{
|
||||
get => _state;
|
||||
protected set
|
||||
{
|
||||
StateChangedAt = DateTime.Now;
|
||||
_state = value;
|
||||
}
|
||||
StateChangedAt = DateTime.Now;
|
||||
_state = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When <see cref="State"/> was last changed.
|
||||
/// </summary>
|
||||
public DateTime StateChangedAt { get; private set; } = DateTime.Now;
|
||||
/// <summary>
|
||||
/// When <see cref="State"/> was last changed.
|
||||
/// </summary>
|
||||
public DateTime StateChangedAt { get; private set; } = DateTime.Now;
|
||||
|
||||
protected readonly HashSet<char> _knownTerminators = new ();
|
||||
|
||||
public AnsiResponseParserBase ()
|
||||
{
|
||||
protected readonly HashSet<char> _knownTerminators = new ();
|
||||
|
||||
public AnsiResponseParserBase ()
|
||||
{
|
||||
// These all are valid terminators on ansi responses,
|
||||
// see CSI in https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s
|
||||
_knownTerminators.Add ('@');
|
||||
@@ -98,206 +84,217 @@ namespace Terminal.Gui;
|
||||
_knownTerminators.Add ('x');
|
||||
_knownTerminators.Add ('y');
|
||||
_knownTerminators.Add ('z');
|
||||
}
|
||||
|
||||
protected void ResetState ()
|
||||
{
|
||||
State = ParserState.Normal;
|
||||
ClearHeld ();
|
||||
}
|
||||
|
||||
public abstract void ClearHeld ();
|
||||
protected abstract string HeldToString ();
|
||||
protected abstract IEnumerable<object> HeldToObjects ();
|
||||
protected abstract void AddToHeld (object o);
|
||||
|
||||
/// <summary>
|
||||
/// Processes an input collection of objects <paramref name="inputLength"/> long.
|
||||
/// You must provide the indexers to return the objects and the action to append
|
||||
/// to output stream.
|
||||
/// </summary>
|
||||
/// <param name="getCharAtIndex">The character representation of element i of your input collection</param>
|
||||
/// <param name="getObjectAtIndex">The actual element in the collection (e.g. char or Tuple<char,T>)</param>
|
||||
/// <param name="appendOutput">Action to invoke when parser confirms an element of the current collection or a previous
|
||||
/// call's collection should be appended to the current output (i.e. append to your output List/StringBuilder).</param>
|
||||
/// <param name="inputLength">The total number of elements in your collection</param>
|
||||
protected void ProcessInputBase (
|
||||
Func<int, char> getCharAtIndex,
|
||||
Func<int, object> getObjectAtIndex,
|
||||
Action<object> appendOutput,
|
||||
int inputLength)
|
||||
{
|
||||
var index = 0; // Tracks position in the input string
|
||||
|
||||
while (index < inputLength)
|
||||
{
|
||||
var currentChar = getCharAtIndex (index);
|
||||
var currentObj = getObjectAtIndex (index);
|
||||
|
||||
bool isEscape = currentChar == '\x1B';
|
||||
|
||||
switch (State)
|
||||
{
|
||||
case ParserState.Normal:
|
||||
if (isEscape)
|
||||
{
|
||||
// Escape character detected, move to ExpectingBracket state
|
||||
State = ParserState.ExpectingBracket;
|
||||
AddToHeld (currentObj); // Hold the escape character
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal character, append to output
|
||||
appendOutput (currentObj);
|
||||
}
|
||||
break;
|
||||
|
||||
case ParserState.ExpectingBracket:
|
||||
if (isEscape)
|
||||
{
|
||||
// Second escape so we must release first
|
||||
ReleaseHeld (appendOutput, ParserState.ExpectingBracket);
|
||||
AddToHeld (currentObj); // Hold the new escape
|
||||
}
|
||||
else
|
||||
if (currentChar == '[')
|
||||
{
|
||||
// Detected '[', transition to InResponse state
|
||||
State = ParserState.InResponse;
|
||||
AddToHeld (currentObj); // Hold the '['
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalid sequence, release held characters and reset to Normal
|
||||
ReleaseHeld (appendOutput);
|
||||
appendOutput (currentObj); // Add current character
|
||||
}
|
||||
break;
|
||||
|
||||
case ParserState.InResponse:
|
||||
AddToHeld (currentObj);
|
||||
|
||||
// Check if the held content should be released
|
||||
if (ShouldReleaseHeldContent ())
|
||||
{
|
||||
ReleaseHeld (appendOutput);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void ReleaseHeld (Action<object> appendOutput, ParserState newState = ParserState.Normal)
|
||||
{
|
||||
foreach (var o in HeldToObjects ())
|
||||
{
|
||||
appendOutput (o);
|
||||
}
|
||||
|
||||
State = newState;
|
||||
ClearHeld ();
|
||||
}
|
||||
|
||||
// Common response handler logic
|
||||
protected bool ShouldReleaseHeldContent ()
|
||||
{
|
||||
string cur = HeldToString ();
|
||||
|
||||
// Check for expected responses
|
||||
(string terminator, Action<string> response) matchingResponse = expectedResponses.FirstOrDefault (r => cur.EndsWith (r.terminator));
|
||||
|
||||
if (matchingResponse.response != null)
|
||||
{
|
||||
DispatchResponse (matchingResponse.response);
|
||||
expectedResponses.Remove (matchingResponse);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_knownTerminators.Contains (cur.Last ()) && cur.StartsWith (EscSeqUtils.CSI))
|
||||
{
|
||||
// Detected a response that was not expected
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // Continue accumulating
|
||||
}
|
||||
|
||||
|
||||
protected void DispatchResponse (Action<string> response)
|
||||
{
|
||||
response?.Invoke (HeldToString ());
|
||||
ResetState ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a new expected ANSI response with a specific terminator and a callback for when the response is completed.
|
||||
/// </summary>
|
||||
public void ExpectResponse (string terminator, Action<string> response) => expectedResponses.Add ((terminator, response));
|
||||
}
|
||||
|
||||
internal class AnsiResponseParser<T> : AnsiResponseParserBase
|
||||
protected void ResetState ()
|
||||
{
|
||||
private readonly List<Tuple<char, T>> held = new ();
|
||||
State = AnsiResponseParserState.Normal;
|
||||
ClearHeld ();
|
||||
}
|
||||
|
||||
public IEnumerable<Tuple<char, T>> ProcessInput (params Tuple<char, T> [] input)
|
||||
{
|
||||
var output = new List<Tuple<char, T>> ();
|
||||
ProcessInputBase (
|
||||
i => input [i].Item1,
|
||||
i => input [i],
|
||||
c => output.Add ((Tuple<char, T>)c),
|
||||
input.Length);
|
||||
return output;
|
||||
}
|
||||
public abstract void ClearHeld ();
|
||||
protected abstract string HeldToString ();
|
||||
protected abstract IEnumerable<object> HeldToObjects ();
|
||||
protected abstract void AddToHeld (object o);
|
||||
|
||||
public IEnumerable<Tuple<char, T>> Release ()
|
||||
/// <summary>
|
||||
/// Processes an input collection of objects <paramref name="inputLength"/> long.
|
||||
/// You must provide the indexers to return the objects and the action to append
|
||||
/// to output stream.
|
||||
/// </summary>
|
||||
/// <param name="getCharAtIndex">The character representation of element i of your input collection</param>
|
||||
/// <param name="getObjectAtIndex">The actual element in the collection (e.g. char or Tuple<char,T>)</param>
|
||||
/// <param name="appendOutput">
|
||||
/// Action to invoke when parser confirms an element of the current collection or a previous
|
||||
/// call's collection should be appended to the current output (i.e. append to your output List/StringBuilder).
|
||||
/// </param>
|
||||
/// <param name="inputLength">The total number of elements in your collection</param>
|
||||
protected void ProcessInputBase (
|
||||
Func<int, char> getCharAtIndex,
|
||||
Func<int, object> getObjectAtIndex,
|
||||
Action<object> appendOutput,
|
||||
int inputLength
|
||||
)
|
||||
{
|
||||
var index = 0; // Tracks position in the input string
|
||||
|
||||
while (index < inputLength)
|
||||
{
|
||||
foreach (var h in held.ToArray ())
|
||||
char currentChar = getCharAtIndex (index);
|
||||
object currentObj = getObjectAtIndex (index);
|
||||
|
||||
bool isEscape = currentChar == '\x1B';
|
||||
|
||||
switch (State)
|
||||
{
|
||||
yield return h;
|
||||
case AnsiResponseParserState.Normal:
|
||||
if (isEscape)
|
||||
{
|
||||
// Escape character detected, move to ExpectingBracket state
|
||||
State = AnsiResponseParserState.ExpectingBracket;
|
||||
AddToHeld (currentObj); // Hold the escape character
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal character, append to output
|
||||
appendOutput (currentObj);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case AnsiResponseParserState.ExpectingBracket:
|
||||
if (isEscape)
|
||||
{
|
||||
// Second escape so we must release first
|
||||
ReleaseHeld (appendOutput, AnsiResponseParserState.ExpectingBracket);
|
||||
AddToHeld (currentObj); // Hold the new escape
|
||||
}
|
||||
else if (currentChar == '[')
|
||||
{
|
||||
// Detected '[', transition to InResponse state
|
||||
State = AnsiResponseParserState.InResponse;
|
||||
AddToHeld (currentObj); // Hold the '['
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalid sequence, release held characters and reset to Normal
|
||||
ReleaseHeld (appendOutput);
|
||||
appendOutput (currentObj); // Add current character
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case AnsiResponseParserState.InResponse:
|
||||
AddToHeld (currentObj);
|
||||
|
||||
// Check if the held content should be released
|
||||
if (ShouldReleaseHeldContent ())
|
||||
{
|
||||
ReleaseHeld (appendOutput);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
ResetState ();
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
private void ReleaseHeld (Action<object> appendOutput, AnsiResponseParserState newState = AnsiResponseParserState.Normal)
|
||||
{
|
||||
foreach (object o in HeldToObjects ())
|
||||
{
|
||||
appendOutput (o);
|
||||
}
|
||||
|
||||
public override void ClearHeld () => held.Clear ();
|
||||
State = newState;
|
||||
ClearHeld ();
|
||||
}
|
||||
|
||||
protected override string HeldToString () => new string (held.Select (h => h.Item1).ToArray ());
|
||||
// Common response handler logic
|
||||
protected bool ShouldReleaseHeldContent ()
|
||||
{
|
||||
string cur = HeldToString ();
|
||||
|
||||
protected override IEnumerable<object> HeldToObjects () => held;
|
||||
// Check for expected responses
|
||||
(string terminator, Action<string> response) matchingResponse = expectedResponses.FirstOrDefault (r => cur.EndsWith (r.terminator));
|
||||
|
||||
protected override void AddToHeld (object o) => held.Add ((Tuple<char, T>)o);
|
||||
if (matchingResponse.response != null)
|
||||
{
|
||||
DispatchResponse (matchingResponse.response);
|
||||
expectedResponses.Remove (matchingResponse);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_knownTerminators.Contains (cur.Last ()) && cur.StartsWith (EscSeqUtils.CSI))
|
||||
{
|
||||
// Detected a response that was not expected
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // Continue accumulating
|
||||
}
|
||||
|
||||
protected void DispatchResponse (Action<string> response)
|
||||
{
|
||||
response?.Invoke (HeldToString ());
|
||||
ResetState ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a new expected ANSI response with a specific terminator and a callback for when the response is
|
||||
/// completed.
|
||||
/// </summary>
|
||||
public void ExpectResponse (string terminator, Action<string> response) { expectedResponses.Add ((terminator, response)); }
|
||||
}
|
||||
|
||||
internal class AnsiResponseParser : AnsiResponseParserBase
|
||||
internal class AnsiResponseParser<T> : AnsiResponseParserBase
|
||||
{
|
||||
private readonly List<Tuple<char, T>> held = new ();
|
||||
|
||||
public IEnumerable<Tuple<char, T>> ProcessInput (params Tuple<char, T> [] input)
|
||||
{
|
||||
private readonly StringBuilder held = new ();
|
||||
List<Tuple<char, T>> output = new List<Tuple<char, T>> ();
|
||||
|
||||
public string ProcessInput (string input)
|
||||
ProcessInputBase (
|
||||
i => input [i].Item1,
|
||||
i => input [i],
|
||||
c => output.Add ((Tuple<char, T>)c),
|
||||
input.Length);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
public IEnumerable<Tuple<char, T>> Release ()
|
||||
{
|
||||
foreach (Tuple<char, T> h in held.ToArray ())
|
||||
{
|
||||
var output = new StringBuilder ();
|
||||
ProcessInputBase (
|
||||
i => input [i],
|
||||
i => input [i], // For string there is no T so object is same as char
|
||||
c => output.Append ((char)c),
|
||||
input.Length);
|
||||
return output.ToString ();
|
||||
yield return h;
|
||||
}
|
||||
public string Release ()
|
||||
{
|
||||
var output = held.ToString ();
|
||||
ResetState ();
|
||||
|
||||
return output;
|
||||
}
|
||||
public override void ClearHeld () => held.Clear ();
|
||||
ResetState ();
|
||||
}
|
||||
|
||||
protected override string HeldToString () => held.ToString ();
|
||||
public override void ClearHeld () { held.Clear (); }
|
||||
|
||||
protected override IEnumerable<object> HeldToObjects () => held.ToString().Select(c => (object) c).ToArray ();
|
||||
protected override void AddToHeld (object o) => held.Append ((char)o);
|
||||
}
|
||||
protected override string HeldToString () { return new (held.Select (h => h.Item1).ToArray ()); }
|
||||
|
||||
protected override IEnumerable<object> HeldToObjects () { return held; }
|
||||
|
||||
protected override void AddToHeld (object o) { held.Add ((Tuple<char, T>)o); }
|
||||
}
|
||||
|
||||
internal class AnsiResponseParser : AnsiResponseParserBase
|
||||
{
|
||||
private readonly StringBuilder held = new ();
|
||||
|
||||
public string ProcessInput (string input)
|
||||
{
|
||||
var output = new StringBuilder ();
|
||||
|
||||
ProcessInputBase (
|
||||
i => input [i],
|
||||
i => input [i], // For string there is no T so object is same as char
|
||||
c => output.Append ((char)c),
|
||||
input.Length);
|
||||
|
||||
return output.ToString ();
|
||||
}
|
||||
|
||||
public string Release ()
|
||||
{
|
||||
var output = held.ToString ();
|
||||
ResetState ();
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
public override void ClearHeld () { held.Clear (); }
|
||||
|
||||
protected override string HeldToString () { return held.ToString (); }
|
||||
|
||||
protected override IEnumerable<object> HeldToObjects () { return held.ToString ().Select (c => (object)c).ToArray (); }
|
||||
|
||||
protected override void AddToHeld (object o) { held.Append ((char)o); }
|
||||
}
|
||||
|
||||
8
Terminal.Gui/ConsoleDrivers/IAnsiResponseParser.cs
Normal file
8
Terminal.Gui/ConsoleDrivers/IAnsiResponseParser.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
#nullable enable
|
||||
namespace Terminal.Gui;
|
||||
|
||||
public interface IAnsiResponseParser
|
||||
{
|
||||
AnsiResponseParserState State { get; }
|
||||
void ExpectResponse (string terminator, Action<string> response);
|
||||
}
|
||||
24
Terminal.Gui/ConsoleDrivers/ParserState.cs
Normal file
24
Terminal.Gui/ConsoleDrivers/ParserState.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace Terminal.Gui;
|
||||
|
||||
/// <summary>
|
||||
/// Describes the current state of an <see cref="IAnsiResponseParser"/>
|
||||
/// </summary>
|
||||
public enum AnsiResponseParserState
|
||||
{
|
||||
/// <summary>
|
||||
/// Parser is reading normal input e.g. keys typed by user.
|
||||
/// </summary>
|
||||
Normal,
|
||||
|
||||
/// <summary>
|
||||
/// Parser has encountered an Esc and is waiting to see if next
|
||||
/// key(s) continue to form an Ansi escape sequence
|
||||
/// </summary>
|
||||
ExpectingBracket,
|
||||
|
||||
/// <summary>
|
||||
/// Parser has encountered Esc[ and considers that it is in the process
|
||||
/// of reading an ANSI sequence.
|
||||
/// </summary>
|
||||
InResponse
|
||||
}
|
||||
@@ -1566,7 +1566,7 @@ internal class WindowsDriver : ConsoleDriver
|
||||
public IEnumerable<WindowsConsole.InputRecord> ShouldRelease ()
|
||||
{
|
||||
|
||||
if (Parser.State == ParserState.ExpectingBracket &&
|
||||
if (Parser.State == AnsiResponseParserState.ExpectingBracket &&
|
||||
DateTime.Now - Parser.StateChangedAt > _escTimeout)
|
||||
{
|
||||
return Parser.Release ().Select (o => o.Item2);
|
||||
|
||||
@@ -154,7 +154,7 @@ public class AnsiResponseParserTests (ITestOutputHelper output)
|
||||
null,
|
||||
new []
|
||||
{
|
||||
new StepExpectation ('\u001b',ParserState.ExpectingBracket,string.Empty)
|
||||
new StepExpectation ('\u001b',AnsiResponseParserState.ExpectingBracket,string.Empty)
|
||||
}
|
||||
];
|
||||
|
||||
@@ -164,13 +164,13 @@ public class AnsiResponseParserTests (ITestOutputHelper output)
|
||||
'c',
|
||||
new []
|
||||
{
|
||||
new StepExpectation ('\u001b',ParserState.ExpectingBracket,string.Empty),
|
||||
new StepExpectation ('H',ParserState.Normal,"\u001bH"), // H is known terminator and not expected one so here we release both chars
|
||||
new StepExpectation ('\u001b',ParserState.ExpectingBracket,string.Empty),
|
||||
new StepExpectation ('[',ParserState.InResponse,string.Empty),
|
||||
new StepExpectation ('0',ParserState.InResponse,string.Empty),
|
||||
new StepExpectation ('c',ParserState.Normal,string.Empty,"\u001b[0c"), // c is expected terminator so here we swallow input and populate expected response
|
||||
new StepExpectation ('\u001b',ParserState.ExpectingBracket,string.Empty),
|
||||
new StepExpectation ('\u001b',AnsiResponseParserState.ExpectingBracket,string.Empty),
|
||||
new StepExpectation ('H',AnsiResponseParserState.Normal,"\u001bH"), // H is known terminator and not expected one so here we release both chars
|
||||
new StepExpectation ('\u001b',AnsiResponseParserState.ExpectingBracket,string.Empty),
|
||||
new StepExpectation ('[',AnsiResponseParserState.InResponse,string.Empty),
|
||||
new StepExpectation ('0',AnsiResponseParserState.InResponse,string.Empty),
|
||||
new StepExpectation ('c',AnsiResponseParserState.Normal,string.Empty,"\u001b[0c"), // c is expected terminator so here we swallow input and populate expected response
|
||||
new StepExpectation ('\u001b',AnsiResponseParserState.ExpectingBracket,string.Empty),
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -186,7 +186,7 @@ public class AnsiResponseParserTests (ITestOutputHelper output)
|
||||
/// What should the state of the parser be after the <see cref="Input"/>
|
||||
/// is fed in.
|
||||
/// </summary>
|
||||
public ParserState ExpectedStateAfterOperation { get; }
|
||||
public AnsiResponseParserState ExpectedStateAfterOperation { get; }
|
||||
|
||||
/// <summary>
|
||||
/// If this step should release one or more characters, put them here.
|
||||
@@ -201,7 +201,7 @@ public class AnsiResponseParserTests (ITestOutputHelper output)
|
||||
|
||||
public StepExpectation (
|
||||
char input,
|
||||
ParserState expectedStateAfterOperation,
|
||||
AnsiResponseParserState expectedStateAfterOperation,
|
||||
string expectedRelease = "",
|
||||
string expectedAnsiResponse = "") : this ()
|
||||
{
|
||||
@@ -261,8 +261,8 @@ public class AnsiResponseParserTests (ITestOutputHelper output)
|
||||
AssertConsumed (input,ref i);
|
||||
|
||||
// We should know when the state changed
|
||||
Assert.Equal (ParserState.ExpectingBracket, _parser1.State);
|
||||
Assert.Equal (ParserState.ExpectingBracket, _parser2.State);
|
||||
Assert.Equal (AnsiResponseParserState.ExpectingBracket, _parser1.State);
|
||||
Assert.Equal (AnsiResponseParserState.ExpectingBracket, _parser2.State);
|
||||
|
||||
Assert.Equal (DateTime.Now.Date, _parser1.StateChangedAt.Date);
|
||||
Assert.Equal (DateTime.Now.Date, _parser2.StateChangedAt.Date);
|
||||
@@ -300,14 +300,14 @@ public class AnsiResponseParserTests (ITestOutputHelper output)
|
||||
|
||||
// First Esc gets grabbed
|
||||
AssertConsumed (input, ref i); // Esc
|
||||
Assert.Equal (ParserState.ExpectingBracket,_parser1.State);
|
||||
Assert.Equal (ParserState.ExpectingBracket, _parser2.State);
|
||||
Assert.Equal (AnsiResponseParserState.ExpectingBracket,_parser1.State);
|
||||
Assert.Equal (AnsiResponseParserState.ExpectingBracket, _parser2.State);
|
||||
|
||||
// Because next char is 'f' we do not see a bracket so release both
|
||||
AssertReleased (input, ref i, "\u001bf", 0,1); // f
|
||||
|
||||
Assert.Equal (ParserState.Normal, _parser1.State);
|
||||
Assert.Equal (ParserState.Normal, _parser2.State);
|
||||
Assert.Equal (AnsiResponseParserState.Normal, _parser1.State);
|
||||
Assert.Equal (AnsiResponseParserState.Normal, _parser2.State);
|
||||
|
||||
AssertReleased (input, ref i,"i",2);
|
||||
AssertReleased (input, ref i, "s", 3);
|
||||
@@ -428,7 +428,7 @@ public class AnsiResponseParserTests (ITestOutputHelper output)
|
||||
|
||||
Assert.Equal (expectedRelease, _parser2.Release ());
|
||||
|
||||
Assert.Equal (ParserState.Normal, _parser1.State);
|
||||
Assert.Equal (ParserState.Normal, _parser2.State);
|
||||
Assert.Equal (AnsiResponseParserState.Normal, _parser1.State);
|
||||
Assert.Equal (AnsiResponseParserState.Normal, _parser2.State);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user