diff --git a/TPP.Core/Modes/Runmode.cs b/TPP.Core/Modes/Runmode.cs index 0144e210..62e10c86 100644 --- a/TPP.Core/Modes/Runmode.cs +++ b/TPP.Core/Modes/Runmode.cs @@ -179,7 +179,7 @@ private async Task CollectRunStatistics(User user, InputSequence input, string r if (runNumber != null && !user.ParticipationEmblems.Contains(runNumber.Value)) await _userRepo.GiveEmblem(user, runNumber.Value); long counter = await _runCounterRepo.Increment(runNumber, incrementBy: input.InputSets.Count); - await _overlayConnection.Send(new ButtonPressUpdate(counter), CancellationToken.None); + await _overlayConnection.Send(new ButtonPressesCountUpdate(counter), CancellationToken.None); } public async Task Run() diff --git a/TPP.Core/Overlay/Events/RunInputEvents.cs b/TPP.Core/Overlay/Events/RunInputEvents.cs index 356f7179..5cb1bdd5 100644 --- a/TPP.Core/Overlay/Events/RunInputEvents.cs +++ b/TPP.Core/Overlay/Events/RunInputEvents.cs @@ -3,6 +3,7 @@ using System.Collections.Immutable; using System.Linq; using System.Runtime.Serialization; +using NodaTime; using TPP.Inputting; using TPP.Inputting.Inputs; using TPP.Model; @@ -66,11 +67,81 @@ public sealed class AnarchyInputStop : IOverlayEvent } [DataContract] - public sealed class ButtonPressUpdate : IOverlayEvent + public sealed class ButtonPressesCountUpdate : IOverlayEvent { public string OverlayEventType => "button_press_update"; [DataMember(Name = "presses")] public long NumTotalButtonPresses { get; set; } - public ButtonPressUpdate(long numTotalButtonPresses) => NumTotalButtonPresses = numTotalButtonPresses; + public ButtonPressesCountUpdate(long numTotalButtonPresses) => NumTotalButtonPresses = numTotalButtonPresses; + } + + [DataContract] + public readonly struct NewVote + { + [DataMember(Name = "command")] public string Command { get; init; } + [DataMember(Name = "user")] public User User { get; init; } + // [DataMember(Name = "button_sequence")] public InputSequence InputSequence { get; init; } // unused + // [DataMember(Name = "ts")] public Instant Timestamp { get; init; } // unused + } + + [DataContract] + public readonly struct Vote + { + [DataMember(Name = "command")] public string Command { get; init; } + [DataMember(Name = "count")] public int Count { get; init; } + // [DataMember(Name = "button_sequence")] public InputSequence InputSequence { get; init; } // unused + } + + [DataContract] + public sealed class DemocracyVotesUpdate : IOverlayEvent + { + public string OverlayEventType => "democracy_new_vote"; + + [DataMember(Name = "new_vote")] public NewVote NewVote { get; init; } + [DataMember(Name = "votes")] public List Votes { get; init; } + + public DemocracyVotesUpdate( + User newVoteUser, + InputSequence votedInput, + IReadOnlyDictionary votes) + { + NewVote = new NewVote { User = newVoteUser, Command = votedInput.OriginalText }; + Votes = votes + .Select(kvp => new Vote { Command = kvp.Key.OriginalText, Count = kvp.Value }) + .OrderBy(vote => vote.Count) + .ToList(); + } + } + + [DataContract] + public sealed class DemocracyReset : IOverlayEvent + { + public string OverlayEventType => "democracy_reset"; + + [DataMember(Name = "vote_ends_at")] public Instant Timestamp { get; init; } + public DemocracyReset(Instant timestamp) => Timestamp = timestamp; + } + + [DataContract] + public sealed class DemocracyVotingOver : IOverlayEvent + { + public string OverlayEventType => "democracy_voting_over"; + + [DataMember(Name = "winning_button_sequence")] public string WinningSequence { get; init; } + public DemocracyVotingOver(InputSequence input) => WinningSequence = input.OriginalText; + } + + [DataContract] + public sealed class DemocracySequenceStart : IOverlayEvent + { + public string OverlayEventType => "democracy_sequence_start"; + + [DataMember(Name = "button_sequence")] public List> Sequence { get; init; } + public DemocracySequenceStart(InputSequence input) + { + Sequence = input.InputSets + .Select(set => set.Inputs + .Select(i => i.DisplayedText).ToList()).ToList(); + } } } diff --git a/TPP.Inputting/InputHoldTiming.cs b/TPP.Inputting/InputHoldTiming.cs index 30d1cb29..1bf29aa1 100644 --- a/TPP.Inputting/InputHoldTiming.cs +++ b/TPP.Inputting/InputHoldTiming.cs @@ -51,7 +51,7 @@ public TimedInputSet TimeInput(InputSet inputSet, float duration) sleepDuration = _minSleepDuration; } - return new TimedInputSet(new InputSet(inputsWithoutHold), holdDuration, sleepDuration); + return new TimedInputSet(inputSet with { Inputs = inputsWithoutHold }, holdDuration, sleepDuration); } } } diff --git a/TPP.Inputting/InputSequence.cs b/TPP.Inputting/InputSequence.cs index 1a9486b9..0c9533f8 100644 --- a/TPP.Inputting/InputSequence.cs +++ b/TPP.Inputting/InputSequence.cs @@ -8,11 +8,13 @@ namespace TPP.Inputting /// An input sequence is a sequence of that are inputted in sequence. /// This is used e.g. in democracy mode. /// - public sealed record InputSequence(IImmutableList InputSets) + public sealed record InputSequence(IImmutableList InputSets, string OriginalText) { // Need to manually define these, because lists don't implement a proper Equals and GetHashCode themselves. - public bool Equals(InputSequence? other) => other != null && InputSets.SequenceEqual(other.InputSets); - public override int GetHashCode() => InputSets.Select(i => i.GetHashCode()).Aggregate(HashCode.Combine); + public bool Equals(InputSequence? other) => + other != null && InputSets.SequenceEqual(other.InputSets) && OriginalText == other.OriginalText; + public override int GetHashCode() => + InputSets.Select(i => i.GetHashCode()).Aggregate(HashCode.Combine) + OriginalText.GetHashCode(); /// /// Determines whether this input sequence is effectively equal to another input sequence, @@ -32,6 +34,7 @@ public bool HasSameOutcomeAs(InputSequence other) return true; } - public override string ToString() => $"{nameof(InputSequence)}({string.Join(", ", InputSets)})"; + public override string ToString() => + $"{nameof(InputSequence)}([{string.Join(", ", InputSets)}] '{OriginalText}')"; } } diff --git a/TPP.Inputting/InputSet.cs b/TPP.Inputting/InputSet.cs index f3edcbe0..6144c1f6 100644 --- a/TPP.Inputting/InputSet.cs +++ b/TPP.Inputting/InputSet.cs @@ -10,11 +10,13 @@ namespace TPP.Inputting /// An input set is a set of inputs being inputted simultaneously. /// These include buttons, touch screen coordinates, waits etc. /// - public sealed record InputSet(ImmutableList Inputs) + public sealed record InputSet(ImmutableList Inputs, string OriginalText) { // Need to manually define these, because lists don't implement a proper Equals and GetHashCode themselves. - public bool Equals(InputSet? other) => other != null && Inputs.SequenceEqual(other.Inputs); - public override int GetHashCode() => Inputs.Select(i => i.GetHashCode()).Aggregate(HashCode.Combine); + public bool Equals(InputSet? other) => + other != null && Inputs.SequenceEqual(other.Inputs) && OriginalText == other.OriginalText; + public override int GetHashCode() => + Inputs.Select(i => i.GetHashCode()).Aggregate(HashCode.Combine) + OriginalText.GetHashCode(); /// /// Determines whether this input set is effectively equal to another input set, @@ -29,7 +31,7 @@ public bool HasSameOutcomeAs(InputSet other) return new HashSet(Inputs, SameOutcomeComparer.Instance).SetEquals(other.Inputs); } - public override string ToString() => string.Join("+", Inputs); + public override string ToString() => $"{nameof(InputSet)}({string.Join("+", Inputs)} '{OriginalText}')"; } /// diff --git a/TPP.Inputting/LinqExtensions.cs b/TPP.Inputting/LinqExtensions.cs new file mode 100644 index 00000000..69c9ddaa --- /dev/null +++ b/TPP.Inputting/LinqExtensions.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace TPP.Inputting; + +public static class LinqExtensions +{ + private sealed class Group : IGrouping + { + public T Elem { get; } + public List Members { get; } + public Group(T elem, List members) + { + Elem = elem; + Members = members; + } + + public T Key => Elem; + public IEnumerator GetEnumerator() => Members.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)Members).GetEnumerator(); + } + + /// + /// Inspired by MoreLINQ's GroupAdjacent. + /// Might want to replace with proper dependency on `MoreLINQ` once more than this is needed. + /// + public static IEnumerable> GroupAdjacent( + this IEnumerable source, + Func equalityComparer) + { + Group? group = null; + foreach (T element in source) + { + if (group != null) + { + if (equalityComparer(group.Elem, element)) + { + group.Members.Add(element); + continue; + } + else + yield return group; + } + group = new Group(element, new List { element }); + } + if (group != null) + yield return group; + } +} diff --git a/TPP.Inputting/Parsing/BareInputParser.cs b/TPP.Inputting/Parsing/BareInputParser.cs index e4033e5f..14313014 100644 --- a/TPP.Inputting/Parsing/BareInputParser.cs +++ b/TPP.Inputting/Parsing/BareInputParser.cs @@ -62,9 +62,9 @@ public BareInputParser( } // Get the indexes that each input set ends at - IEnumerable inputSetEndIndexes = match.Groups["inputset"].Captures + IEnumerable<(int, int)> inputSetRanges = match.Groups["inputset"].Captures .OrderBy(c => c.Index) - .Select(c => c.Index + c.Length); + .Select(c => (c.Index, c.Index + c.Length)); // Get all captures as queues for easy consumption Dictionary> defsToCaptureQueues = _inputDefinitions .Select((def, i) => @@ -75,7 +75,7 @@ public BareInputParser( var capturesRepeat = new Queue(match.Groups["repeat"].Captures.OrderBy(c => c.Index)); var inputSets = new List(); - foreach (int endIndex in inputSetEndIndexes) + foreach ((int startIndex, int endIndex) in inputSetRanges) { var inputs = new List(); var inputWithIndexes = new List<(int, Input)>(); @@ -99,12 +99,19 @@ public BareInputParser( inputs.Add(HoldInput.Instance); capturesHold.Dequeue(); } + string originalText; int numRepeat = 1; - if (capturesRepeat.Any() && capturesRepeat.Peek().Index < endIndex) + int capturesRepeatIndex = capturesRepeat.Any() ? capturesRepeat.Peek().Index : endIndex; + if (capturesRepeatIndex < endIndex) { numRepeat = int.Parse(capturesRepeat.Dequeue().Value); + originalText = text[startIndex..capturesRepeatIndex]; } - var inputSet = new InputSet(inputs.ToImmutableList()); + else + { + originalText = text[startIndex..endIndex]; + } + var inputSet = new InputSet(inputs.ToImmutableList(), originalText); inputSets.AddRange(Enumerable.Repeat(inputSet, numRepeat)); // we need to check the length, because the regex cannot enforce the max length since the sequence may // have been lengthened with a specified number of repetitions for a button set. @@ -113,7 +120,7 @@ public BareInputParser( return null; } } - return new InputSequence(inputSets.ToImmutableList()); + return new InputSequence(inputSets.ToImmutableList(), text); } } } diff --git a/TPP.Inputting/Parsing/SidedInputParser.cs b/TPP.Inputting/Parsing/SidedInputParser.cs index 20295cdb..aedd56c6 100644 --- a/TPP.Inputting/Parsing/SidedInputParser.cs +++ b/TPP.Inputting/Parsing/SidedInputParser.cs @@ -46,7 +46,8 @@ public SidedInputParser(IInputParser delegateParser) bool direct = inputSide != null; var sideInput = new SideInput(inputSide, direct); return new InputSequence(inputSequence.InputSets - .Select(set => new InputSet(set.Inputs.Append(sideInput).ToImmutableList())).ToImmutableList()); + .Select(set => set with { Inputs = set.Inputs.Append(sideInput).ToImmutableList() }).ToImmutableList(), + text); } } } diff --git a/tests/TPP.Core.Tests/Overlay/OverlayConnectionTest.cs b/tests/TPP.Core.Tests/Overlay/OverlayConnectionTest.cs index 499aa975..499de1d7 100644 --- a/tests/TPP.Core.Tests/Overlay/OverlayConnectionTest.cs +++ b/tests/TPP.Core.Tests/Overlay/OverlayConnectionTest.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.Logging.Abstractions; using Moq; +using NodaTime; using NUnit.Framework; using TPP.Core.Overlay; @@ -50,5 +51,28 @@ await _connection.Send( const string json = @"{""type"":""test"",""extra_parameters"":{""enum_value"":""foo_bar""}}"; _broadcastServerMock.Verify(s => s.Send(json, CancellationToken.None), Times.Once); } + + private struct EventWithInstant : IOverlayEvent + { + public string OverlayEventType => "iso_test"; + [DataMember(Name = "instant")] public Instant Instant { get; init; } + public EventWithInstant(Instant instant) => Instant = instant; + } + + [Test] + public async Task send_instant_as_iso8601() + { + await _connection.Send(new EventWithInstant(Instant.FromUnixTimeSeconds(0)), CancellationToken.None); + await _connection.Send(new EventWithInstant(Instant.FromUnixTimeSeconds(123)), CancellationToken.None); + await _connection.Send(new EventWithInstant(Instant.FromUnixTimeSeconds(123).PlusNanoseconds(1)), + CancellationToken.None); + const string json1 = @"{""type"":""iso_test"",""extra_parameters"":{""instant"":""1970-01-01T00:00:00Z""}}"; + const string json2 = @"{""type"":""iso_test"",""extra_parameters"":{""instant"":""1970-01-01T00:02:03Z""}}"; + const string json3 = + @"{""type"":""iso_test"",""extra_parameters"":{""instant"":""1970-01-01T00:02:03.000000001Z""}}"; + _broadcastServerMock.Verify(s => s.Send(json1, CancellationToken.None), Times.Once); + _broadcastServerMock.Verify(s => s.Send(json2, CancellationToken.None), Times.Once); + _broadcastServerMock.Verify(s => s.Send(json3, CancellationToken.None), Times.Once); + } } } diff --git a/tests/TPP.Inputting.Tests/InputEqualityTest.cs b/tests/TPP.Inputting.Tests/InputEqualityTest.cs index 4c51dbb3..72fad6ab 100644 --- a/tests/TPP.Inputting.Tests/InputEqualityTest.cs +++ b/tests/TPP.Inputting.Tests/InputEqualityTest.cs @@ -8,9 +8,10 @@ namespace TPP.Inputting.Tests public class InputEqualityTest { private static InputSet Set(params string[] inputs) => - new(inputs.Select(s => new Input(s, s, s)).ToImmutableList()); + new(inputs.Select(s => new Input(s, s, s)).ToImmutableList(), string.Join('+', inputs)); - private static InputSequence Seq(params InputSet[] inputSets) => new(inputSets.ToImmutableList()); + private static InputSequence Seq(params InputSet[] inputSets) => new(inputSets.ToImmutableList(), + string.Join("", inputSets.Select(i => i.OriginalText))); [Test] public void TestSameOutcomeRegularInput() @@ -136,10 +137,10 @@ public void TestSameOutcomeInputSet() var input4A = new Input("Foo", "a", "foo"); var input4B = new Input("Bar", "a", "bar"); - var setRef = new InputSet(ImmutableList.Create(inputRefA, inputRefB)); - var setDifferentOrder = new InputSet(ImmutableList.Create(input1A, input1B)); - var setDifferentLength = new InputSet(ImmutableList.Create(input2)); - var setDifferentEffectiveInput = new InputSet(ImmutableList.Create(input4A, input4B)); + var setRef = new InputSet(ImmutableList.Create(inputRefA, inputRefB), "foo+bar"); + var setDifferentOrder = new InputSet(ImmutableList.Create(input1A, input1B), "baz+quz"); + var setDifferentLength = new InputSet(ImmutableList.Create(input2), "foo"); + var setDifferentEffectiveInput = new InputSet(ImmutableList.Create(input4A, input4B), "foo+bar"); Assert.AreNotEqual(setRef, setDifferentOrder); Assert.IsTrue(setRef.HasSameOutcomeAs(setDifferentOrder)); diff --git a/tests/TPP.Inputting.Tests/InputHoldTimingTest.cs b/tests/TPP.Inputting.Tests/InputHoldTimingTest.cs index 757120f5..bff72100 100644 --- a/tests/TPP.Inputting.Tests/InputHoldTimingTest.cs +++ b/tests/TPP.Inputting.Tests/InputHoldTimingTest.cs @@ -9,10 +9,10 @@ public class InputHoldTimingTest private const float Delta = 1 / 600f; private static readonly InputSet DummyInput = - new(ImmutableList.Create(new Input("A", "A", "A"))); + new(ImmutableList.Create(new Input("A", "A", "A")), "A"); private static readonly InputSet DummyInputHeld = - new(ImmutableList.Create(new Input("A", "A", "A"), HoldInput.Instance)); + new(ImmutableList.Create(new Input("A", "A", "A"), HoldInput.Instance), "A-"); [Test] public void regular_with_spare_time_divides_normally() diff --git a/tests/TPP.Inputting.Tests/Parsing/BareInputParserTest.cs b/tests/TPP.Inputting.Tests/Parsing/BareInputParserTest.cs index d39ed9f4..e1cb1d04 100644 --- a/tests/TPP.Inputting.Tests/Parsing/BareInputParserTest.cs +++ b/tests/TPP.Inputting.Tests/Parsing/BareInputParserTest.cs @@ -9,9 +9,10 @@ namespace TPP.Inputting.Tests.Parsing public class BareInputParserTest { private static InputSet Set(params string[] inputs) => - new(inputs.Select(s => new Input(s, s, s)).ToImmutableList()); + new(inputs.Select(s => new Input(s, s, s)).ToImmutableList(), string.Join('+', inputs)); - private static InputSequence Seq(params InputSet[] inputSets) => new(inputSets.ToImmutableList()); + private static InputSequence Seq(string text, params InputSet[] inputSets) => + new(inputSets.ToImmutableList(), text); private IInputParser _inputParser = null!; @@ -29,12 +30,13 @@ public void TestBasicInputs() .Build(); // good cases - AssertInput("aa", Seq(Set("a"), Set("a"))); - AssertInput("a2a", Seq(Set("a"), Set("a"), Set("a"))); - AssertInput("a2a2", Seq(Set("a"), Set("a"), Set("a"), Set("a"))); - AssertInput("start4", Seq(Set("start"), Set("start"), Set("start"), Set("start"))); - AssertInput("a+b2startselect", Seq(Set("a", "b"), Set("a", "b"), Set("start"), Set("select"))); - AssertInput("b+a", Seq(Set("b", "a"))); // order is preserved + AssertInput("aa", Seq("aa", Set("a"), Set("a"))); + AssertInput("a2a", Seq("a2a", Set("a"), Set("a"), Set("a"))); + AssertInput("a2a2", Seq("a2a2", Set("a"), Set("a"), Set("a"), Set("a"))); + AssertInput("start4", Seq("start4", Set("start"), Set("start"), Set("start"), Set("start"))); + AssertInput("a+b2startselect", + Seq("a+b2startselect", Set("a", "b"), Set("a", "b"), Set("start"), Set("select"))); + AssertInput("b+a", Seq("b+a", Set("b", "a"))); // order is preserved // bad cases AssertInput("x", null); // not a button @@ -51,15 +53,15 @@ public void TestHold() // hold enabled _inputParser = builder.HoldEnabled(true).Build(); - AssertInput("a", Seq(Set("a"))); - Assert.AreEqual(Seq(new InputSet(ImmutableList.Create( - new Input("a", "a", "a"), - HoldInput.Instance)) + AssertInput("a", Seq("a", Set("a"))); + Assert.AreEqual(Seq("a-", new InputSet(ImmutableList.Create( + new Input("a", "a", "a"), + HoldInput.Instance), "a-") ), _inputParser.Parse("a-")); // hold disabled _inputParser = builder.HoldEnabled(false).Build(); - AssertInput("a", Seq(Set("a"))); + AssertInput("a", Seq("a", Set("a"))); AssertInput("a-", null); } @@ -73,9 +75,9 @@ public void TestAlias() .Build(); InputSequence? result = _inputParser.Parse("honky"); - Assert.AreEqual(Seq( - new InputSet(ImmutableList.Create(new Input("honk", "y", "honk"))), - new InputSet(ImmutableList.Create(new Input("y", "y", "y"))) + Assert.AreEqual(Seq("honky", + new InputSet(ImmutableList.Create(new Input("honk", "y", "honk")), "honk"), + new InputSet(ImmutableList.Create(new Input("y", "y", "y")), "y") ), result); } @@ -89,9 +91,9 @@ public void TestRemapping() .Build(); InputSequence? result = _inputParser.Parse("honky"); - Assert.AreEqual(Seq( - new InputSet(ImmutableList.Create(new Input("y", "y", "honk"))), - new InputSet(ImmutableList.Create(new Input("y", "y", "y"))) + Assert.AreEqual(Seq("honky", + new InputSet(ImmutableList.Create(new Input("y", "y", "honk")), "honk"), + new InputSet(ImmutableList.Create(new Input("y", "y", "y")), "y") ), result); } @@ -104,28 +106,28 @@ public void TestTouchscreen() .LengthRestrictions(maxSetLength: 2, maxSequenceLength: 4) .Build(); - Assert.AreEqual(Seq( - new InputSet(ImmutableList.Create(new Input("a", "a", "a"))), + Assert.AreEqual(Seq("a234,123a", + new InputSet(ImmutableList.Create(new Input("a", "a", "a")), "a"), new InputSet(ImmutableList.Create( - new TouchscreenInput("234,123", "touchscreen", "234,123", 234, 123))), - new InputSet(ImmutableList.Create(new Input("a", "a", "a"))) + new TouchscreenInput("234,123", "touchscreen", "234,123", 234, 123)), "234,123"), + new InputSet(ImmutableList.Create(new Input("a", "a", "a")), "a") ), _inputParser.Parse("a234,123a")); - Assert.AreEqual(Seq( + Assert.AreEqual(Seq("239,159", new InputSet(ImmutableList.Create( - new TouchscreenInput("239,159", "touchscreen", "239,159", 239, 159))) + new TouchscreenInput("239,159", "touchscreen", "239,159", 239, 159)), "239,159") ), _inputParser.Parse("239,159")); - Assert.AreEqual(Seq( + Assert.AreEqual(Seq("0,0", new InputSet(ImmutableList.Create( - new TouchscreenInput("0,0", "touchscreen", "0,0", 0, 0))) + new TouchscreenInput("0,0", "touchscreen", "0,0", 0, 0)), "0,0") ), _inputParser.Parse("0,0")); // allow leading zeroes - Assert.AreEqual(Seq( + Assert.AreEqual(Seq("000,000", new InputSet(ImmutableList.Create( - new TouchscreenInput("000,000", "touchscreen", "000,000", 0, 0))) + new TouchscreenInput("000,000", "touchscreen", "000,000", 0, 0)), "000,000") ), _inputParser.Parse("000,000")); - Assert.AreEqual(Seq( + Assert.AreEqual(Seq("012,023", new InputSet(ImmutableList.Create( - new TouchscreenInput("012,023", "touchscreen", "012,023", 12, 23))) + new TouchscreenInput("012,023", "touchscreen", "012,023", 12, 23)), "012,023") ), _inputParser.Parse("012,023")); // out of bounds Assert.IsNull(_inputParser.Parse("240,159")); @@ -144,24 +146,28 @@ public void TestTouchscreenDrag() .LengthRestrictions(maxSetLength: 2, maxSequenceLength: 4) .Build(); - Assert.AreEqual(Seq( - new InputSet(ImmutableList.Create(new Input("a", "a", "a"))), + Assert.AreEqual(Seq("a234,123>222,111a", + new InputSet(ImmutableList.Create(new Input("a", "a", "a")), "a"), new InputSet(ImmutableList.Create( - new TouchscreenDragInput("234,123>222,111", "touchscreen", "234,123>222,111", 234, 123, 222, 111))), - new InputSet(ImmutableList.Create(new Input("a", "a", "a"))) + new TouchscreenDragInput("234,123>222,111", "touchscreen", "234,123>222,111", 234, 123, 222, + 111)), + "234,123>222,111"), + new InputSet(ImmutableList.Create(new Input("a", "a", "a")), "a") ), _inputParser.Parse("a234,123>222,111a")); - Assert.AreEqual(Seq( + Assert.AreEqual(Seq("239,159>0,0", new InputSet(ImmutableList.Create( - new TouchscreenDragInput("239,159>0,0", "touchscreen", "239,159>0,0", 239, 159, 0, 0))) + new TouchscreenDragInput("239,159>0,0", "touchscreen", "239,159>0,0", 239, 159, 0, 0)), + "239,159>0,0") ), _inputParser.Parse("239,159>0,0")); // allow leading zeroes - Assert.AreEqual(Seq( + Assert.AreEqual(Seq("000,000>000,000", new InputSet(ImmutableList.Create( - new TouchscreenDragInput("000,000>000,000", "touchscreen", "000,000>000,000", 0, 0, 0, 0))) + new TouchscreenDragInput("000,000>000,000", "touchscreen", "000,000>000,000", 0, 0, 0, 0)), + "000,000>000,000") ), _inputParser.Parse("000,000>000,000")); - Assert.AreEqual(Seq( + Assert.AreEqual(Seq("012,023>0,0", new InputSet(ImmutableList.Create( - new TouchscreenDragInput("012,023>0,0", "touchscreen", "012,023>0,0", 12, 23, 0, 0))) + new TouchscreenDragInput("012,023>0,0", "touchscreen", "012,023>0,0", 12, 23, 0, 0)), "012,023>0,0") ), _inputParser.Parse("012,023>0,0")); // out of bounds Assert.IsNull(_inputParser.Parse("240,159>0,0")); @@ -192,19 +198,19 @@ public void TestTouchscreenAlias() .LengthRestrictions(maxSetLength: 2, maxSequenceLength: 4) .Build(); - Assert.AreEqual(Seq( - new InputSet(ImmutableList.Create(new Input("a", "a", "a"))), + Assert.AreEqual(Seq("amove12a", + new InputSet(ImmutableList.Create(new Input("a", "a", "a")), "a"), new InputSet(ImmutableList.Create( - new TouchscreenInput("move1", "touchscreen", "move1", 42, 69))), + new TouchscreenInput("move1", "touchscreen", "move1", 42, 69)), "move1"), new InputSet(ImmutableList.Create( - new TouchscreenInput("move1", "touchscreen", "move1", 42, 69))), - new InputSet(ImmutableList.Create(new Input("a", "a", "a"))) + new TouchscreenInput("move1", "touchscreen", "move1", 42, 69)), "move1"), + new InputSet(ImmutableList.Create(new Input("a", "a", "a")), "a") ), _inputParser.Parse("amove12a")); - Assert.AreEqual(Seq( + Assert.AreEqual(Seq("234,123move1", new InputSet(ImmutableList.Create( - new TouchscreenInput("234,123", "touchscreen", "234,123", 234, 123))), + new TouchscreenInput("234,123", "touchscreen", "234,123", 234, 123)), "234,123"), new InputSet(ImmutableList.Create( - new TouchscreenInput("move1", "touchscreen", "move1", 42, 69))) + new TouchscreenInput("move1", "touchscreen", "move1", 42, 69)), "move1") ), _inputParser.Parse("234,123move1")); Assert.IsNull(_inputParser.Parse("234,123+move1")); } @@ -218,17 +224,17 @@ public void TestAnalog() .LengthRestrictions(maxSetLength: 2, maxSequenceLength: 4) .Build(); - Assert.AreEqual(Seq( - new InputSet(ImmutableList.Create(new Input("a", "a", "a"))), - new InputSet(ImmutableList.Create(new AnalogInput("up", "up", "up.2", 0.2f))), - new InputSet(ImmutableList.Create(new AnalogInput("up", "up", "up.2", 0.2f))), - new InputSet(ImmutableList.Create(new Input("a", "a", "a"))) + Assert.AreEqual(Seq("aup.22a", + new InputSet(ImmutableList.Create(new Input("a", "a", "a")), "a"), + new InputSet(ImmutableList.Create(new AnalogInput("up", "up", "up.2", 0.2f)), "up.2"), + new InputSet(ImmutableList.Create(new AnalogInput("up", "up", "up.2", 0.2f)), "up.2"), + new InputSet(ImmutableList.Create(new Input("a", "a", "a")), "a") ), _inputParser.Parse("aup.22a")); - Assert.AreEqual(Seq( - new InputSet(ImmutableList.Create(new AnalogInput("up", "up", "UP", 1.0f))) + Assert.AreEqual(Seq("UP", + new InputSet(ImmutableList.Create(new AnalogInput("up", "up", "UP", 1.0f)), "UP") ), _inputParser.Parse("UP")); - Assert.AreEqual(Seq( - new InputSet(ImmutableList.Create(new AnalogInput("up", "up", "up.9", 0.9f))) + Assert.AreEqual(Seq("up.9", + new InputSet(ImmutableList.Create(new AnalogInput("up", "up", "up.9", 0.9f)), "up.9") ), _inputParser.Parse("up.9")); Assert.IsNull(_inputParser.Parse("up.")); Assert.IsNull(_inputParser.Parse("up.0")); @@ -248,17 +254,19 @@ public void TestRetainCase() .Build(); Assert.AreEqual( - Seq(new InputSet(ImmutableList.Create(new Input("A", "A", "a")))), _inputParser.Parse("a")); + Seq("a", new InputSet(ImmutableList.Create(new Input("A", "A", "a")), "a")), _inputParser.Parse("a")); Assert.AreEqual( - Seq(new InputSet(ImmutableList.Create(new Input("B", "X", "b")))), _inputParser.Parse("b")); + Seq("b", new InputSet(ImmutableList.Create(new Input("B", "X", "b")), "b")), _inputParser.Parse("b")); Assert.AreEqual( - Seq(new InputSet(ImmutableList.Create(new Input("Y", "Y", "c")))), _inputParser.Parse("c")); + Seq("c", new InputSet(ImmutableList.Create(new Input("Y", "Y", "c")), "c")), _inputParser.Parse("c")); Assert.AreEqual( - Seq(new InputSet(ImmutableList.Create(new AnalogInput("UP", "UP", "up.2", 0.2f)))), + Seq("up.2", + new InputSet(ImmutableList.Create(new AnalogInput("UP", "UP", "up.2", 0.2f)), "up.2")), _inputParser.Parse("up.2")); Assert.AreEqual( - Seq(new InputSet( - ImmutableList.Create(new TouchscreenInput("MOVE1", "touchscreen", "move1", 10, 20)))), + Seq("move1", new InputSet( + ImmutableList.Create(new TouchscreenInput("MOVE1", "touchscreen", "move1", 10, 20)), + "move1")), _inputParser.Parse("move1")); } } diff --git a/tests/TPP.Inputting.Tests/Parsing/ContextualInputParserTest.cs b/tests/TPP.Inputting.Tests/Parsing/ContextualInputParserTest.cs index b4583b4b..d4e44420 100644 --- a/tests/TPP.Inputting.Tests/Parsing/ContextualInputParserTest.cs +++ b/tests/TPP.Inputting.Tests/Parsing/ContextualInputParserTest.cs @@ -11,9 +11,10 @@ namespace TPP.Inputting.Tests.Parsing public class ContextualInputParserTest { private static InputSet Set(params string[] inputs) => - new(inputs.Select(s => new Input(s, s, s)).ToImmutableList()); + new(inputs.Select(s => new Input(s, s, s)).ToImmutableList(), string.Join('+', inputs)); - private static InputSequence Seq(params InputSet[] inputSets) => new(inputSets.ToImmutableList()); + private static InputSequence Seq(params InputSet[] inputSets) => + new(inputSets.ToImmutableList(), string.Join("", inputSets.Select(set => set.OriginalText))); private IInputParser _inputParser = null!; @@ -48,12 +49,14 @@ public void TestMultitouch() .Build(); Assert.AreEqual(Seq(new InputSet(ImmutableList.Create( - new TouchscreenInput("234,123", "touchscreen", "234,123", 234, 123), - new TouchscreenInput("11,22", "touchscreen", "11,22", 11, 22))) + new TouchscreenInput("234,123", "touchscreen", "234,123", 234, 123), + new TouchscreenInput("11,22", "touchscreen", "11,22", 11, 22)), + "234,123+11,22") ), _inputParser.Parse("234,123+11,22")); Assert.AreEqual(Seq(new InputSet(ImmutableList.Create( - new TouchscreenInput("234,123", "touchscreen", "234,123", 234, 123), - new TouchscreenDragInput("11,22>33,44", "touchscreen", "11,22>33,44", 11, 22, 33, 44))) + new TouchscreenInput("234,123", "touchscreen", "234,123", 234, 123), + new TouchscreenDragInput("11,22>33,44", "touchscreen", "11,22>33,44", 11, 22, 33, 44)), + "234,123+11,22>33,44") ), _inputParser.Parse("234,123+11,22>33,44")); // multitouch disabled