/// <summary>
 ///     Parses the arguments.
 /// </summary>
 /// <param name="request">
 ///     The request.
 /// </param>
 /// <returns>
 ///     The <see cref="ParsedArguments" />.
 /// </returns>
 protected internal ParsedArguments ParseArguments(FormatterRequest request)
 {
     int index;
     var extensions = this.ParseExtensions(request, out index);
     var keyedBlocks = this.ParseKeyedBlocks(request, index);
     return new ParsedArguments(keyedBlocks, extensions);
 }
Example #2
0
        /// <summary>
        ///     Parses the arguments.
        /// </summary>
        /// <param name="request">
        ///     The request.
        /// </param>
        /// <returns>
        ///     The <see cref="ParsedArguments" />.
        /// </returns>
        protected internal ParsedArguments ParseArguments(FormatterRequest request)
        {
            int index;
            var extensions  = this.ParseExtensions(request, out index);
            var keyedBlocks = this.ParseKeyedBlocks(request, index);

            return(new ParsedArguments(keyedBlocks, extensions));
        }
Example #3
0
        /// <summary>
        ///     Parses the extensions.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <param name="index">The index.</param>
        /// <returns>The formatter extensions.</returns>
        protected internal IEnumerable <FormatterExtension> ParseExtensions(FormatterRequest request, out int index)
        {
            var result = new List <FormatterExtension>();
            int length = request.FormatterArguments.Length;

            index = 0;

            var extension = new StringBuilder();
            var value     = new StringBuilder();

            const char Colon          = ':';
            bool       foundExtension = false;

            for (int i = 0; i < length; i++)
            {
                var c = request.FormatterArguments[i];

                // Whitespace is tolerated at the beginning.
                bool isWhiteSpace = char.IsWhiteSpace(c);
                if (isWhiteSpace)
                {
                    // We've reached the end
                    if (value.Length > 0)
                    {
                        foundExtension = false;
                        result.Add(new FormatterExtension(extension.ToString(), value.ToString()));
                        extension.Clear();
                        value.Clear();
                        index = i;
                        continue;
                    }

                    if (extension.Length > 0)
                    {
                        // It's not an extension, so we're done looking.
                        break;
                    }

                    continue;
                }

                if (c == Colon)
                {
                    foundExtension = true;
                    continue;
                }

                if (foundExtension)
                {
                    value.Append(c);
                    continue;
                }

                extension.Append(c);
            }

            return(result);
        }
        /// <summary>
        ///     Parses the extensions.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <param name="index">The index.</param>
        /// <returns>The formatter extensions.</returns>
        protected internal IEnumerable<FormatterExtension> ParseExtensions(FormatterRequest request, out int index)
        {
            var result = new List<FormatterExtension>();
            int length = request.FormatterArguments.Length;
            index = 0;

            var extension = new StringBuilder();
            var value = new StringBuilder();

            const char Colon = ':';
            bool foundExtension = false;
            for (int i = 0; i < length; i++)
            {
                var c = request.FormatterArguments[i];

                // Whitespace is tolerated at the beginning.
                bool isWhiteSpace = char.IsWhiteSpace(c);
                if (isWhiteSpace)
                {
                    // We've reached the end
                    if (value.Length > 0)
                    {
                        foundExtension = false;
                        result.Add(new FormatterExtension(extension.ToString(), value.ToString()));
                        extension.Clear();
                        value.Clear();
                        index = i;
                        continue;
                    }

                    if (extension.Length > 0)
                    {
                        // It's not an extension, so we're done looking.
                        break;
                    }

                    continue;
                }

                if (c == Colon)
                {
                    foundExtension = true;
                    continue;
                }

                if (foundExtension)
                {
                    value.Append(c);
                    continue;
                }

                extension.Append(c);
            }

            return result;
        }
 /// <summary>
 ///     Builds the message.
 /// </summary>
 /// <param name="request">
 ///     The request.
 /// </param>
 /// <returns>
 ///     The <see cref="string" />.
 /// </returns>
 private static string BuildMessage(FormatterRequest request)
 {
     return
         string.Format(
             "Format '{0}' could not be resolved.\r\n" + "Line {1}, position {2}\r\n" + "Source literal: '{3}'", 
             request.FormatterName, 
             request.SourceLiteral.SourceLineNumber, 
             request.SourceLiteral.SourceColumnNumber, 
             request.SourceLiteral.InnerText);
 }
