From 8752befaa5e935abe46e4958a56b66a28cf77906 Mon Sep 17 00:00:00 2001 From: Andrii Kurdiumov Date: Sun, 27 Apr 2025 08:22:59 +0500 Subject: [PATCH] Add iterator tests for ParseErrorElementDictionary --- .../Parser/ParseErrorElementDictionary.cs | 71 ++++++++++++++++++- .../Parser.Tests/ExpressionParserTests.cs | 5 +- .../Tests/Parser.Tests/ParseErrorTests.cs | 30 ++++++++ 3 files changed, 101 insertions(+), 5 deletions(-) diff --git a/Sources/SynKit/Libraries/Parser/ParseErrorElementDictionary.cs b/Sources/SynKit/Libraries/Parser/ParseErrorElementDictionary.cs index c908badb..3514534a 100644 --- a/Sources/SynKit/Libraries/Parser/ParseErrorElementDictionary.cs +++ b/Sources/SynKit/Libraries/Parser/ParseErrorElementDictionary.cs @@ -35,7 +35,9 @@ public ParseErrorElementDictionary(string key, ParseErrorElement value) ? this.elements is null ? throw new KeyNotFoundException($"The key {key} was not found in the dictionary") : this.elements[key] - : this.firstItem!; + : this.firstKey == key + ? this.firstItem! + : throw new KeyNotFoundException($"The key {key} was not found in the dictionary"); public IEnumerable Keys => this.firstKey is null ? this.elements!.Keys : new[] { this.firstKey }; @@ -44,8 +46,27 @@ public ParseErrorElementDictionary(string key, ParseErrorElement value) public int Count => this.firstKey is null ? this.elements is null ? 0 : this.elements.Count : 1; public bool ContainsKey(string key) => this.firstKey is null ? this.elements is null ? false : this.elements.ContainsKey(key) : this.firstKey == key; - public IEnumerator> GetEnumerator() => throw new NotImplementedException(); - public bool TryGetValue(string key, out ParseErrorElement value) => throw new NotImplementedException(); + public IEnumerator> GetEnumerator() => + this.elements is null + ? new Enumerator(this.firstKey!, this.firstItem!) + : this.elements.GetEnumerator(); + public bool TryGetValue(string key, out ParseErrorElement value) + { + if (this.elements is null) + { + if (this.firstKey == key) + { + value = firstItem; + return true; + } + + value = default; + return false; + } + + return this.elements.TryGetValue(key, out value); + } + IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); public ParseErrorElementDictionary Merge(ParseErrorElementDictionary other) @@ -91,4 +112,48 @@ public ParseErrorElementDictionary Merge(ParseErrorElementDictionary other) return new (elements); } + + private struct Enumerator : IEnumerator> + { + private bool valid; + private KeyValuePair _current; + public Enumerator(string key, ParseErrorElement value) + { + this._current = new KeyValuePair(key, value); + } + + public KeyValuePair Current + { + get + { + if (!valid) + { + throw new InvalidOperationException("The enumerator is not valid."); + } + + return _current; + } + } + + object IEnumerator.Current => this.Current; + + public void Dispose() {} + public bool MoveNext() + { + if (!this.valid) + { + this.valid = true; + return true; + } + else + { + this.valid = false; + return false; + } + } + public void Reset() + { + this.valid = false; + } + } } diff --git a/Sources/SynKit/Tests/Parser.Tests/ExpressionParserTests.cs b/Sources/SynKit/Tests/Parser.Tests/ExpressionParserTests.cs index 8045f5ea..a94c28d3 100644 --- a/Sources/SynKit/Tests/Parser.Tests/ExpressionParserTests.cs +++ b/Sources/SynKit/Tests/Parser.Tests/ExpressionParserTests.cs @@ -110,11 +110,12 @@ internal partial class Parser [InlineData(1, "(2 * 3 + 1 << 1 > 1 == 1 & 123 | 22 && 1 || 0) || (2 * 3 + 1 << 1 > 1 == 1 & 123 | 22 && 1 || 0)")] public void Tests(int value, string text) => Assert.Equal(value, Eval(text)); - [Fact(Timeout = 1000, Skip = "In order for this test to pass, BNF desuar should be refactored")] + [Fact] public async System.Threading.Tasks.Task LongExpressionParsedWithinExpectedTime() { await Task.Yield(); var text = "(((((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))) + ((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))))+(((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))) + ((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))))))))+((((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))) + ((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))))+(((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))) + ((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))))))))) + (((((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))) + ((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))))+(((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))) + ((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))))))))+((((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))) + ((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))))+(((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))) + ((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))))))"; - Assert.Equal(1536, Eval(text)); + var result = Eval(text); + Assert.Equal(1536, result); } } diff --git a/Sources/SynKit/Tests/Parser.Tests/ParseErrorTests.cs b/Sources/SynKit/Tests/Parser.Tests/ParseErrorTests.cs index 52a5ca19..0d3e6cad 100644 --- a/Sources/SynKit/Tests/Parser.Tests/ParseErrorTests.cs +++ b/Sources/SynKit/Tests/Parser.Tests/ParseErrorTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. // Source repository: https://github.com/LanguageDev/Yoakke +using System.Linq; using Xunit; namespace Yoakke.SynKit.Parser.Tests; @@ -82,4 +83,33 @@ public void MergeTwoErrorsFromDifferentExpressions() Assert.Equal(1, result.Elements["other_expression"].Expected.Count); Assert.True(result.Elements["other_expression"].Expected.Contains("^")); } + + [Fact] + public void EnumerateWhenSingleElement() + { + var firstError = new ParseError("^", null, 12, "expression"); + + var result = firstError.Elements.Single(); + + Assert.Equal("expression", result.Key); + Assert.Equal("expression", result.Value.Context); + Assert.True(result.Value.Expected.Contains("^")); + } + + [Fact] + public void EnumerateTwoElements() + { + var firstError = new ParseError("^", null, 12, "expression"); + var secondError = new ParseError("^", null, 12, "other_expression"); + var mergedError = firstError | secondError; + + var result = mergedError.Elements.ToList(); + + Assert.Equal("expression", result[0].Key); + Assert.Equal("expression", result[0].Value.Context); + Assert.True(result[0].Value.Expected.Contains("^")); + Assert.Equal("other_expression", result[1].Key); + Assert.Equal("other_expression", result[1].Value.Context); + Assert.True(result[1].Value.Expected.Contains("^")); + } }