From 034d3691d072ed9ca0ad9a855dc57f2d78d41e69 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 1 Oct 2015 21:56:55 +0200 Subject: [PATCH] Add tests for malformed binding expressions. --- .../Binding/Parsers/ArgumentListParser.cs | 8 +- .../Binding/Parsers/ExpressionParser.cs | 45 +++-------- .../Perspex.Markup/Binding/Parsers/Reader.cs | 13 ++++ .../Binding/ExpressionNodeBuilderTests.cs | 11 ++- .../ExpressionNodeBuilderTests_Errors.cs | 74 +++++++++++++++++++ 5 files changed, 111 insertions(+), 40 deletions(-) create mode 100644 tests/Perspex.Markup.UnitTests/Binding/ExpressionNodeBuilderTests_Errors.cs diff --git a/src/Markup/Perspex.Markup/Binding/Parsers/ArgumentListParser.cs b/src/Markup/Perspex.Markup/Binding/Parsers/ArgumentListParser.cs index 9d53c09453..bba9226a10 100644 --- a/src/Markup/Perspex.Markup/Binding/Parsers/ArgumentListParser.cs +++ b/src/Markup/Perspex.Markup/Binding/Parsers/ArgumentListParser.cs @@ -16,7 +16,7 @@ namespace Perspex.Markup.Binding.Parsers r.Take(); - while (!r.End && r.Peek != close) + while (!r.End) { var literal = LiteralParser.Parse(r); @@ -35,7 +35,11 @@ namespace Perspex.Markup.Binding.Parsers { throw new ExpressionParseException(r, "Expected ','."); } - if (r.Peek != close) + else if (r.TakeIf(close)) + { + return result; + } + else { if (r.Take() != ',') { diff --git a/src/Markup/Perspex.Markup/Binding/Parsers/ExpressionParser.cs b/src/Markup/Perspex.Markup/Binding/Parsers/ExpressionParser.cs index c344a41cda..300585f730 100644 --- a/src/Markup/Perspex.Markup/Binding/Parsers/ExpressionParser.cs +++ b/src/Markup/Perspex.Markup/Binding/Parsers/ExpressionParser.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; namespace Perspex.Markup.Binding.Parsers { @@ -28,19 +29,20 @@ namespace Perspex.Markup.Binding.Parsers case State.BeforeMember: state = ParseBeforeMember(r, nodes); break; - - default: - state = State.End; - break; } } + if (state == State.BeforeMember) + { + throw new ExpressionParseException(r, "Unexpected end of expression."); + } + for (int n = 0; n < nodes.Count - 1; ++n) { nodes[n].Next = nodes[n + 1]; } - return nodes[0]; + return nodes.FirstOrDefault(); } private static State ParseStart(Reader r, IList nodes) @@ -104,41 +106,12 @@ namespace Perspex.Markup.Binding.Parsers private static bool ParseNot(Reader r) { - if (!r.End && r.Peek == '!') - { - r.Take(); - return true; - } - else - { - return false; - } + return !r.End && r.TakeIf('!'); } private static bool ParseMemberAccessor(Reader r) { - if (!r.End && r.Peek == '.') - { - r.Take(); - return true; - } - else - { - return false; - } - } - - private static bool ParseIndexer(Reader r) - { - if (!r.End && r.Peek == '[') - { - r.Take(); - return true; - } - else - { - return false; - } + return !r.End && r.TakeIf('.'); } private enum State diff --git a/src/Markup/Perspex.Markup/Binding/Parsers/Reader.cs b/src/Markup/Perspex.Markup/Binding/Parsers/Reader.cs index b69d299ebb..34c2746487 100644 --- a/src/Markup/Perspex.Markup/Binding/Parsers/Reader.cs +++ b/src/Markup/Perspex.Markup/Binding/Parsers/Reader.cs @@ -27,5 +27,18 @@ namespace Perspex.Markup.Binding.Parsers Take(); } } + + public bool TakeIf(char c) + { + if (Peek == c) + { + Take(); + return true; + } + else + { + return false; + } + } } } diff --git a/tests/Perspex.Markup.UnitTests/Binding/ExpressionNodeBuilderTests.cs b/tests/Perspex.Markup.UnitTests/Binding/ExpressionNodeBuilderTests.cs index 623d6a6365..424586cf45 100644 --- a/tests/Perspex.Markup.UnitTests/Binding/ExpressionNodeBuilderTests.cs +++ b/tests/Perspex.Markup.UnitTests/Binding/ExpressionNodeBuilderTests.cs @@ -15,8 +15,15 @@ namespace Perspex.Markup.UnitTests.Binding { var result = ToList(ExpressionNodeBuilder.Build("Foo")); - Assert.Equal(1, result.Count); - Assert.IsType(result[0]); + AssertIsProperty(result[0], "Foo"); + } + + [Fact] + public void Should_Build_Underscored_Property() + { + var result = ToList(ExpressionNodeBuilder.Build("_Foo")); + + AssertIsProperty(result[0], "_Foo"); } [Fact] diff --git a/tests/Perspex.Markup.UnitTests/Binding/ExpressionNodeBuilderTests_Errors.cs b/tests/Perspex.Markup.UnitTests/Binding/ExpressionNodeBuilderTests_Errors.cs new file mode 100644 index 0000000000..d30bd097a7 --- /dev/null +++ b/tests/Perspex.Markup.UnitTests/Binding/ExpressionNodeBuilderTests_Errors.cs @@ -0,0 +1,74 @@ +// Copyright (c) The Perspex Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Perspex.Markup.Binding; +using Xunit; + +namespace Perspex.Markup.UnitTests.Binding +{ + public class ExpressionNodeBuilderTests_Errors + { + [Fact] + public void Identifier_Cannot_Start_With_Digit() + { + Assert.Throws( + () => ExpressionNodeBuilder.Build("1Foo")); + } + + [Fact] + public void Identifier_Cannot_Start_With_Symbol() + { + Assert.Throws( + () => ExpressionNodeBuilder.Build("Foo.%Bar")); + } + + [Fact] + public void Expression_Cannot_End_With_Period() + { + Assert.Throws( + () => ExpressionNodeBuilder.Build("Foo.Bar.")); + } + + [Fact] + public void Expression_Cannot_Have_Empty_Indexer() + { + Assert.Throws( + () => ExpressionNodeBuilder.Build("Foo.Bar[]")); + } + + [Fact] + public void Expression_Cannot_Have_Extra_Comma_At_Start_Of_Indexer() + { + Assert.Throws( + () => ExpressionNodeBuilder.Build("Foo.Bar[,3,4]")); + } + + [Fact] + public void Expression_Cannot_Have_Extra_Comma_In_Indexer() + { + Assert.Throws( + () => ExpressionNodeBuilder.Build("Foo.Bar[3,,4]")); + } + + [Fact] + public void Expression_Cannot_Have_Extra_Comma_At_End_Of_Indexer() + { + Assert.Throws( + () => ExpressionNodeBuilder.Build("Foo.Bar[3,4,]")); + } + + [Fact] + public void Expression_Cannot_Have_Digit_After_Indexer() + { + Assert.Throws( + () => ExpressionNodeBuilder.Build("Foo.Bar[3,4]5")); + } + + [Fact] + public void Expression_Cannot_Have_Letter_After_Indexer() + { + Assert.Throws( + () => ExpressionNodeBuilder.Build("Foo.Bar[3,4]A")); + } + } +}