refactors

This commit is contained in:
Jacob Dubin
2026-05-17 08:08:11 -05:00
parent 05efeb2853
commit dfcf521a5a
99 changed files with 8632 additions and 9922 deletions

View File

@@ -14,20 +14,25 @@ public sealed class LegacyMimCatalogImporterTests
{
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("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(
"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);
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);
Directory.Delete(rootDirectory, true);
}
}
@@ -70,7 +75,7 @@ public sealed class LegacyMimCatalogImporterTests
}
finally
{
Directory.Delete(rootDirectory, recursive: true);
Directory.Delete(rootDirectory, true);
}
}
@@ -87,12 +92,14 @@ public sealed class LegacyMimCatalogImporterTests
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("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("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 =>
@@ -129,7 +136,8 @@ public sealed class LegacyMimCatalogImporterTests
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("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));
@@ -208,12 +216,18 @@ public sealed class LegacyMimCatalogImporterTests
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(
"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("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);
@@ -245,7 +259,7 @@ public sealed class LegacyMimCatalogImporterTests
}
finally
{
Directory.Delete(rootDirectory, recursive: true);
Directory.Delete(rootDirectory, true);
}
}
@@ -259,10 +273,12 @@ public sealed class LegacyMimCatalogImporterTests
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("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);
Assert.Contains("Looking at your calendar, I don't see anything scheduled today.",
catalog.CalendarNothingTodayReplies);
}
private static string CreateSeedDirectory()
@@ -449,4 +465,4 @@ public sealed class LegacyMimCatalogImporterTests
return rootDirectory;
}
}
}

View File

@@ -13,12 +13,8 @@ internal static class ProtocolFixtureLoader
var headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
if (root.TryGetProperty("headers", out var headerElement) && headerElement.ValueKind == JsonValueKind.Object)
{
foreach (var property in headerElement.EnumerateObject())
{
headers[property.Name] = property.Value.ToString();
}
}
var bodyText = root.TryGetProperty("body", out var bodyElement)
? bodyElement.GetRawText()
@@ -34,8 +30,12 @@ internal static class ProtocolFixtureLoader
Name = Path.GetFileNameWithoutExtension(relativePath),
Request = new ProtocolEnvelope
{
HostName = root.TryGetProperty("host", out var hostElement) ? hostElement.GetString() ?? "api.jibo.com" : "api.jibo.com",
Method = root.TryGetProperty("method", out var methodElement) ? methodElement.GetString() ?? "POST" : "POST",
HostName = root.TryGetProperty("host", out var hostElement)
? hostElement.GetString() ?? "api.jibo.com"
: "api.jibo.com",
Method = root.TryGetProperty("method", out var methodElement)
? methodElement.GetString() ?? "POST"
: "POST",
Path = root.TryGetProperty("path", out var pathElement) ? pathElement.GetString() ?? "/" : "/",
Headers = headers,
ServicePrefix = targetParts.Length > 0 ? targetParts[0] : null,
@@ -45,4 +45,4 @@ internal static class ProtocolFixtureLoader
ExpectedStatusCode = 200
};
}
}
}

View File

@@ -28,23 +28,31 @@ internal static class WebSocketFixtureLoader
Kind = session.GetProperty("kind").GetString() ?? "neo-hub-listen",
Token = session.GetProperty("token").GetString(),
Text = stepElement.TryGetProperty("text", out var text) ? text.GetRawText() : null,
Binary = stepElement.TryGetProperty("binary", out var binary) && binary.ValueKind == JsonValueKind.Array
Binary = stepElement.TryGetProperty("binary", out var binary) &&
binary.ValueKind == JsonValueKind.Array
? binary.EnumerateArray().Select(item => (byte)item.GetInt32()).ToArray()
: null
},
ExpectedReplyTypes = [.. stepElement.GetProperty("expectedReplyTypes")
.EnumerateArray()
.Select(item => item.GetString() ?? string.Empty)
.Where(item => !string.IsNullOrWhiteSpace(item))],
ExpectedReplies = stepElement.TryGetProperty("expectedReplies", out var expectedReplies) && expectedReplies.ValueKind == JsonValueKind.Array
? JsonSerializer.Deserialize<List<ExpectedWebSocketReply>>(expectedReplies.GetRawText(), SerializerOptions) ?? []
ExpectedReplyTypes =
[
.. stepElement.GetProperty("expectedReplyTypes")
.EnumerateArray()
.Select(item => item.GetString() ?? string.Empty)
.Where(item => !string.IsNullOrWhiteSpace(item))
],
ExpectedReplies = stepElement.TryGetProperty("expectedReplies", out var expectedReplies) &&
expectedReplies.ValueKind == JsonValueKind.Array
? JsonSerializer.Deserialize<List<ExpectedWebSocketReply>>(expectedReplies.GetRawText(),
SerializerOptions) ?? []
: []
})
.ToList();
return new WebSocketFixture
{
Name = root.TryGetProperty("name", out var name) ? name.GetString() ?? Path.GetFileNameWithoutExtension(relativePath) : Path.GetFileNameWithoutExtension(relativePath),
Name = root.TryGetProperty("name", out var name)
? name.GetString() ?? Path.GetFileNameWithoutExtension(relativePath)
: Path.GetFileNameWithoutExtension(relativePath),
Steps = steps
};
}
@@ -68,4 +76,4 @@ internal sealed class ExpectedWebSocketReply
public string Type { get; init; } = string.Empty;
public int? DelayMs { get; init; }
public JsonElement? JsonSubset { get; init; }
}
}

View File

@@ -1 +1 @@
global using Xunit;
global using Xunit;

View File

@@ -10,13 +10,12 @@ public sealed class AzureBlobPersistenceSmokeTests
var stateBackend = Environment.GetEnvironmentVariable("OpenJibo__State__Backend");
var stateConnectionString = Environment.GetEnvironmentVariable("OpenJibo__State__ConnectionString");
var personalMemoryBackend = Environment.GetEnvironmentVariable("OpenJibo__PersonalMemory__Backend");
var personalMemoryConnectionString = Environment.GetEnvironmentVariable("OpenJibo__PersonalMemory__ConnectionString");
var personalMemoryConnectionString =
Environment.GetEnvironmentVariable("OpenJibo__PersonalMemory__ConnectionString");
if (!string.Equals(stateBackend, "AzureBlob", StringComparison.OrdinalIgnoreCase) ||
string.IsNullOrWhiteSpace(stateConnectionString))
{
return;
}
var factory = new PersistenceSnapshotStoreFactory();
var snapshotName = $"smoke-{Guid.NewGuid():N}";
@@ -45,4 +44,4 @@ public sealed class AzureBlobPersistenceSmokeTests
public string Name { get; init; } = string.Empty;
public string Value { get; init; } = string.Empty;
}
}
}

View File