Example #6
0
        /// <summary>
        ///     Gets the formatter to use. If none was found, throws an exception.
        /// </summary>
        /// <param name="request">
        ///     The request.
        /// </param>
        /// <returns>
        ///     The <see cref="IFormatter" />.
        /// </returns>
        /// <exception cref="FormatterNotFoundException">
        ///     Thrown when the formatter was not found.
        /// </exception>
        public IFormatter GetFormatter(FormatterRequest request)
        {
            var formatter = this.FirstOrDefault(x => x.CanFormat(request));

            if (formatter == null)
            {
                throw new FormatterNotFoundException(request);
            }

            return(formatter);
        }
 public void Format(string formatterArgs, string keyToUse, string expectedBlock)
 {
     var subject = new SelectFormatter();
     var messageFormatterMock = new Mock<IMessageFormatter>();
     messageFormatterMock.Setup(x => x.FormatMessage(It.IsAny<string>(), It.IsAny<Dictionary<string, object>>()))
                         .Returns((string input, Dictionary<string, object> a) => input);
     var req = new FormatterRequest(
         new Literal(1, 1, 1, 1, new StringBuilder()), 
         "gender", 
         "select", 
         formatterArgs);
     var args = new Dictionary<string, object> { { "gender", keyToUse } };
     var result = subject.Format("en", req, args, messageFormatterMock.Object);
     Assert.Equal(expectedBlock, result);
 }
 public void Pluralize(double n, string expected)
 {
     var subject = new PluralFormatter();
     var args = new Dictionary<string, object> { { "test", n } };
     var arguments =
         new ParsedArguments(
             new[]
             {
                 new KeyedBlock("zero", "nothing"), new KeyedBlock("one", "just one"), 
                 new KeyedBlock("other", "wow")
             }, 
             new FormatterExtension[0]);
     var request = new FormatterRequest(new Literal(1, 1, 1, 1, new StringBuilder()), "test", "plural", null);
     var actual = subject.Pluralize("en", arguments, Convert.ToDouble(args[request.Variable]), 0);
     Assert.Equal(expected, actual);
 }
        public void GetFormatter()
        {
            var subject = new FormatterLibrary();
            var mock1 = new Mock<IFormatter>();
            var mock2 = new Mock<IFormatter>();

            var req = new FormatterRequest(new Literal(1, 1, 1, 1, new StringBuilder()), "test", "dawg", null);
            subject.Add(mock1.Object);
            subject.Add(mock2.Object);

            Assert.Throws<FormatterNotFoundException>(() => subject.GetFormatter(req));

            mock2.Setup(x => x.CanFormat(req)).Returns(true);
            var actual = subject.GetFormatter(req);
            Assert.Same(mock2.Object, actual);

            mock1.Setup(x => x.CanFormat(req)).Returns(true);
            actual = subject.GetFormatter(req);
            Assert.Same(mock1.Object, actual);
        }
 /// <summary>
 ///     Initializes a new instance of the <see cref="FormatterNotFoundException" /> class.
 /// </summary>
 /// <param name="request">
 ///     The request.
 /// </param>
 public FormatterNotFoundException(FormatterRequest request)
     : base(BuildMessage(request))
 {
 }
        public void ParseKeyedBlocks(string args, string[] keys, string[] values)
        {
            var subject = new BaseFormatterImpl();
            var req = new FormatterRequest(new Literal(1, 1, 1, 1, new StringBuilder()), null, null, args);

            // Warm-up
            subject.ParseKeyedBlocks(req, 0);

            Benchmark.Start("Parsing keyed blocks..", this.outputHelper);
            for (int i = 0; i < 10000; i++)
            {
                subject.ParseKeyedBlocks(req, 0);
            }

            Benchmark.End(this.outputHelper);

            var actual = subject.ParseKeyedBlocks(req, 0);
            Assert.Equal(keys.Length, actual.Count());
            this.outputHelper.WriteLine("Input: " + args);
            this.outputHelper.WriteLine("-----");
            for (int index = 0; index < actual.ToArray().Length; index++)
            {
                var keyedBlock = actual.ToArray()[index];
                var expectedKey = keys[index];
                var expectedValue = values[index];
                Assert.Equal(expectedKey, keyedBlock.Key);
                Assert.Equal(expectedValue, keyedBlock.BlockText);

                this.outputHelper.WriteLine("Key: " + keyedBlock.Key);
                this.outputHelper.WriteLine("Block: " + keyedBlock.BlockText);
            }
        }
