Exercise 6: Test cases

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Plato.Core;
using Plato.Language;
using Plato.Language.Parser;

namespace Tests
{
    [TestFixture]
    public class Exercise6
    {
        Brain brain;
        TransformationParserHelper parser;
        IEntity noun;
        IEntity speaker;

        [SetUp]
        public void SetUp()
        {
            brain = new Brain();
            parser = new TransformationParserHelper(brain);

            noun = brain.CreateEntity("noun");
            Assert.IsNotNull(noun);
            speaker = brain.CreateEntity("speaker");
            Assert.IsNotNull(speaker);
        }

        /// <summary>
        /// Ensure the parser can parse literal tokens in the
        /// input specification.
        /// </summary>
        [Test]
        public void TransInput_LiteralToken()
        {
            TransInput input = parser.ParseTransInputHelper("abc");

            Assert.AreEqual(TokenType.Literal, input.Tokens[0].TokenType);
            Assert.AreEqual("abc", input.Tokens[0].ToString());
        }

        /// <summary>
        /// Ensure the parser can parse entity type tokens in the
        /// input specification.
        /// </summary>
        [Test]
        public void TransInput_EntityTypeToken()
        {
            TransInput input = parser.ParseTransInputHelper("{noun}");

            Assert.AreEqual(TokenType.EntityType, input.Tokens[0].TokenType);
            Assert.AreEqual("noun", input.Tokens[0].ToString());
        }

        /// <summary>
        /// Ensure the parser can parse variable tokens.
        /// </summary>
        [Test]
        public void VariableToken()
        {
            VariableToken token = parser.ParseVariableTokenHelper("$1");

            Assert.AreEqual(1, token.VariableNumber);
        }

        /// <summary>
        /// Ensure the parser can parse property tokens.
        /// </summary>
        [Test]
        public void PropertyToken()
        {
            PropertyToken token = parser.ParsePropertyHelper("$1.$2");

            Assert.AreEqual(1, ((VariableToken)token.Path[0]).VariableNumber);
            Assert.AreEqual(2, ((VariableToken)token.Path[1]).VariableNumber);
        }

        /// <summary>
        /// Ensure the parser can parse property tokens.
        /// </summary>
        [Test]
        public void PropertyToken2()
        {
            PropertyToken token = parser.ParsePropertyHelper("speaker.$1");

            Assert.AreEqual("speaker", ((EntityToken)token.Path[0]).Entity.Id);
            Assert.AreEqual(1, ((VariableToken)token.Path[1]).VariableNumber);
        }

        /// <summary>
        /// Ensure the parser can parse property tokens which contain
        /// fragments.
        /// </summary>
        [Test]
        public void PropertyToken_WithFragment()
        {
            PropertyToken token = parser.ParsePropertyHelper("$1.$2.(($3 $4))");

            Assert.AreEqual(TokenType.Fragment, token.Path[2].TokenType);
            Assert.AreEqual(3, ((VariableToken)((FragmentToken)
                token.Path[2]).Fragment.Tokens[0]).VariableNumber);
            Assert.AreEqual(4, ((VariableToken)((FragmentToken)
                token.Path[2]).Fragment.Tokens[1]).VariableNumber);
        }

        /// <summary>
        /// Ensure the parser can parse transformation output
        /// specifications that are assignments.
        /// </summary>
        [Test]
        public void TransOutput_Assignment()
        {
            TransOutput_Assignment assignment =
                parser.ParseTransOutputAssignmentHelper("speaker.$1 = $2");

            Assert.AreEqual("speaker", ((EntityToken)assignment.Property.Path[0]).Entity.Id);
            Assert.AreEqual(1, ((VariableToken)assignment.Property.Path[1]).VariableNumber);
            Assert.AreEqual(2, ((VariableToken)assignment.Value).VariableNumber);
            Assert.AreEqual("speaker.$1 = $2", assignment.ToString());
        }

        /// <summary>
        /// Ensure the parser can parse transformation output
        /// specifications that are values.
        /// </summary>
        [Test]
        public void TransOutput_Value()
        {
            TransOutput_Value value =
                parser.ParseTransOutputValueHelper("speaker.$1");

            Assert.AreEqual("speaker", ((EntityToken)value.Property.Path[0]).Entity.Id);
            Assert.AreEqual(1, ((VariableToken)value.Property.Path[1]).VariableNumber);
            Assert.AreEqual("speaker.$1", value.ToString());
        }

        /// <summary>
        /// Ensure the parser can parse transformations.
        /// </summary>
        [Test]
        public void Transformation1()
        {
            IList<Transformation> transformations =
                parser.Parse("my {noun} -> speaker.$1");
            Transformation t = transformations[0];

            TransInput input = t.Input;
            TransOutput_Value output = (TransOutput_Value)t.Output;

            Assert.AreEqual(TokenType.Literal, input.Tokens[0].TokenType);
            Assert.AreEqual("my", input.Tokens[0].ToString());
            Assert.AreEqual(TokenType.EntityType, input.Tokens[1].TokenType);
            Assert.AreEqual("noun", input.Tokens[1].ToString());
            Assert.AreEqual(TokenType.Entity, output.Property.Path[0].TokenType);
            Assert.AreEqual("speaker", output.Property.Path[0].ToString());
            Assert.AreEqual(TokenType.Variable, output.Property.Path[1].TokenType);
            Assert.AreEqual("$1", output.Property.Path[1].ToString());
        }