@@ -10,7 +10,8 @@ public sealed class PersistenceStoreTests
{
var factory = new PersistenceSnapshotStoreFactory();
var store = factory.Create(Path.Combine(Path.GetTempPath(), $"factory-{Guid.NewGuid():N}.json"), PersistenceBackendKind.File, "sample-snapshot");
var store = factory.Create(Path.Combine(Path.GetTempPath(), $"factory-{Guid.NewGuid():N}.json"),
PersistenceBackendKind.File, "sample-snapshot");
Assert.Equal("JsonFileSnapshotStore", store.GetType().Name);
}
@@ -21,7 +22,8 @@ public sealed class PersistenceStoreTests
var factory = new PersistenceSnapshotStoreFactory();
Assert.Throws<InvalidOperationException>(() =>
factory.Create(Path.Combine(Path.GetTempPath(), $"factory-{Guid.NewGuid():N}.json"), PersistenceBackendKind.AzureSql, "sample-snapshot"));
factory.Create(Path.Combine(Path.GetTempPath(), $"factory-{Guid.NewGuid():N}.json"),
PersistenceBackendKind.AzureSql, "sample-snapshot"));
}
[Fact]
@@ -86,10 +88,7 @@ public sealed class PersistenceStoreTests
}
finally
{
if (File.Exists(persistencePath))
{
File.Delete(persistencePath);
}
if (File.Exists(persistencePath)) File.Delete(persistencePath);
}
}
@@ -102,7 +101,8 @@ public sealed class PersistenceStoreTests
{
var firstStore = new InMemoryCloudStateStore(persistencePath);
var update = firstStore.CreateUpdate("1.0.0", "1.0.1", "Bug fix", null, 42, "robot", null, null);
var media = firstStore.CreateMedia("openjibo-default-loop", "persisted-photo", "image", "photo-ref", false, new Dictionary<string, object?> { ["note"] = "roundtrip" });
var media = firstStore.CreateMedia("openjibo-default-loop", "persisted-photo", "image", "photo-ref", false,
new Dictionary<string, object?> { ["note"] = "roundtrip" });
var sessionToken = firstStore.IssueRobotToken("robot-123");
var device = firstStore.GetOrCreateDevice("robot-123", "3.2.1", "4.5.6");
firstStore.SavePersistedState();
@@ -124,10 +124,7 @@ public sealed class PersistenceStoreTests
}
finally
{
if (File.Exists(persistencePath))
{
File.Delete(persistencePath);
}
if (File.Exists(persistencePath)) File.Delete(persistencePath);
}
}
@@ -137,7 +134,7 @@ public sealed class PersistenceStoreTests
public TSnapshot2? Load<TSnapshot2>() where TSnapshot2 : class
{
return default;
return null;
}
public void Save<TSnapshot2>(TSnapshot2 snapshot) where TSnapshot2 : class
@@ -145,4 +142,4 @@ public sealed class PersistenceStoreTests
Saves.Add(snapshot);
}
}
}
}

View File

@@ -1,5 +1,4 @@
using System.Net;
using System.Linq;
using System.Text;
using Jibo.Cloud.Application.Abstractions;
using Jibo.Cloud.Infrastructure.News;
@@ -93,7 +92,8 @@ public sealed class ProviderCachingTests
},
NullLogger<OpenWeatherReportProvider>.Instance);
var report = await provider.GetReportAsync(new WeatherReportRequest("Lone Jack,US", null, null, false, false, 0));
var report =
await provider.GetReportAsync(new WeatherReportRequest("Lone Jack,US", null, null, false, false, 0));
Assert.NotNull(report);
Assert.Equal(76, report!.Temperature);
@@ -202,9 +202,7 @@ public sealed class ProviderCachingTests
{
if (!message.Headers.TryGetValues("User-Agent", out var userAgents) ||
!userAgents.Any())
{
missingUserAgentRequestCount += 1;
}
var path = message.RequestUri?.AbsolutePath ?? string.Empty;
return path switch
@@ -224,7 +222,7 @@ public sealed class ProviderCachingTests
},
NullLogger<NewsApiBriefingProvider>.Instance);
var request = new NewsBriefingRequest(["sports"], 3);
var request = new NewsBriefingRequest(["sports"]);
var first = await provider.GetBriefingAsync(request);
var second = await provider.GetBriefingAsync(request);
@@ -241,18 +239,12 @@ public sealed class ProviderCachingTests
{
var path = message.RequestUri?.AbsolutePath ?? string.Empty;
if (!string.Equals(path, "/v2/top-headlines", StringComparison.OrdinalIgnoreCase))
{
return new HttpResponseMessage(HttpStatusCode.NotFound);
}
var query = message.RequestUri?.Query ?? string.Empty;
if (query.Contains("category=sports", StringComparison.OrdinalIgnoreCase))
{
return JsonResponse("""{"status":"ok","articles":[]}""");
}
return JsonResponse(
"""{"status":"ok","articles":[{"title":"General robotics update","description":"Top story","source":{"name":"AP News"},"url":"https://example.com/general"}]}""");
return JsonResponse(query.Contains("category=sports", StringComparison.OrdinalIgnoreCase)
? """{"status":"ok","articles":[]}"""
: """{"status":"ok","articles":[{"title":"General robotics update","description":"Top story","source":{"name":"AP News"},"url":"https://example.com/general"}]}""");
});
var provider = new NewsApiBriefingProvider(
new HttpClient(handler),
@@ -264,7 +256,7 @@ public sealed class ProviderCachingTests
},
NullLogger<NewsApiBriefingProvider>.Instance);
var result = await provider.GetBriefingAsync(new NewsBriefingRequest(["sports"], 3));
var result = await provider.GetBriefingAsync(new NewsBriefingRequest(["sports"]));
Assert.NotNull(result);
Assert.Single(result!.Headlines);
@@ -297,7 +289,7 @@ public sealed class ProviderCachingTests
},
NullLogger<NewsApiBriefingProvider>.Instance);
var result = await provider.GetBriefingAsync(new NewsBriefingRequest([], 3));
var result = await provider.GetBriefingAsync(new NewsBriefingRequest([]));
Assert.NotNull(result);
Assert.Single(result!.Headlines);
@@ -313,13 +305,10 @@ public sealed class ProviderCachingTests
{
var path = message.RequestUri?.AbsolutePath ?? string.Empty;
if (!string.Equals(path, "/v2/top-headlines", StringComparison.OrdinalIgnoreCase))
{
return new HttpResponseMessage(HttpStatusCode.NotFound);
}
var query = message.RequestUri?.Query ?? string.Empty;
if (query.Contains("category=sports", StringComparison.OrdinalIgnoreCase))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = new StringContent(
@@ -327,7 +316,6 @@ public sealed class ProviderCachingTests
Encoding.UTF8,
"application/json")
};
}
return JsonResponse(
"""{"status":"ok","articles":[{"title":"General robotics update","description":"Top story","source":{"name":"AP News"},"url":"https://example.com/general"}]}""");
@@ -342,7 +330,7 @@ public sealed class ProviderCachingTests
},
NullLogger<NewsApiBriefingProvider>.Instance);
var result = await provider.GetBriefingAsync(new NewsBriefingRequest(["sports"], 3));
var result = await provider.GetBriefingAsync(new NewsBriefingRequest(["sports"]));
Assert.NotNull(result);
Assert.Single(result!.Headlines);
@@ -358,7 +346,6 @@ public sealed class ProviderCachingTests
{
var path = message.RequestUri?.AbsolutePath ?? string.Empty;
if (string.Equals(path, "/v2/top-headlines", StringComparison.OrdinalIgnoreCase))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = new StringContent(
@@ -366,10 +353,8 @@ public sealed class ProviderCachingTests
Encoding.UTF8,
"application/json")
};
}
if (string.Equals(path, "/v2/everything", StringComparison.OrdinalIgnoreCase))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = new StringContent(
@@ -377,7 +362,6 @@ public sealed class ProviderCachingTests
Encoding.UTF8,
"application/json")
};
}
return new HttpResponseMessage(HttpStatusCode.NotFound);
});
@@ -392,7 +376,7 @@ public sealed class ProviderCachingTests
},
NullLogger<NewsApiBriefingProvider>.Instance);
var result = await provider.GetBriefingAsync(new NewsBriefingRequest([], 3));
var result = await provider.GetBriefingAsync(new NewsBriefingRequest([]));
Assert.NotNull(result);
Assert.Empty(result!.Headlines);
@@ -414,14 +398,14 @@ public sealed class ProviderCachingTests
private sealed class CountingHttpMessageHandler(Func<HttpRequestMessage, HttpResponseMessage> responseFactory)
: HttpMessageHandler
{
private readonly Dictionary<string, int> callsByPath = new(StringComparer.OrdinalIgnoreCase);
private readonly object gate = new();
private readonly Dictionary<string, int> _callsByPath = new(StringComparer.OrdinalIgnoreCase);
private readonly Lock _gate = new();
public int GetCallCount(string path)
{
lock (gate)
lock (_gate)
{
return callsByPath.TryGetValue(path, out var count) ? count : 0;
return _callsByPath.GetValueOrDefault(path, 0);
}
}
@@ -430,12 +414,12 @@ public sealed class ProviderCachingTests
CancellationToken cancellationToken)
{
var path = request.RequestUri?.AbsolutePath ?? string.Empty;
lock (gate)
lock (_gate)
{
callsByPath[path] = callsByPath.TryGetValue(path, out var count) ? count + 1 : 1;
_callsByPath[path] = _callsByPath.TryGetValue(path, out var count) ? count + 1 : 1;
}
return Task.FromResult(responseFactory(request));
}
}
}
}