Example #12
0
        /// <summary>
        ///     Parses the keyed blocks.
        /// </summary>
        /// <param name="request">
        ///     The request.
        /// </param>
        /// <param name="startIndex">
        ///     The start index.
        /// </param>
        /// <returns>
        ///     The keyed blocks.
        /// </returns>
        protected internal IEnumerable <KeyedBlock> ParseKeyedBlocks(FormatterRequest request, int startIndex)
        {
            const char OpenBrace    = '{';
            const char CloseBrace   = '}';
            const char EscapingChar = '\'';

            var result                  = new List <KeyedBlock>();
            var key                     = new StringBuilder();
            var block                   = new StringBuilder();
            var braceBalance            = 0;
            var foundWhitespaceAfterKey = false;
            var insideEscapeSequence    = false;

            if (request.FormatterArguments == null)
            {
                return(Enumerable.Empty <KeyedBlock>());
            }

            for (int i = startIndex; i < request.FormatterArguments.Length; i++)
            {
                var c            = request.FormatterArguments[i];
                var isWhitespace = char.IsWhiteSpace(c);

                if (c == EscapingChar)
                {
                    if (braceBalance == 0)
                    {
                        throw new MalformedLiteralException(
                                  "Expected a key, but found start of a escape sequence.",
                                  0,
                                  0,
                                  request.FormatterArguments);
                    }

                    if (i == request.FormatterArguments.Length - 1)
                    {
                        if (!insideEscapeSequence)
                        {
                            block.Append(EscapingChar);
                        }

                        // The last char can't open a new escape sequence, it can only close one
                        if (insideEscapeSequence)
                        {
                            insideEscapeSequence = false;
                        }
                        continue;
                    }

                    var nextChar = request.FormatterArguments[i + 1];
                    if (nextChar == EscapingChar)
                    {
                        block.Append(EscapingChar);
                        block.Append(EscapingChar);
                        ++i;
                        continue;
                    }

                    if (insideEscapeSequence)
                    {
                        block.Append(EscapingChar);
                        insideEscapeSequence = false;
                        continue;
                    }

                    if (nextChar == '{' || nextChar == '}' || nextChar == '#')
                    {
                        block.Append(EscapingChar);
                        block.Append(nextChar);
                        insideEscapeSequence = true;
                        ++i;
                        continue;
                    }

                    block.Append(EscapingChar);
                    continue;
                }

                if (insideEscapeSequence)
                {
                    block.Append(c);
                    continue;
                }

                if (c == OpenBrace)
                {
                    if (key.Length == 0)
                    {
                        throw new MalformedLiteralException(
                                  "Expected a key, but found start of a new block.",
                                  0,
                                  0,
                                  request.FormatterArguments);
                    }

                    braceBalance++;
                    if (braceBalance > 1)
                    {
                        block.Append(c);
                    }

                    continue;
                }

                if (c == CloseBrace)
                {
                    if (key.Length == 0)
                    {
                        throw new MalformedLiteralException(
                                  "Expected a key, but found end of a block.",
                                  0,
                                  0,
                                  request.FormatterArguments);
                    }

                    if (braceBalance == 0)
                    {
                        throw new MalformedLiteralException(
                                  "Found end of a block, but no block has been started, or the"
                                  + " block has already been closed. " + "This could indicate an unescaped brace somewhere.",
                                  0,
                                  0,
                                  request.FormatterArguments);
                    }

                    braceBalance--;
                    if (braceBalance == 0)
                    {
                        result.Add(new KeyedBlock(key.ToString(), block.ToString()));
                        block.Clear();
                        key.Clear();
                        foundWhitespaceAfterKey = false;
                        continue;
                    }

                    if (braceBalance < 0)
                    {
                        throw new MalformedLiteralException(
                                  "Expected '{', but found '}' - essentially this means there are more close braces than there are open braces.",
                                  0,
                                  0,
                                  request.FormatterArguments);
                    }
                }

                // If we are inside a block, append to the block buffer
                if (braceBalance > 0)
                {
                    block.Append(c);
                    continue;
                }

                // Else, we are buffering our key
                if (isWhitespace == false)
                {
                    if (foundWhitespaceAfterKey)
                    {
                        throw new MalformedLiteralException(
                                  "Any whitespace after a key should be followed by the beginning of a block.",
                                  0,
                                  0,
                                  request.FormatterArguments);
                    }

                    key.Append(c);
                }
                else if (key.Length > 0)
                {
                    foundWhitespaceAfterKey = true;
                }
            }

            if (insideEscapeSequence)
            {
                throw new MalformedLiteralException(
                          "There is an unclosed escape sequence.",
                          0,
                          0,
                          request.FormatterArguments);
            }

            if (braceBalance > 0)
            {
                throw new MalformedLiteralException(
                          "There are more open braces than there are close braces.",
                          0,
                          0,
                          request.FormatterArguments);
            }

            return(result);
        }
 /// <summary>
 ///     Creates the request.
 /// </summary>
 /// <returns>
 ///     The <see cref="FormatterRequest" />.
 /// </returns>
 private static FormatterRequest CreateRequest()
 {
     var req = new FormatterRequest(new Literal(1, 10, 1, 1, new StringBuilder()), "test", null, null);
     return req;
 }
        public void ParseArguments(
            string args, 
            string[] extensionKeys, 
            string[] extensionValues, 
            string[] keys, 
            string[] blocks)
        {
            var subject = new BaseFormatterImpl();
            var req = new FormatterRequest(new Literal(1, 1, 1, 1, new StringBuilder()), null, null, args);
            var actual = subject.ParseArguments(req);

            Assert.Equal(extensionKeys.Length, actual.Extensions.Count());
            Assert.Equal(keys.Length, actual.KeyedBlocks.Count());

            for (int i = 0; i < actual.Extensions.ToArray().Length; i++)
            {
                var extension = actual.Extensions.ToArray()[i];
                Assert.Equal(extensionKeys[i], extension.Extension);
                Assert.Equal(extensionValues[i], extension.Value);
            }

            for (int i = 0; i < actual.KeyedBlocks.ToArray().Length; i++)
            {
                var block = actual.KeyedBlocks.ToArray()[i];
                Assert.Equal(keys[i], block.Key);
                Assert.Equal(blocks[i], block.BlockText);
            }
        }
 public void ParseArguments_invalid(string args)
 {
     var subject = new BaseFormatterImpl();
     var req = new FormatterRequest(new Literal(1, 1, 1, 1, new StringBuilder()), null, null, args);
     var ex = Assert.Throws<MalformedLiteralException>(() => subject.ParseArguments(req));
     this.outputHelper.WriteLine(ex.Message);
 }
        public void ParseExtensions(string args, string extension, string value, int expectedIndex)
        {
            var subject = new BaseFormatterImpl();
            int index;
            var req = new FormatterRequest(new Literal(1, 1, 1, 1, new StringBuilder()), null, null, args);

            // Warmup
            subject.ParseExtensions(req, out index);

            Benchmark.Start("Parsing extensions a few times (warmed up)", this.outputHelper);
            for (int i = 0; i < 1000; i++)
            {
                subject.ParseExtensions(req, out index);
            }

            Benchmark.End(this.outputHelper);

            var actual = subject.ParseExtensions(req, out index);
            Assert.NotEmpty(actual);
            var first = actual.First();
            Assert.Equal(extension, first.Extension);
            Assert.Equal(value, first.Value);
            Assert.Equal(expectedIndex, index);
        }
        public void ParseExtensions_multiple()
        {
            var subject = new BaseFormatterImpl();
            int index;
            var args = " offset:2 code:js ";
            var expectedIndex = 17;

            var req = new FormatterRequest(new Literal(1, 1, 1, 1, new StringBuilder()), null, null, args);

            var actual = subject.ParseExtensions(req, out index);
            Assert.NotEmpty(actual);
            var result = actual.First();
            Assert.Equal("offset", result.Extension);
            Assert.Equal("2", result.Value);

            result = actual.ElementAt(1);
            Assert.Equal("code", result.Extension);
            Assert.Equal("js", result.Value);

            Assert.Equal(expectedIndex, index);
        }
        /// <summary>
        ///     Parses the keyed blocks.
        /// </summary>
        /// <param name="request">
        ///     The request.
        /// </param>
        /// <param name="startIndex">
        ///     The start index.
        /// </param>
        /// <returns>
        ///     The keyed blocks.
        /// </returns>
        protected internal IEnumerable<KeyedBlock> ParseKeyedBlocks(FormatterRequest request, int startIndex)
        {
            const char OpenBrace = '{';
            const char CloseBrace = '}';
            const char EscapingChar = '\\';

            var result = new List<KeyedBlock>();
            var key = new StringBuilder();
            var block = new StringBuilder();
            var braceBalance = 0;
            var foundWhitespaceAfterKey = false;
            for (int i = startIndex; i < request.FormatterArguments.Length; i++)
            {
                var c = request.FormatterArguments[i];
                var isWhitespace = char.IsWhiteSpace(c);

                if (c == OpenBrace)
                {
                    if (key.Length == 0)
                    {
                        throw new MalformedLiteralException(
                            "Expected a key, but found start of a new block.", 
                            0, 
                            0, 
                            request.FormatterArguments);
                    }

                    if (i != 0 && request.FormatterArguments[i - 1] == EscapingChar)
                    {
                        block.Append(c);
                        continue;
                    }

                    braceBalance++;
                    if (braceBalance > 1)
                    {
                        block.Append(c);
                    }

                    continue;
                }

                if (c == CloseBrace)
                {
                    if (key.Length == 0)
                    {
                        throw new MalformedLiteralException(
                            "Expected a key, but found end of a block.", 
                            0, 
                            0, 
                            request.FormatterArguments);
                    }

                    if (i != 0 && request.FormatterArguments[i - 1] == EscapingChar)
                    {
                        block.Append(c);
                        continue;
                    }

                    if (braceBalance == 0)
                    {
                        throw new MalformedLiteralException(
                            "Found end of a block, but no block has been started, or the"
                            + " block has already been closed. " + "This could indicate an unescaped brace somewhere.", 
                            0, 
                            0, 
                            request.FormatterArguments);
                    }

                    braceBalance--;
                    if (braceBalance == 0)
                    {
                        result.Add(new KeyedBlock(key.ToString(), block.ToString()));
                        block.Clear();
                        key.Clear();
                        foundWhitespaceAfterKey = false;
                        continue;
                    }

                    if (braceBalance < 0)
                    {
                        throw new MalformedLiteralException(
                            "Expected '{', but found '}' - essentially this means there are more close braces than there are open braces.", 
                            0, 
                            0, 
                            request.FormatterArguments);
                    }
                }

                // If we are inside a block, append to the block buffer
                if (braceBalance > 0)
                {
                    block.Append(c);
                    continue;
                }

                // Else, we are buffering our key
                if (isWhitespace == false)
                {
                    if (foundWhitespaceAfterKey)
                    {
                        throw new MalformedLiteralException(
                            "Any whitespace after a key should be followed by the beginning of a block.", 
                            0, 
                            0, 
                            request.FormatterArguments);
                    }

                    key.Append(c);
                }
                else if (key.Length > 0)
                {
                    foundWhitespaceAfterKey = true;
                }
            }

            if (braceBalance > 0)
            {
                throw new MalformedLiteralException(
                    "There are more open braces than there are close braces.", 
                    0, 
                    0, 
                    request.FormatterArguments);
            }

            return result;
        }