        /// <summary>
        /// Ensure the parser can parse transformations.
        /// </summary>
        [Test]
        public void Transformation2()
        {
            IEntity word = brain.CreateEntity("word");

            IList<Transformation> transformations =
                parser.Parse("{noun} is {word} -> $1 = $2");
            Transformation t = transformations[0];

            TransInput input = t.Input;
            TransOutput_Assignment output = (TransOutput_Assignment)t.Output;

            Assert.AreEqual(TokenType.EntityType, input.Tokens[0].TokenType);
            Assert.AreEqual("noun", input.Tokens[0].ToString());
            Assert.AreEqual(TokenType.Literal, input.Tokens[1].TokenType);
            Assert.AreEqual("is", input.Tokens[1].ToString());
            Assert.AreEqual(TokenType.EntityType, input.Tokens[2].TokenType);
            Assert.AreEqual("word", input.Tokens[2].ToString());
            Assert.AreEqual(TokenType.Variable, output.Property.Path[0].TokenType);
            Assert.AreEqual("$1", output.Property.Path[0].ToString());
            Assert.AreEqual(TokenType.Variable, output.Value.TokenType);
            Assert.AreEqual("$2", output.Value.ToString());
        }

        /// <summary>
        /// Ensure the parser returns an error if the '->' is missing.
        /// </summary>
        [Test]
        [ExpectedException(typeof(MissingArrowException))]
        public void MissingArrow()
        {
            parser.Parse("abc");
        }

        /// <summary>
        /// Ensure the parser returns an error if there are too
        /// many '->' tokens.
        /// </summary>
        [Test]
        [ExpectedException(typeof(TooManyArrowsException))]
        public void TooManyArrows()
        {
            parser.Parse("abc -> def -> ghi");
        }

        /// <summary>
        /// Ensure the parser returns an error if the input
        /// specification is empty.
        /// </summary>
        [Test]
        [ExpectedException(typeof(EmptyInputException))]
        public void EmptyInput()
        {
            parser.Parse(" -> def");
        }

        /// <summary>
        /// Ensure the parser returns an error if the input
        /// specification contains an entity type that is
        /// missing its closing brace.
        /// </summary>
        [Test]
        [ExpectedException(typeof(MissingClosingBraceException))]
        public void MissingClosingBrace()
        {
            parser.Parse("{abc -> def");
        }

        /// <summary>
        /// Ensure the parser returns an error if the input
        /// specification contains an entity type that does
        /// not exist.
        /// </summary>
        [Test]
        [ExpectedException(typeof(EntityNotFoundException))]
        public void EntityNotFound()
        {
            parser.Parse("{abc} -> def");
        }

        /// <summary>
        /// Ensure the parser returns an error if the variable
        /// token is invalid.
        /// </summary>
        [Test]
        [ExpectedException(typeof(InvalidVariableTokenException))]
        public void InvalidVariableToken()
        {
            parser.ParseVariableTokenHelper("$");
        }

        /// <summary>
        /// Ensure the parser returns an error if the variable
        /// token is invalid.
        /// </summary>
        [Test]
        [ExpectedException(typeof(InvalidVariableTokenException))]
        public void InvalidVariableToken2()
        {
            parser.ParseVariableTokenHelper("$a");
        }

        /// <summary>
        /// Ensure the parser returns an error if the property
        /// token contains empty tokens.
        /// </summary>
        [Test]
        [ExpectedException(typeof(InvalidPropertyException))]
        public void InvalidProperty()
        {
            parser.ParsePropertyHelper(".b");
        }

        /// <summary>
        /// Ensure the parser returns an error if the property
        /// token contains an entity that does not exist.
        /// </summary>
        [Test]
        [ExpectedException(typeof(EntityNotFoundException))]
        public void InvalidProperty_EntityNotFound()
        {
            parser.ParsePropertyHelper("a.b");
        }

        /// <summary>
        /// Ensure the parser returns an error if the property
        /// token contains an invalid fragment.
        /// </summary>
        [Test]
        [ExpectedException(typeof(InvalidTokenException))]
        public void InvalidProperty_InvalidFragment()
        {
            parser.ParsePropertyHelper("((b)");
        }
    }

    public class TransformationParserHelper : TransformationParser
    {
        public TransformationParserHelper(Brain brain)
            : base(brain)
        {
        }

        // Allow access to this method for testing.
        public TransInput ParseTransInputHelper(string str)
        {
            return ParseTransInput(str);
        }

        // Allow access to this method for testing.
        public VariableToken ParseVariableTokenHelper(string token)
        {
            return ParseVariableToken(token);
        }

        // Allow access to this method for testing.
        public PropertyToken ParsePropertyHelper(string str)
        {
            return ParseProperty(str);
        }

        // Allow access to this method for testing.
        public TransOutput_Assignment ParseTransOutputAssignmentHelper(string str)
        {
            return ParseTransOutput_Assignment(str);
        }

        // Allow access to this method for testing.
        public TransOutput_Value ParseTransOutputValueHelper(string str)
        {
            return ParseTransOutput_Value(str);
        }
    }
}