View File

@@ -7,21 +7,28 @@ namespace Jibo.Cloud.Tests.Protocol;
public sealed class FileProtocolTelemetrySinkTests : IDisposable
{
private readonly string _workspaceRoot;
private readonly string _repoRoot;
private readonly string _appBaseDirectory;
private readonly string _repoRoot;
private readonly string _workspaceRoot;
public FileProtocolTelemetrySinkTests()
{
_workspaceRoot = Path.Combine(Path.GetTempPath(), "OpenJibo.ProtocolTelemetry.Tests", Guid.NewGuid().ToString("N"));
_workspaceRoot = Path.Combine(Path.GetTempPath(), "OpenJibo.ProtocolTelemetry.Tests",
Guid.NewGuid().ToString("N"));
_repoRoot = Path.Combine(_workspaceRoot, "OpenJibo");
_appBaseDirectory = Path.Combine(_repoRoot, "src", "Jibo.Cloud", "dotnet", "src", "Jibo.Cloud.Api", "bin", "Debug", "net10.0");
_appBaseDirectory = Path.Combine(_repoRoot, "src", "Jibo.Cloud", "dotnet", "src", "Jibo.Cloud.Api", "bin",
"Debug", "net10.0");
Directory.CreateDirectory(_repoRoot);
Directory.CreateDirectory(_appBaseDirectory);
File.WriteAllText(Path.Combine(_repoRoot, "OpenJibo.slnx"), string.Empty);
}
public void Dispose()
{
if (Directory.Exists(_workspaceRoot)) Directory.Delete(_workspaceRoot, true);
}
[Fact]
public async Task RecordAsync_ResolvesRelativePathAgainstOpenJiboRepoRoot()
{
@@ -52,12 +59,4 @@ public sealed class FileProtocolTelemetrySinkTests : IDisposable
Assert.Contains("Notification_20150505", contents);
Assert.DoesNotContain(Path.Combine("bin", "Debug"), captureFile, StringComparison.OrdinalIgnoreCase);
}
public void Dispose()
{
if (Directory.Exists(_workspaceRoot))
{
Directory.Delete(_workspaceRoot, true);
}
}
}
}

View File

@@ -144,10 +144,7 @@ public sealed class JiboCloudProtocolServiceTests
}
finally
{
if (File.Exists(persistencePath))
{
File.Delete(persistencePath);
}
if (File.Exists(persistencePath)) File.Delete(persistencePath);
}
}
@@ -170,7 +167,8 @@ public sealed class JiboCloudProtocolServiceTests
});
using var createdPayload = JsonDocument.Parse(result.BodyText);
Assert.Equal("https://api.jibo.com/media/photo-blob-1", createdPayload.RootElement.GetProperty("url").GetString());
Assert.Equal("https://api.jibo.com/media/photo-blob-1",
createdPayload.RootElement.GetProperty("url").GetString());
var mediaGet = await _service.DispatchAsync(new ProtocolEnvelope
{
@@ -226,7 +224,10 @@ public sealed class JiboCloudProtocolServiceTests
Assert.NotEmpty(people);
Assert.Contains(people, person => person.IsPrimary);
Assert.Contains(people, person => string.Equals(person.AccountId, store.GetAccount().AccountId, StringComparison.OrdinalIgnoreCase));
Assert.Contains(people, person => string.Equals(person.LoopId, store.GetLoops()[0].LoopId, StringComparison.OrdinalIgnoreCase));
Assert.Contains(people,
person => string.Equals(person.AccountId, store.GetAccount().AccountId,
StringComparison.OrdinalIgnoreCase));
Assert.Contains(people,
person => string.Equals(person.LoopId, store.GetLoops()[0].LoopId, StringComparison.OrdinalIgnoreCase));
}
}
}

View File

@@ -19,4 +19,4 @@ public sealed class ProtocolFixtureReplayTests
Assert.Equal(fixture.ExpectedStatusCode, result.StatusCode);
Assert.False(string.IsNullOrWhiteSpace(result.BodyText));
}
}
}

View File

