diff --git a/libraries/Bot.Builder.Community.Adapters.Alexa.Core/Helpers/AlexaMarkdownToPlaintextRenderer.cs b/libraries/Bot.Builder.Community.Adapters.Alexa.Core/Helpers/AlexaMarkdownToPlaintextRenderer.cs index 8e95c695..2f165be4 100644 --- a/libraries/Bot.Builder.Community.Adapters.Alexa.Core/Helpers/AlexaMarkdownToPlaintextRenderer.cs +++ b/libraries/Bot.Builder.Community.Adapters.Alexa.Core/Helpers/AlexaMarkdownToPlaintextRenderer.cs @@ -1,5 +1,4 @@ -using System; -using Microsoft.MarkedNet; +using Microsoft.MarkedNet; namespace Bot.Builder.Community.Adapters.Alexa.Core.Helpers { @@ -8,7 +7,7 @@ namespace Bot.Builder.Community.Adapters.Alexa.Core.Helpers /// public static class AlexaMarkdownToPlaintextRenderer { - private static readonly Marked _marked = new Marked(new Options { Renderer = new RemoveMarkupRenderer() }); + private static readonly Marked _marked = new Marked(new Options { EscapeHtml = false, Sanitize = false, Mangle = false, Renderer = new RemoveMarkupRenderer() }); public static string Render(string source) => _marked.Parse(source); @@ -16,6 +15,9 @@ private class RemoveMarkupRenderer : MarkdownRenderer { private const string ListItemMarker = "$$ListItemMarker$$"; + public RemoveMarkupRenderer() : base() { } + public RemoveMarkupRenderer(Options options) : base(options) { } + public override string Blockquote(string quote) => string.Concat(quote, ". "); public override string Br() => ". "; public override string Code(string code, string lang, bool escaped) => code; @@ -26,7 +28,19 @@ private class RemoveMarkupRenderer : MarkdownRenderer public override string Hr() => ". "; public override string Html(string html) => string.Empty; public override string Image(string href, string title, string text) => title ?? text; - public override string Link(string href, string title, string text) => $"{title ?? text} {href}"; + public override string Link(string href, string title, string text) + { + if (title != null) + { + return $"{title} {href}"; + } + else if (text == href) + { + // For standard links the title and href will be the same. + return href; + } + return $"{text} {href}"; + } public override string List(string body, bool ordered, int start) { if (ordered) @@ -43,11 +57,14 @@ public override string List(string body, bool ordered, int start) return $"{body.Trim().TrimEnd(',')}. "; } public override string ListItem(string text) => $"{ListItemMarker}{text}, "; - public override string Paragraph(string text) => string.Concat(text.TrimEnd('.'), ". "); + public override string Paragraph(string text) => string.Concat(text.Replace("\n", " ").TrimEnd('.'), ". "); public override string Strong(string text) => text; public override string Table(string header, string body) => string.Empty; public override string TableCell(string content, TableCellFlags flags) => string.Empty; - public override string TableRow(string content) => string.Empty; + public override string TableRow(string content) => string.Empty; + public override string Text(string text) => text.TrimEnd('.'); + public override string Preprocess(string text) => text.Trim(); + public override string Postprocess(string text) => text.Trim(); } } } diff --git a/tests/Bot.Builder.Community.Adapters.Alexa.Tests/AlexaMarkdownToPlaintextRendererTests.cs b/tests/Bot.Builder.Community.Adapters.Alexa.Tests/AlexaMarkdownToPlaintextRendererTests.cs new file mode 100644 index 00000000..bcc62379 --- /dev/null +++ b/tests/Bot.Builder.Community.Adapters.Alexa.Tests/AlexaMarkdownToPlaintextRendererTests.cs @@ -0,0 +1,73 @@ +using Bot.Builder.Community.Adapters.Alexa.Core.Helpers; +using Xunit; + +namespace Bot.Builder.Community.Adapters.Alexa.Tests +{ + public class AlexaMarkdownToPlaintextRendererTests + { + [Fact] + public void ConvertTextWithTrailingPeriod() + { + var md = "Text text."; + var result = AlexaMarkdownToPlaintextRenderer.Render(md); + Assert.Equal(md, result); + } + + [Fact] + public void ConvertTextWithNoTrailingPeriod() + { + var md = "Text text"; + var result = AlexaMarkdownToPlaintextRenderer.Render(md); + // Trailing period is added because it is a paragraph. Alexa TTS doesn't mind either way. + Assert.Equal("Text text.", result); + } + + [Fact] + public void ConvertTextLeadingTrailingWhitespace() + { + var md = " Text text "; + var result = AlexaMarkdownToPlaintextRenderer.Render(md); + Assert.Equal("Text text.", result); + } + + [Fact] + public void ConvertTextTrailingNewline() + { + var md = "Text text\n"; + var result = AlexaMarkdownToPlaintextRenderer.Render(md); + Assert.Equal("Text text.", result); + } + + [Fact] + public void ConvertTextNoTrailingNewline() + { + var md = "Text text"; + var result = AlexaMarkdownToPlaintextRenderer.Render(md); + Assert.Equal("Text text.", result); + } + + [Fact] + public void ConvertTextBrAndParagraphs() + { + var md = "Same line.\nSame line. \n2nd line.\n\r3rd line."; + var result = AlexaMarkdownToPlaintextRenderer.Render(md); + Assert.Equal("Same line. Same line. 2nd line. 3rd line.", result); + } + + [Fact] + public void ConvertTextBrAndParagraphsNoSpacesBetween() + { + var md = "Same line.\nSame line.\n2nd line.\n\r3rd line."; + var result = AlexaMarkdownToPlaintextRenderer.Render(md); + Assert.Equal("Same line. Same line. 2nd line. 3rd line.", result); + } + + [Fact] + public void ConvertQuotesAndUrls() + { + var md = "{ \"contentType\": \"image/jpeg\", \"content\": \"https://somefantasticurl/\", \"name\": \"Attachment1.jpg\" }"; + var result = AlexaMarkdownToPlaintextRenderer.Render(md); + Assert.Equal("{ \"contentType\": \"image/jpeg\", \"content\": \"https://somefantasticurl/\", \"name\": \"Attachment1.jpg\" }.", result); + } + } +} diff --git a/tests/Bot.Builder.Community.Adapters.Alexa.Tests/AlexaRequestMapperTests.cs b/tests/Bot.Builder.Community.Adapters.Alexa.Tests/AlexaRequestMapperTests.cs index 6cec8c68..9bcc8361 100644 --- a/tests/Bot.Builder.Community.Adapters.Alexa.Tests/AlexaRequestMapperTests.cs +++ b/tests/Bot.Builder.Community.Adapters.Alexa.Tests/AlexaRequestMapperTests.cs @@ -1,23 +1,23 @@ +using System.Collections.Generic; +using System.Text; using Alexa.NET.Request; using Alexa.NET.Request.Type; using Alexa.NET.Response; -using Bot.Builder.Community.Adapters.Alexa.Core; -using Microsoft.Bot.Builder; -using Microsoft.Bot.Schema; -using Microsoft.Extensions.Logging; -using Moq; -using System.Collections.Generic; -using System.Text; using Alexa.NET.Response.Directive; using Alexa.NET.Response.Directive.Templates; using Alexa.NET.Response.Directive.Templates.Types; +using Bot.Builder.Community.Adapters.Alexa.Core; using Bot.Builder.Community.Adapters.Alexa.Core.Attachments; using Bot.Builder.Community.Adapters.Alexa.Tests.Helpers; using FluentAssertions.Common; +using Microsoft.Bot.Builder; +using Microsoft.Bot.Builder.Integration.AspNet.Core; +using Microsoft.Bot.Schema; +using Microsoft.Extensions.Logging; +using Moq; using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using Xunit; - + namespace Bot.Builder.Community.Adapters.Alexa.Tests { public class AlexaRequestMapperTests @@ -100,6 +100,25 @@ public void MergeActivitiesReturnsCorrectlyJoinedText() Assert.Equal("This is the first activity. This is the second activity", processActivityResult.Text); } + [Fact] + public void MergeActivitiesAttachmentAndPlainText() + { + var alexaAdapter = new AlexaRequestMapper(); + + var attachment = new Attachment + { + Name = "Attachment1.jpg", + ContentType = "image/jpeg", + Content = "https://somefantasticurl/", + }; + var firstActivity = MessageFactory.Text(JsonConvert.SerializeObject(attachment, HttpHelper.BotMessageSerializerSettings)); + var secondActivity = (Activity) MessageFactory.Attachment(attachment); + + var processActivityResult = alexaAdapter.MergeActivities(new List { firstActivity, secondActivity }); + + Assert.Equal("{ \"contentType\": \"image/jpeg\", \"content\": \"https://somefantasticurl/\", \"name\": \"Attachment1.jpg\" }", processActivityResult.Text); + } + [Fact] public void MergeActivitiesMergesAttachments() {