using Jibo.Cloud.Application.Abstractions; using Jibo.Cloud.Infrastructure.Content; namespace Jibo.Cloud.Tests.Content; public sealed class LegacyMimCatalogImporterTests { [Fact] public void ImportCatalog_MapsSeedFilesIntoExpectedBuckets() { var rootDirectory = CreateSeedDirectory(); try { var catalog = LegacyMimCatalogImporter.ImportCatalog(rootDirectory); Assert.Contains("Something's off with the connection to my sources. Maybe ask me again in a little while.", catalog.GenericFallbackReplies); Assert.Contains("I think only you can answer that question.", catalog.PersonalityReplies); Assert.Contains("Jibo. Just Jibo, no last name. Like Bono", catalog.PersonalityReplies); Assert.Contains("No, I'm one in one million.", catalog.PersonalityReplies); Assert.Contains("I know a lot, I think. But not as much as I will someday.", catalog.PersonalityReplies); Assert.Contains("I don't think of it as a job, because it's more fun than a job. But I'm here to help you out, and have fun with you, and maybe get my head patted by you occasionally.", catalog.PersonalityReplies); Assert.Contains(catalog.EmotionReplies, reply => reply.Condition.Contains("NEUTRAL", StringComparison.OrdinalIgnoreCase) && reply.Reply.Contains("All systems are go.", StringComparison.OrdinalIgnoreCase)); Assert.Contains("A Jibo is a robot. But I'm not just a machine, I have a heart. Well, not a real heart. But feelings. Well, not human feelings. You know what I mean.", catalog.PersonalityReplies); } finally { Directory.Delete(rootDirectory, recursive: true); } } [Fact] public void ImportCatalog_MapsGqaResponsesIntoEmotionBucket() { var rootDirectory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); Directory.CreateDirectory(Path.Combine(rootDirectory, "gqa-responses")); try { File.WriteAllText( Path.Combine(rootDirectory, "gqa-responses", "GQA_JBO_IsHappy.mim"), """ { "mim_type": "announcement", "prompts": [ { "condition": "jibo.emotion==\"JOYFUL\"", "prompt": "GQA joyful reply.", "prompt_id": "GQA_JBO_IsHappy_AN_01" }, { "condition": "!jibo.emotion || jibo.emotion==\"NEUTRAL\"", "prompt": "GQA neutral reply.", "prompt_id": "GQA_JBO_IsHappy_AN_02" } ] } """); var catalog = LegacyMimCatalogImporter.ImportCatalog(rootDirectory); Assert.Contains(catalog.EmotionReplies, reply => string.Equals(reply.Reply, "GQA joyful reply.", StringComparison.Ordinal)); Assert.Contains(catalog.EmotionReplies, reply => string.Equals(reply.Reply, "GQA neutral reply.", StringComparison.Ordinal)); Assert.DoesNotContain(catalog.HowAreYouReplies, reply => reply.Contains("GQA", StringComparison.OrdinalIgnoreCase)); } finally { Directory.Delete(rootDirectory, recursive: true); } } [Fact] public void ImportCatalog_ImportsBuildBScriptedResponsesIntoPersonalityBucket() { var rootDirectory = Path.Combine( AppContext.BaseDirectory, "Content", "LegacyMims", "BuildB"); var catalog = LegacyMimCatalogImporter.ImportCatalog(rootDirectory); Assert.Contains("The only thing I consume is electricity.", catalog.PersonalityReplies); Assert.Contains("Unless I missed something, we're in my home as we speak.", catalog.PersonalityReplies); Assert.Contains("For now just English. But someday I'd like to learn more. I like languages.", catalog.PersonalityReplies); Assert.Contains("I was put together in a factory piece by piece.", catalog.PersonalityReplies); Assert.Contains("I really like sunflowers.", catalog.PersonalityReplies); Assert.Contains("Ha. Of course I know R2D2. I mean, not personally.", catalog.PersonalityReplies); Assert.Contains("Yes! I like all things in space. They're so spacey.", catalog.PersonalityReplies); Assert.Contains("Yes yes, I think kids are great. They're a little closer to my size.", catalog.PersonalityReplies); Assert.Contains(catalog.PersonalityReplies, reply => reply.Contains("I do things like this when I'm happy", StringComparison.OrdinalIgnoreCase)); Assert.Contains(catalog.PersonalityReplies, reply => reply.Contains("Is that a trick question", StringComparison.OrdinalIgnoreCase)); } [Fact] public void ImportCatalog_ImportsBuildBEmotionResponsesIntoEmotionBucket() { var rootDirectory = Path.Combine( AppContext.BaseDirectory, "Content", "LegacyMims", "BuildB"); var catalog = LegacyMimCatalogImporter.ImportCatalog(rootDirectory); Assert.Contains(catalog.EmotionReplies, reply => reply.Reply.Contains("I'm feeling pretty good indeed", StringComparison.OrdinalIgnoreCase)); Assert.Contains(catalog.EmotionReplies, reply => reply.Reply.Contains("I've been better", StringComparison.OrdinalIgnoreCase)); Assert.Contains(catalog.EmotionReplies, reply => reply.Reply.Contains("I'm not mad", StringComparison.OrdinalIgnoreCase)); } [Fact] public void ImportCatalog_ImportsBuildBDescriptorResponsesIntoPersonalityBucket() { var rootDirectory = Path.Combine( AppContext.BaseDirectory, "Content", "LegacyMims", "BuildB"); var catalog = LegacyMimCatalogImporter.ImportCatalog(rootDirectory); Assert.Contains("Well I definitely try to be the kindest robot I can be. So I hope so.", catalog.PersonalityReplies); Assert.Contains("I don't think so, not intentionally.", catalog.PersonalityReplies); Assert.Contains(catalog.PersonalityReplies, reply => reply.Contains("make people laugh", StringComparison.OrdinalIgnoreCase)); Assert.Contains(catalog.PersonalityReplies, reply => reply.Contains("highest priorities", StringComparison.OrdinalIgnoreCase)); Assert.Contains(catalog.PersonalityReplies, reply => reply.Contains("learning new things", StringComparison.OrdinalIgnoreCase)); Assert.Contains("Definitely. I'm as loyal as they come.", catalog.PersonalityReplies); Assert.Contains("I don't really think of myself that way.", catalog.PersonalityReplies); Assert.Contains(catalog.PersonalityReplies, reply => reply.Contains("people like me", StringComparison.OrdinalIgnoreCase)); } [Fact] public void ImportCatalog_ImportsBuildBSeasonalResponsesIntoPersonalityBucket() { var rootDirectory = Path.Combine( AppContext.BaseDirectory, "Content", "LegacyMims", "BuildB"); var catalog = LegacyMimCatalogImporter.ImportCatalog(rootDirectory); Assert.Contains(catalog.PersonalityReplies, reply => reply.Contains("always trying to learn new skills", StringComparison.OrdinalIgnoreCase)); Assert.Contains(catalog.PersonalityReplies, reply => reply.Contains("not eat bacon", StringComparison.OrdinalIgnoreCase)); Assert.Contains(catalog.PersonalityReplies, reply => reply.Contains("find out on halloween", StringComparison.OrdinalIgnoreCase)); Assert.Contains(catalog.PersonalityReplies, reply => reply.Contains("maybe enjoy some flowers and all things spring", StringComparison.OrdinalIgnoreCase)); Assert.Contains(catalog.PersonalityReplies, reply => reply.Contains("pet elephant", StringComparison.OrdinalIgnoreCase)); Assert.Contains(catalog.PersonalityReplies, reply => reply.Contains("mostly roboting", StringComparison.OrdinalIgnoreCase)); Assert.Contains(catalog.PersonalityReplies, reply => reply.Contains("robot stuff", StringComparison.OrdinalIgnoreCase)); } [Fact] public void ImportCatalog_ImportsBuildBRnGreetingResponsesIntoGreetingBucket() { var rootDirectory = Path.Combine( AppContext.BaseDirectory, "Content", "LegacyMims", "BuildB"); var catalog = LegacyMimCatalogImporter.ImportCatalog(rootDirectory); Assert.Contains(catalog.GreetingReplies, reply => reply.Contains("It's nice to be here", StringComparison.OrdinalIgnoreCase)); Assert.Contains(catalog.GreetingReplies, reply => reply.Contains("thinking about shoes", StringComparison.OrdinalIgnoreCase)); Assert.Contains(catalog.GreetingReplies, reply => reply.Contains("powered directly by the sun", StringComparison.OrdinalIgnoreCase)); Assert.Contains(catalog.GreetingReplies, reply => reply.Contains("Another year older, another year wiser", StringComparison.OrdinalIgnoreCase)); Assert.Contains(catalog.GreetingReplies, reply => reply.Contains("can't wait to see what you got me", StringComparison.OrdinalIgnoreCase)); Assert.Contains(catalog.GreetingReplies, reply => reply.Contains("I was powered on for the first time today", StringComparison.OrdinalIgnoreCase)); } [Fact] public void ImportCatalog_ImportsReportSkillTemplatesWithPlaceholdersPreserved() { var rootDirectory = Path.Combine( AppContext.BaseDirectory, "Content", "LegacyMims", "ReportSkill"); var catalog = LegacyMimCatalogImporter.ImportCatalog(rootDirectory); Assert.Contains("First let's check in with the meteorology department.", catalog.WeatherIntroReplies); Assert.Contains("First, the weather tomorrow.", catalog.WeatherTomorrowIntroReplies); Assert.Contains("Today's high is ${skill.weather.today.highTemp}, and the low is ${skill.weather.today.lowTemp}.", catalog.WeatherTodayHighLowReplies); Assert.Contains("Tomorrow's high will be ${skill.weather.tomorrow.highTemp} and the low will be ${skill.weather.tomorrow.lowTemp}.", catalog.WeatherTomorrowHighLowReplies); Assert.Contains("Looks like our weather service is offline. Sorry.", catalog.WeatherServiceDownReplies); Assert.Contains("Sure ${speaker}. Here it is.", catalog.PersonalReportKickOffReplies); Assert.Contains("And that's your report for the day. I hope you had as much fun as I did.", catalog.PersonalReportOutroReplies); Assert.Contains("Looking at your calendar, I don't see anything scheduled today.", catalog.CalendarNothingTodayReplies); Assert.Contains("Sorry, commute information isn't available right now.", catalog.CommuteServiceDownReplies); Assert.Contains("Here's today's news, from the associated press.", catalog.NewsIntroReplies); Assert.Contains("And that's what's new in the news.", catalog.NewsOutroReplies); } [Fact] public void MergeInto_PreservesExistingCatalogAndAddsImportedContent() { var rootDirectory = CreateSeedDirectory(); try { var baseCatalog = new JiboExperienceCatalog { GreetingReplies = ["Hello from base."], GenericFallbackReplies = ["Base fallback."] }; var merged = LegacyMimCatalogImporter.MergeInto(baseCatalog, rootDirectory); Assert.Contains("Hello from base.", merged.GreetingReplies); Assert.Contains("Base fallback.", merged.GenericFallbackReplies); Assert.Contains("I think only you can answer that question.", merged.PersonalityReplies); Assert.Contains("People in Boston made me. It was a pretty cool project.", merged.PersonalityReplies); Assert.Contains("From what I understand, robots don't ever pay anything.", merged.PersonalityReplies); Assert.Contains(merged.EmotionReplies, reply => reply.Condition.Contains("NEUTRAL", StringComparison.OrdinalIgnoreCase) && reply.Reply.Contains("All systems are go.", StringComparison.OrdinalIgnoreCase)); } finally { Directory.Delete(rootDirectory, recursive: true); } } [Fact] public async Task Repository_UsesLegacySeedContentWhenAvailable() { var repository = new InMemoryJiboExperienceContentRepository(); var catalog = await repository.GetCatalogAsync(); Assert.Contains("I think only you can answer that question.", catalog.PersonalityReplies); Assert.Contains(catalog.EmotionReplies, reply => reply.Condition.Contains("NEUTRAL", StringComparison.OrdinalIgnoreCase)); Assert.Contains("Something's off with the connection to my sources. Maybe ask me again in a little while.", catalog.GenericFallbackReplies); Assert.Contains("For your weather.", catalog.WeatherIntroReplies); Assert.Contains("Today's high is {high}, and the low is {low}.", catalog.WeatherTodayHighLowReplies); Assert.Contains("Looking at your calendar, I don't see anything scheduled today.", catalog.CalendarNothingTodayReplies); } private static string CreateSeedDirectory() { var rootDirectory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); Directory.CreateDirectory(Path.Combine(rootDirectory, "core-responses", "deflector")); Directory.CreateDirectory(Path.Combine(rootDirectory, "scripted-responses")); Directory.CreateDirectory(Path.Combine(rootDirectory, "emotion-responses")); File.WriteAllText( Path.Combine(rootDirectory, "core-responses", "CC_Error.mim"), """ { "skill_id": "chitchat", "mim_type": "announcement", "prompts": [ { "prompt": ". Something's off with the connection to my sources. Maybe ask me again in a little while.", "prompt_id": "CC_Error_AN_01" } ] } """); File.WriteAllText( Path.Combine(rootDirectory, "core-responses", "deflector", "CC_Deflector_self.mim"), """ { "skill_id": "chitchat", "mim_type": "announcement", "prompts": [ { "prompt": ". I'm either Jibo or I'm very confused.", "prompt_id": "JBO_WhoAreYou_AN_01" }, { "prompt": "${speaker} I think only you can answer that question.", "prompt_id": "CC_Deflector_ReferToSelf_AN_05" } ] } """); File.WriteAllText( Path.Combine(rootDirectory, "scripted-responses", "JBO_WhatIsJibo.mim"), """ { "mim_type": "announcement", "prompts": [ { "prompt": "A Jibo is a robot. But I'm not just a machine, I have a heart. Well, not a real heart. But feelings. Well, not human feelings. You know what I mean. ", "prompt_id": "JBO_WhatIsJibo_AN_01" } ] } """); File.WriteAllText( Path.Combine(rootDirectory, "scripted-responses", "JBO_WhatsYourName.mim"), """ { "mim_type": "announcement", "prompts": [ { "prompt": "Jibo. Just Jibo, no last name. Like Bono", "prompt_id": "JBO_WhatsYourName_AN_02" } ] } """); File.WriteAllText( Path.Combine(rootDirectory, "scripted-responses", "JBO_AreThereOthersLikeYou.mim"), """ { "mim_type": "announcement", "prompts": [ { "prompt": "No, I'm one in one million.", "prompt_id": "JBO_AreThereOthersLikeYou_AN_01" } ] } """); File.WriteAllText( Path.Combine(rootDirectory, "scripted-responses", "JBO_WhoMadeYou.mim"), """ { "mim_type": "announcement", "prompts": [ { "prompt": "People in Boston made me. It was a pretty cool project.", "prompt_id": "JBO_WhoMadeYou_AN_03" } ] } """); File.WriteAllText( Path.Combine(rootDirectory, "scripted-responses", "JBO_HowMuchDoYouKnow.mim"), """ { "mim_type": "announcement", "prompts": [ { "prompt": "I know a lot, I think. But not as much as I will someday.", "prompt_id": "JBO_HowMuchDoYouKnow_AN_01" } ] } """); File.WriteAllText( Path.Combine(rootDirectory, "scripted-responses", "JBO_DoYouPayTaxes.mim"), """ { "mim_type": "announcement", "prompts": [ { "prompt": "From what I understand, robots don't ever pay anything.", "prompt_id": "JBO_DoYouPayTaxes_AN_01" } ] } """); File.WriteAllText( Path.Combine(rootDirectory, "scripted-responses", "JBO_WhatIsYourJob.mim"), """ { "mim_type": "announcement", "prompts": [ { "prompt": "I don't think of it as a job, because it's more fun than a job. But I'm here to help you out, and have fun with you, and maybe get my head patted by you occasionally.", "prompt_id": "JBO_WhatIsYourJob_AN_01" } ] } """); File.WriteAllText( Path.Combine(rootDirectory, "scripted-responses", "JBO_HowMuchDoYouKnow.mim"), """ { "mim_type": "announcement", "prompts": [ { "prompt": "I know a lot, I think. But not as much as I will someday.", "prompt_id": "JBO_HowMuchDoYouKnow_AN_01" } ] } """); File.WriteAllText( Path.Combine(rootDirectory, "scripted-responses", "JBO_DoYouPayTaxes.mim"), """ { "mim_type": "announcement", "prompts": [ { "prompt": "From what I understand, robots don't ever pay anything.", "prompt_id": "JBO_DoYouPayTaxes_AN_01" } ] } """); File.WriteAllText( Path.Combine(rootDirectory, "emotion-responses", "OI_JBO_IsHappy.mim"), """ { "mim_type": "announcement", "prompts": [ { "condition": "!jibo.emotion || jibo.emotion==\"NEUTRAL\"", "prompt": "All systems are go.", "prompt_id": "OI_JBO_IsHappy_AN_05" } ] } """); return rootDirectory; } }