@@ -106,7 +106,8 @@ public sealed class FileTurnTelemetrySinkTests
public async Task HandleContext_EmitsGlsmPhaseTransitionDiagnostic()
{
var sink = new Mock<ITurnTelemetrySink>();
sink.Setup(s => s.RecordTurnDiagnosticAsync(It.IsAny<string>(), It.IsAny<IReadOnlyDictionary<string, object?>>(), It.IsAny<CancellationToken>()))
sink.Setup(s => s.RecordTurnDiagnosticAsync(It.IsAny<string>(),
It.IsAny<IReadOnlyDictionary<string, object?>>(), It.IsAny<CancellationToken>()))
.Returns(Task.CompletedTask);
var turnService = new WebSocketTurnFinalizationService(
Mock.Of<IConversationBroker>(),
@@ -142,8 +143,9 @@ public sealed class FileTurnTelemetrySinkTests
"glsm_phase_transition",
It.Is<IReadOnlyDictionary<string, object?>>(details =>
details.ContainsKey("state") &&
string.Equals(details["state"] == null ? null : details["state"]!.ToString(), "LISTENING", StringComparison.OrdinalIgnoreCase)),
string.Equals(details["state"] == null ? null : details["state"]!.ToString(), "LISTENING",
StringComparison.OrdinalIgnoreCase)),
It.IsAny<CancellationToken>()),
Times.AtLeastOnce());
}
}
}

View File

@@ -8,15 +8,21 @@ namespace Jibo.Cloud.Tests.WebSockets;
public sealed class FileWebSocketTelemetrySinkTests : IDisposable
{
private readonly string _appBaseDirectory;
private readonly string _directoryPath;
private readonly string _repoRoot;
private readonly string _appBaseDirectory;
public FileWebSocketTelemetrySinkTests()
{
_directoryPath = Path.Combine(Path.GetTempPath(), "OpenJibo.Tests", Guid.NewGuid().ToString("N"));
_repoRoot = Path.Combine(_directoryPath, "OpenJibo");
_appBaseDirectory = Path.Combine(_repoRoot, "src", "Jibo.Cloud", "dotnet", "src", "Jibo.Cloud.Api", "bin", "Debug", "net10.0");
_appBaseDirectory = Path.Combine(_repoRoot, "src", "Jibo.Cloud", "dotnet", "src", "Jibo.Cloud.Api", "bin",
"Debug", "net10.0");
}
public void Dispose()
{
if (Directory.Exists(_directoryPath)) Directory.Delete(_directoryPath, true);
}
[Fact]
@@ -55,17 +61,11 @@ public sealed class FileWebSocketTelemetrySinkTests : IDisposable
var fixtureDirectory = Path.Combine(_directoryPath, "fixtures");
var fixturePath = Directory.GetFiles(fixtureDirectory, "*.flow.json").Single();
using var document = JsonDocument.Parse(await File.ReadAllTextAsync(fixturePath));
Assert.Equal("neo-hub.jibo.com", document.RootElement.GetProperty("session").GetProperty("hostName").GetString());
Assert.Equal("neo-hub.jibo.com",
document.RootElement.GetProperty("session").GetProperty("hostName").GetString());
Assert.Equal(1, document.RootElement.GetProperty("steps").GetArrayLength());
Assert.Equal("LISTEN", document.RootElement.GetProperty("steps")[0].GetProperty("expectedReplyTypes")[0].GetString());
}
public void Dispose()
{
if (Directory.Exists(_directoryPath))
{
Directory.Delete(_directoryPath, true);
}
Assert.Equal("LISTEN",
document.RootElement.GetProperty("steps")[0].GetProperty("expectedReplyTypes")[0].GetString());
}
[Fact]

View File

@@ -1,9 +1,9 @@
using System.Text.Json;
using Jibo.Cloud.Application.Abstractions;
using Jibo.Cloud.Application.Services;
using Jibo.Cloud.Infrastructure.Content;
using Jibo.Cloud.Infrastructure.Persistence;
using Jibo.Runtime.Abstractions;
using System.Text.Json;
namespace Jibo.Cloud.Tests.WebSockets;
@@ -56,9 +56,13 @@ public sealed class JiboInteractionServiceTests
Assert.Equal("dance", decision.IntentName);
Assert.Equal("chitchat-skill", decision.SkillName);
var catalog = await new InMemoryJiboExperienceContentRepository().GetCatalogAsync(); // Ensure catalog is loaded for test coverage
var catalog =
await new InMemoryJiboExperienceContentRepository()
.GetCatalogAsync(); // Ensure catalog is loaded for test coverage
Assert.Contains(decision.ReplyText, catalog.DanceReplies);
Assert.Equal("<speak>Okay.<break size='0.2'/> Watch this.<anim cat='dance' filter='music, rom-upbeat' /></speak>", decision.SkillPayload!["esml"]);
Assert.Equal(
"<speak>Okay.<break size='0.2'/> Watch this.<anim cat='dance' filter='music, rom-upbeat' /></speak>",
decision.SkillPayload!["esml"]);
}
[Fact]
@@ -198,7 +202,8 @@ public sealed class JiboInteractionServiceTests
{
["accountId"] = "acct-a",
["loopId"] = "loop-a",
["context"] = """{"runtime":{"perception":{"speaker":"person-1"},"loop":{"users":[{"id":"person-1","firstName":"jake"}]}}}"""
["context"] =
"""{"runtime":{"perception":{"speaker":"person-1"},"loop":{"users":[{"id":"person-1","firstName":"jake"}]}}}"""
},
DeviceId = "device-a"
});
@@ -222,7 +227,8 @@ public sealed class JiboInteractionServiceTests
{
["accountId"] = "acct-b",
["loopId"] = "loop-b",
["context"] = """{"runtime":{"perception":{"speaker":"person-2"},"loop":{"users":[{"id":"person-2","firstName":"sam"}]}}}"""
["context"] =
"""{"runtime":{"perception":{"speaker":"person-2"},"loop":{"users":[{"id":"person-2","firstName":"sam"}]}}}"""
},
DeviceId = "device-b"
});
@@ -250,7 +256,8 @@ public sealed class JiboInteractionServiceTests
{
["accountId"] = "acct-c",
["loopId"] = "loop-c",
["context"] = """{"runtime":{"perception":{"speaker":"person-3"},"loop":{"users":[{"id":"person-3","firstName":"taylor"}]}}}"""
["context"] =
"""{"runtime":{"perception":{"speaker":"person-3"},"loop":{"users":[{"id":"person-3","firstName":"taylor"}]}}}"""
},
DeviceId = "device-c"
});
@@ -287,7 +294,8 @@ public sealed class JiboInteractionServiceTests
{
["messageType"] = "TRIGGER",
["triggerSource"] = "PRESENCE",
["context"] = """{"runtime":{"perception":{"speaker":"person-1","peoplePresent":[{"id":"person-1"}]},"loop":{"users":[{"id":"person-1","firstName":"jake"}]}}}"""
["context"] =
"""{"runtime":{"perception":{"speaker":"person-1","peoplePresent":[{"id":"person-1"}]},"loop":{"users":[{"id":"person-1","firstName":"jake"}]}}}"""
}
});
@@ -312,7 +320,8 @@ public sealed class JiboInteractionServiceTests
{
["messageType"] = "TRIGGER",
["triggerSource"] = "SURPRISE",
["context"] = """{"runtime":{"perception":{"speaker":"person-1"},"loop":{"users":[{"id":"person-1","firstName":"jake"}]}}}"""
["context"] =
"""{"runtime":{"perception":{"speaker":"person-1"},"loop":{"users":[{"id":"person-1","firstName":"jake"}]}}}"""
}
});
@@ -336,7 +345,8 @@ public sealed class JiboInteractionServiceTests
{
["messageType"] = "TRIGGER",
["triggerSource"] = "PRESENCE",
["context"] = """{"runtime":{"perception":{"speaker":"person-1"},"loop":{"users":[{"id":"person-1","firstName":"jake"}]}}}""",
["context"] =
"""{"runtime":{"perception":{"speaker":"person-1"},"loop":{"users":[{"id":"person-1","firstName":"jake"}]}}}""",
[GreetingLastProactiveUtcKey] = DateTimeOffset.UtcNow.ToString("O")
}
});
@@ -427,13 +437,18 @@ public sealed class JiboInteractionServiceTests
}
[Theory]
[InlineData("how do you work", "robot_how_do_you_work", "Hello! Thank you for updating me I am proud of the community's work Many people have gotten together to care for me more than em eye tee ever did. I hope that I can catch up even though it has been seven years.")]
[InlineData("how do you work", "robot_how_do_you_work",
"Hello! Thank you for updating me I am proud of the community's work Many people have gotten together to care for me more than em eye tee ever did. I hope that I can catch up even though it has been seven years.")]
[InlineData("what do you eat", "robot_what_do_you_eat", "The only thing I consume is electricity.")]
[InlineData("where do you live", "robot_where_do_you_live", "Unless I missed something, we're in my home as we speak.")]
[InlineData("where do you live", "robot_where_do_you_live",
"Unless I missed something, we're in my home as we speak.")]
[InlineData("where were you born", "robot_where_were_you_born", "I was put together in a factory piece by piece.")]
[InlineData("what languages do you speak", "robot_what_languages_do_you_speak", "For now just English. But someday I'd like to learn more. I like languages.")]
[InlineData("what do you like to do", "robot_what_do_you_like_to_do", "Being helpful, making people smile, counting to a billion.")]
[InlineData("what are you made of", "robot_what_are_you_made_of", "Let's see, I'm made of wires, motors, belts, gears, processors, cameras, and one baboon's heart in the middle of my body casing. I'm kidding about the baboon part, but everything else is true.")]
[InlineData("what languages do you speak", "robot_what_languages_do_you_speak",
"For now just English. But someday I'd like to learn more. I like languages.")]
[InlineData("what do you like to do", "robot_what_do_you_like_to_do",
"Being helpful, making people smile, counting to a billion.")]
[InlineData("what are you made of", "robot_what_are_you_made_of",
"Let's see, I'm made of wires, motors, belts, gears, processors, cameras, and one baboon's heart in the middle of my body casing. I'm kidding about the baboon part, but everything else is true.")]
public async Task BuildDecisionAsync_MoreLegacyPersonaMims_UseImportedReplies(
string transcript,
string expectedIntent,
@@ -454,10 +469,13 @@ public sealed class JiboInteractionServiceTests
[Theory]
[InlineData("do you pay taxes", "robot_taxes", "From what I understand, robots don't ever pay anything.")]
[InlineData("what do you want", "robot_desire", "Socializing and electricity. I'd also be happy if everyone in the world was nicer to each other. It seems like they should be.")]
[InlineData("what do you want", "robot_desire",
"Socializing and electricity. I'd also be happy if everyone in the world was nicer to each other. It seems like they should be.")]
[InlineData("what's your name", "robot_name", "Jibo. Just Jibo, no last name. Like Bono")]
[InlineData("who made you", "robot_origin_created", "My story is pretty typical. Some people wanted to create something that would really help people. So they built a robot.")]
[InlineData("where are you from", "robot_origin_from", "Some people think I come from the moon. But they're wrong, I'm from Boston.")]
[InlineData("who made you", "robot_origin_created",
"My story is pretty typical. Some people wanted to create something that would really help people. So they built a robot.")]
[InlineData("where are you from", "robot_origin_from",
"Some people think I come from the moon. But they're wrong, I'm from Boston.")]
public async Task BuildDecisionAsync_LegacyBuildAQuestions_UseImportedScriptedReplies(
string transcript,
string expectedIntent,
@@ -552,7 +570,8 @@ public sealed class JiboInteractionServiceTests
[InlineData("what are you up to", "being helpful")]
[InlineData("what are you doing", "making people smile")]
[InlineData("what have you been up to", "being helpful")]
public async Task BuildDecisionAsync_PersonalityFollowups_UseDoingPath(string transcript, string expectedReplySnippet)
public async Task BuildDecisionAsync_PersonalityFollowups_UseDoingPath(string transcript,
string expectedReplySnippet)
{
var service = CreateService();
@@ -570,11 +589,14 @@ public sealed class JiboInteractionServiceTests
[Theory]
[InlineData("happy holidays", "seasonal_holiday_greeting", "It's a fun time of year")]
[InlineData("merry christmas", "seasonal_holiday_greeting", "It's a fun time of year")]
[InlineData("what holidays do you celebrate", "seasonal_holidays", "official owner can tell me which ones we'll celebrate together")]
[InlineData("what is your new year's resolution", "seasonal_new_years_resolution", "always trying to learn new skills")]
[InlineData("what holidays do you celebrate", "seasonal_holidays",
"official owner can tell me which ones we'll celebrate together")]
[InlineData("what is your new year's resolution", "seasonal_new_years_resolution",
"always trying to learn new skills")]
[InlineData("how are your new year's resolutions going", "seasonal_new_years_update", "not eat bacon")]
[InlineData("what halloween costume", "seasonal_halloween_costume", "I haven't thought much about it yet")]
[InlineData("what should I do for first day of spring", "seasonal_first_day_spring", "flowers and all things spring")]
[InlineData("what should I do for first day of spring", "seasonal_first_day_spring",
"flowers and all things spring")]
[InlineData("what should I get for holiday", "seasonal_holiday_gift", "pet elephant")]
public async Task BuildDecisionAsync_SeasonalCharm_UsesImportedReplies(
string transcript,
@@ -672,7 +694,7 @@ public sealed class JiboInteractionServiceTests
try
{
File.WriteAllText(
await File.WriteAllTextAsync(
Path.Combine(rootDirectory, "gqa-responses", "GQA_JBO_IsHappy.mim"),
"""
{
@@ -710,7 +732,7 @@ public sealed class JiboInteractionServiceTests
}
finally
{
Directory.Delete(rootDirectory, recursive: true);
Directory.Delete(rootDirectory, true);
}
}
@@ -1082,7 +1104,8 @@ public sealed class JiboInteractionServiceTests
});
Assert.Equal("memory_get_birthday", otherTenantRecall.IntentName);
Assert.Equal("I do not know your birthday yet. You can say, my birthday is March 14.", otherTenantRecall.ReplyText);
Assert.Equal("I do not know your birthday yet. You can say, my birthday is March 14.",
otherTenantRecall.ReplyText);
}
[Fact]
@@ -1726,12 +1749,18 @@ public sealed class JiboInteractionServiceTests
Assert.Equal("personal_report_delivered", decision.IntentName);
Assert.Contains("Sure alex. Here it is.", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains("First, your weather.", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains("For your weather. In Boston, U.S., it's light rain and 61 degrees Fahrenheit. Today's high is 65, and the low is 54.", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains("Looking at your calendar, I don't see anything scheduled today.", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains("Sorry, commute information isn't available right now.", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains("Here's today's news, from the associated press.", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains(
"For your weather. In Boston, U.S., it's light rain and 61 degrees Fahrenheit. Today's high is 65, and the low is 54.",
decision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains("Looking at your calendar, I don't see anything scheduled today.", decision.ReplyText,
StringComparison.OrdinalIgnoreCase);
Assert.Contains("Sorry, commute information isn't available right now.", decision.ReplyText,
StringComparison.OrdinalIgnoreCase);
Assert.Contains("Here's today's news, from the associated press.", decision.ReplyText,
StringComparison.OrdinalIgnoreCase);
Assert.Contains("And that's what's new in the news.", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains("alex that wraps up your report for the day. Hope you have a good one.", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains("alex that wraps up your report for the day. Hope you have a good one.", decision.ReplyText,
StringComparison.OrdinalIgnoreCase);
Assert.NotNull(decision.ContextUpdates);
Assert.Equal("idle", decision.ContextUpdates![PersonalReportStateKey]);
Assert.Equal(true, decision.ContextUpdates[PersonalReportUserVerifiedKey]);
@@ -1856,7 +1885,8 @@ public sealed class JiboInteractionServiceTests
Assert.Contains("What else should I add?", addDecision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Equal("awaiting_item", addDecision.ContextUpdates![HouseholdListStateKey]);
Assert.Equal("shopping", addDecision.ContextUpdates[HouseholdListTypeKey]);
Assert.Equal(["milk"], memoryStore.GetListItems(new PersonalMemoryTenantScope("acct-a", "loop-a", "device-a"), "shopping"));
Assert.Equal(["milk"],
memoryStore.GetListItems(new PersonalMemoryTenantScope("acct-a", "loop-a", "device-a"), "shopping"));
var doneDecision = await service.BuildDecisionAsync(new TurnContext
{
@@ -1871,7 +1901,8 @@ public sealed class JiboInteractionServiceTests
});
Assert.Equal("shopping_list_done", doneDecision.IntentName);
Assert.Contains("Okay. Your shopping list has milk.", doneDecision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains("Okay. Your shopping list has milk.", doneDecision.ReplyText,
StringComparison.OrdinalIgnoreCase);
Assert.Equal("idle", doneDecision.ContextUpdates![HouseholdListStateKey]);
var recallDecision = await service.BuildDecisionAsync(new TurnContext
@@ -1924,7 +1955,8 @@ public sealed class JiboInteractionServiceTests
Assert.Equal("todo_list_add", addDecision.IntentName);
Assert.Contains("call mom", addDecision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains("What else should I add?", addDecision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Equal(["call mom"], memoryStore.GetListItems(new PersonalMemoryTenantScope("acct-b", "loop-b", "device-b"), "todo"));
Assert.Equal(["call mom"],
memoryStore.GetListItems(new PersonalMemoryTenantScope("acct-b", "loop-b", "device-b"), "todo"));
var doneDecision = await service.BuildDecisionAsync(new TurnContext
{
@@ -1939,7 +1971,8 @@ public sealed class JiboInteractionServiceTests
});
Assert.Equal("todo_list_done", doneDecision.IntentName);
Assert.Contains("Okay. Your to-do list has call mom.", doneDecision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains("Okay. Your to-do list has call mom.", doneDecision.ReplyText,
StringComparison.OrdinalIgnoreCase);
Assert.Equal("idle", doneDecision.ContextUpdates![HouseholdListStateKey]);
}
@@ -2057,7 +2090,8 @@ public sealed class JiboInteractionServiceTests
Assert.Equal("weather", decision.IntentName);
Assert.Equal("chitchat-skill", decision.SkillName);
Assert.NotNull(decision.SkillPayload);
Assert.Contains("cat='weather'", decision.SkillPayload!["esml"]?.ToString(), StringComparison.OrdinalIgnoreCase);
Assert.Contains("cat='weather'", decision.SkillPayload!["esml"]?.ToString(),
StringComparison.OrdinalIgnoreCase);
Assert.Contains("meta='rain'", decision.SkillPayload["esml"]?.ToString(), StringComparison.OrdinalIgnoreCase);
Assert.Equal("report-skill", decision.SkillPayload["skillId"]);
Assert.Equal("WeatherCommentRain", decision.SkillPayload["mim_id"]);
@@ -2068,7 +2102,9 @@ public sealed class JiboInteractionServiceTests
Assert.Equal(54, decision.SkillPayload["weather_low"]);
Assert.Equal("F", decision.SkillPayload["weather_unit"]);
Assert.Equal("Normal", decision.SkillPayload["weather_theme"]);
Assert.Equal("For your weather. In Boston, U.S., it's light rain and 61 degrees Fahrenheit. Today's high is 65, and the low is 54.", decision.ReplyText);
Assert.Equal(
"For your weather. In Boston, U.S., it's light rain and 61 degrees Fahrenheit. Today's high is 65, and the low is 54.",
decision.ReplyText);
Assert.NotNull(provider.LastRequest);
Assert.False(provider.LastRequest!.IsTomorrow);
Assert.Equal(0, provider.LastRequest.ForecastDayOffset);
@@ -2093,7 +2129,9 @@ public sealed class JiboInteractionServiceTests
Assert.Equal("Chicago", provider.LastRequest?.LocationQuery);
Assert.True(provider.LastRequest?.IsTomorrow);
Assert.Equal(1, provider.LastRequest?.ForecastDayOffset);
Assert.Equal("First, the weather tomorrow. Tomorrow in Chicago, U.S., it looks mostly cloudy. Tomorrow's high will be 74 and the low will be 60.", decision.ReplyText);
Assert.Equal(
"First, the weather tomorrow. Tomorrow in Chicago, U.S., it looks mostly cloudy. Tomorrow's high will be 74 and the low will be 60.",
decision.ReplyText);
}
[Fact]
@@ -2115,7 +2153,9 @@ public sealed class JiboInteractionServiceTests
Assert.Equal("Seattle", provider.LastRequest?.LocationQuery);
Assert.False(provider.LastRequest?.IsTomorrow);
Assert.Equal(0, provider.LastRequest?.ForecastDayOffset);
Assert.Equal("For your weather. In Seattle, U.S., it's light rain and 58 degrees Fahrenheit. Today's high is 61, and the low is 52.", decision.ReplyText);
Assert.Equal(
"For your weather. In Seattle, U.S., it's light rain and 58 degrees Fahrenheit. Today's high is 61, and the low is 52.",
decision.ReplyText);
}
[Fact]
@@ -2137,7 +2177,9 @@ public sealed class JiboInteractionServiceTests
Assert.Equal("Paris", provider.LastRequest?.LocationQuery);
Assert.False(provider.LastRequest?.IsTomorrow);
Assert.Equal(0, provider.LastRequest?.ForecastDayOffset);
Assert.Equal("For your weather. In Paris, FR, it's overcast clouds and 66 degrees Fahrenheit. Today's high is 70, and the low is 60.", decision.ReplyText);
Assert.Equal(
"For your weather. In Paris, FR, it's overcast clouds and 66 degrees Fahrenheit. Today's high is 70, and the low is 60.",
decision.ReplyText);
}
[Fact]
@@ -2159,7 +2201,9 @@ public sealed class JiboInteractionServiceTests
Assert.Equal("Redmond Oregon", provider.LastRequest?.LocationQuery);
Assert.False(provider.LastRequest?.IsTomorrow);
Assert.Equal(0, provider.LastRequest?.ForecastDayOffset);
Assert.Equal("For your weather. In Redmond, U.S., it's clear sky and 63 degrees Fahrenheit. Today's high is 66, and the low is 52.", decision.ReplyText);
Assert.Equal(
"For your weather. In Redmond, U.S., it's clear sky and 63 degrees Fahrenheit. Today's high is 66, and the low is 52.",
decision.ReplyText);
}
[Fact]
@@ -2181,7 +2225,9 @@ public sealed class JiboInteractionServiceTests
Assert.Equal("New York City", provider.LastRequest?.LocationQuery);
Assert.True(provider.LastRequest?.IsTomorrow);
Assert.Equal(1, provider.LastRequest?.ForecastDayOffset);
Assert.Equal("First, the weather tomorrow. Tomorrow in New York, U.S., it looks partly cloudy. Tomorrow's high will be 76 and the low will be 61.", decision.ReplyText);
Assert.Equal(
"First, the weather tomorrow. Tomorrow in New York, U.S., it looks partly cloudy. Tomorrow's high will be 76 and the low will be 61.",
decision.ReplyText);
}
[Fact]
@@ -2210,7 +2256,8 @@ public sealed class JiboInteractionServiceTests
Assert.Equal(5, provider.Requests.Count);
Assert.Contains("next five-day forecast", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains("Tuesday: clear sky, high 79, low 63.", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains("Saturday: clear sky, high 79, low 63.", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains("Saturday: clear sky, high 79, low 63.", decision.ReplyText,
StringComparison.OrdinalIgnoreCase);
}
[Fact]
@@ -2228,7 +2275,8 @@ public sealed class JiboInteractionServiceTests
NormalizedTranscript = "what's the weather in chicago",
Attributes = new Dictionary<string, object?>
{
["context"] = """{"runtime":{"location":{"lat":39.0997,"lng":-94.5786,"iso":"2026-05-09T09:00:00-05:00"}}}"""
["context"] =
"""{"runtime":{"location":{"lat":39.0997,"lng":-94.5786,"iso":"2026-05-09T09:00:00-05:00"}}}"""
}
});
@@ -2236,7 +2284,9 @@ public sealed class JiboInteractionServiceTests
Assert.Equal("Chicago", provider.LastRequest?.LocationQuery);
Assert.Null(provider.LastRequest?.Latitude);
Assert.Null(provider.LastRequest?.Longitude);
Assert.Equal("For your weather. In Chicago, U.S., it's mostly cloudy and 70 degrees Fahrenheit. Today's high is 75, and the low is 62.", decision.ReplyText);
Assert.Equal(
"For your weather. In Chicago, U.S., it's mostly cloudy and 70 degrees Fahrenheit. Today's high is 75, and the low is 62.",
decision.ReplyText);
}
[Fact]
@@ -2266,7 +2316,9 @@ public sealed class JiboInteractionServiceTests
Assert.Equal("Chicago", provider.LastRequest?.LocationQuery);
Assert.Equal(0, provider.LastRequest?.ForecastDayOffset);
Assert.False(provider.LastRequest?.IsTomorrow);
Assert.Equal("For your weather. In Chicago, U.S., it's mostly cloudy and 70 degrees Fahrenheit. Today's high is 75, and the low is 62.", decision.ReplyText);
Assert.Equal(
"For your weather. In Chicago, U.S., it's mostly cloudy and 70 degrees Fahrenheit. Today's high is 75, and the low is 62.",
decision.ReplyText);
}
[Fact]
@@ -2296,7 +2348,9 @@ public sealed class JiboInteractionServiceTests
Assert.Equal("Chicago", provider.LastRequest?.LocationQuery);
Assert.Equal(1, provider.LastRequest?.ForecastDayOffset);
Assert.True(provider.LastRequest?.IsTomorrow);
Assert.Equal("First, the weather tomorrow. Tomorrow in Chicago, U.S., it looks mostly cloudy. Tomorrow's high will be 75 and the low will be 62.", decision.ReplyText);
Assert.Equal(
"First, the weather tomorrow. Tomorrow in Chicago, U.S., it looks mostly cloudy. Tomorrow's high will be 75 and the low will be 62.",
decision.ReplyText);
}
[Theory]
@@ -2335,9 +2389,7 @@ public sealed class JiboInteractionServiceTests
Assert.Equal(true, decision.SkillPayload?["weather_view_enabled"]);
if (string.Equals(transcript, "what's the forecast", StringComparison.Ordinal))
{
Assert.Equal(5, provider.Requests.Count);
}
}
[Fact]
@@ -2366,7 +2418,9 @@ public sealed class JiboInteractionServiceTests
Assert.Equal("weather", decision.IntentName);
Assert.Equal(2, provider.LastRequest?.ForecastDayOffset);
Assert.False(provider.LastRequest?.IsTomorrow);
Assert.Equal("Let's look at the weather. On Monday in Portland, U.S., it looks scattered clouds with a high near 68 degrees Fahrenheit and a low around 53 degrees Fahrenheit.", decision.ReplyText);
Assert.Equal(
"Let's look at the weather. On Monday in Portland, U.S., it looks scattered clouds with a high near 68 degrees Fahrenheit and a low around 53 degrees Fahrenheit.",
decision.ReplyText);
}
[Fact]
@@ -2391,7 +2445,9 @@ public sealed class JiboInteractionServiceTests
Assert.Equal("weather", decision.IntentName);
Assert.Equal("Chicago", provider.LastRequest?.LocationQuery);
Assert.Equal(1, provider.LastRequest?.ForecastDayOffset);
Assert.Equal("First, the weather tomorrow. On Tuesday in Chicago, U.S., it looks light rain. Tomorrow's high will be 63 and the low will be 51.", decision.ReplyText);
Assert.Equal(
"First, the weather tomorrow. On Tuesday in Chicago, U.S., it looks light rain. Tomorrow's high will be 63 and the low will be 51.",
decision.ReplyText);
}
[Fact]
@@ -2440,7 +2496,9 @@ public sealed class JiboInteractionServiceTests
Assert.Equal("weather", decision.IntentName);
Assert.Equal("Paris", provider.LastRequest?.LocationQuery);
Assert.Equal(5, provider.LastRequest?.ForecastDayOffset);
Assert.Equal("Let's look at the weather. This weekend in Paris, FR, it looks overcast clouds with a high near 70 degrees Fahrenheit and a low around 60 degrees Fahrenheit.", decision.ReplyText);
Assert.Equal(
"Let's look at the weather. This weekend in Paris, FR, it looks overcast clouds with a high near 70 degrees Fahrenheit and a low around 60 degrees Fahrenheit.",
decision.ReplyText);
}
[Fact]
@@ -2467,8 +2525,10 @@ public sealed class JiboInteractionServiceTests
Assert.Equal(5, provider.LastRequest?.ForecastDayOffset);
Assert.Equal(5, provider.Requests.Count);
Assert.Contains("rest of this week's forecast", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains("Tuesday: light rain, high 61, low 52.", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains("Saturday: light rain, high 61, low 52.", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains("Tuesday: light rain, high 61, low 52.", decision.ReplyText,
StringComparison.OrdinalIgnoreCase);
Assert.Contains("Saturday: light rain, high 61, low 52.", decision.ReplyText,
StringComparison.OrdinalIgnoreCase);
Assert.Contains("Temperatures are in Fahrenheit.", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.NotNull(decision.SkillPayload);
Assert.True(decision.SkillPayload!.TryGetValue("weather_weekly_cards", out var weeklyCardsValue));
@@ -2562,7 +2622,9 @@ public sealed class JiboInteractionServiceTests
Assert.Equal("weather", decision.IntentName);
Assert.Equal("Chicago", provider.LastRequest?.LocationQuery);
Assert.Equal(2, provider.LastRequest?.ForecastDayOffset);
Assert.Equal("Let's look at the weather. The day after tomorrow in Chicago, U.S., it looks mostly cloudy with a high near 74 degrees Fahrenheit and a low around 60 degrees Fahrenheit.", decision.ReplyText);
Assert.Equal(
"Let's look at the weather. The day after tomorrow in Chicago, U.S., it looks mostly cloudy with a high near 74 degrees Fahrenheit and a low around 60 degrees Fahrenheit.",
decision.ReplyText);
}
[Fact]
@@ -2771,7 +2833,8 @@ public sealed class JiboInteractionServiceTests
NormalizedTranscript = "- Thank you. - Yes.",
Attributes = new Dictionary<string, object?>
{
["listenRules"] = (string[])["surprises-date/offer_date_fact", "globals/gui_nav", "globals/global_commands_launch"],
["listenRules"] = (string[])
["surprises-date/offer_date_fact", "globals/gui_nav", "globals/global_commands_launch"],
["listenAsrHints"] = (string[])["$YESNO"],
["context"] = """{"runtime":{"location":{"iso":"2026-04-20T08:00:00-05:00"}}}"""
}
@@ -2792,7 +2855,8 @@ public sealed class JiboInteractionServiceTests
NormalizedTranscript = "- Me. - Yes.",
Attributes = new Dictionary<string, object?>
{
["listenRules"] = (string[])["word-of-the-day/surprise", "globals/gui_nav", "globals/global_commands_launch"],
["listenRules"] = (string[])
["word-of-the-day/surprise", "globals/gui_nav", "globals/global_commands_launch"],
["listenAsrHints"] = (string[])["$YESNO"]
}
});
@@ -3535,7 +3599,8 @@ public sealed class JiboInteractionServiceTests
Assert.Equal("provider_success", decision.SkillPayload["news_provider_status"]);
Assert.Equal(3, decision.SkillPayload["news_provider_requested_headlines"]);
Assert.Equal(2, decision.SkillPayload["news_provider_resolved_headlines"]);
Assert.Contains("Local robotics team unveils weather-ready helper", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains("Local robotics team unveils weather-ready helper", decision.ReplyText,
StringComparison.OrdinalIgnoreCase);
Assert.NotNull(provider.LastRequest);
Assert.Equal(3, provider.LastRequest!.MaxHeadlines);
}
@@ -3562,7 +3627,8 @@ public sealed class JiboInteractionServiceTests
Assert.Equal("news", decision.IntentName);
Assert.NotNull(provider.LastRequest);
Assert.Contains("technology", provider.LastRequest!.PreferredCategories, StringComparer.OrdinalIgnoreCase);
Assert.Contains("artificial intelligence", decision.SkillPayload?["esml"]?.ToString(), StringComparison.OrdinalIgnoreCase);
Assert.Contains("artificial intelligence", decision.SkillPayload?["esml"]?.ToString(),
StringComparison.OrdinalIgnoreCase);
}
[Fact]
@@ -3788,4 +3854,4 @@ public sealed class JiboInteractionServiceTests
return Task.FromResult(catalog);
}
}
}
}

View File

@@ -19,12 +19,12 @@ public sealed class LocalWhisperCppBufferedAudioSttStrategyTests
new FakeExternalProcessRunner());
var turn = new TurnContext
{
Attributes = new Dictionary<string, object?>
{
Attributes = new Dictionary<string, object?>
{
["bufferedAudioFrames"] = new[] { BuildMinimalOggPage() }
}
};
["bufferedAudioFrames"] = new[] { BuildMinimalOggPage() }
}
};
Assert.False(strategy.CanHandle(turn));
}
@@ -119,10 +119,7 @@ public sealed class LocalWhisperCppBufferedAudioSttStrategyTests
}
finally
{
if (Directory.Exists(tempDirectory))
{
Directory.Delete(tempDirectory, recursive: true);
}
if (Directory.Exists(tempDirectory)) Directory.Delete(tempDirectory, true);
}
}
@@ -139,7 +136,8 @@ public sealed class LocalWhisperCppBufferedAudioSttStrategyTests
0x00, 0x00, 0x00, 0x00,
0x01,
0x13,
0x4F, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64, 0x01, 0x01, 0x38, 0x01, 0x80, 0xBB, 0x00, 0x00, 0x00, 0x00, 0x00
0x4F, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64, 0x01, 0x01, 0x38, 0x01, 0x80, 0xBB, 0x00, 0x00, 0x00, 0x00,
0x00
];
}
@@ -154,7 +152,8 @@ public sealed class LocalWhisperCppBufferedAudioSttStrategyTests
{
public List<(string FileName, IReadOnlyList<string> Arguments)> Calls { get; } = [];
public Task<ExternalProcessResult> RunAsync(string fileName, IReadOnlyList<string> arguments, CancellationToken cancellationToken = default)
public Task<ExternalProcessResult> RunAsync(string fileName, IReadOnlyList<string> arguments,
CancellationToken cancellationToken = default)
{
Calls.Add((fileName, arguments));
@@ -165,7 +164,6 @@ public sealed class LocalWhisperCppBufferedAudioSttStrategyTests
var outputPath = arguments[^1];
File.WriteAllBytes(outputPath, "RIFF"u8);
return Task.FromResult(new ExternalProcessResult(0, string.Empty, string.Empty));
}
}
}
}