mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
.NET: Add comprehensive test classes for extension methods in Microsoft.Agents.AI.Workflows.Declarative (#1555)
* Initial plan * Add test classes for extension methods Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> * Fix test issues and document bug in ExpandoObjectExtensions Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> * Address code review feedback - shorten Skip messages and add explanatory comments Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> * Replace Fields.ToDictionary with GetField calls and fix ExpandoObjectExtensions bug Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> * Update dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Extensions/DataValueExtensionsTests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Extensions/DataValueExtensionsTests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Remove unused using statement from DialogBaseExtensionsTests Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> * Add proper WrapWithBot tests using AdaptiveDialog and OnActivity Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> * Cleanup * Better * Better * One more test --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Chris Rickman <crickman@microsoft.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
470cd109c0
commit
c72455508b
+11
-16
@@ -45,23 +45,17 @@ internal static class ChatMessageExtensions
|
||||
|
||||
public static IEnumerable<ChatMessage> ToChatMessages(this TableDataValue messages)
|
||||
{
|
||||
foreach (DataValue message in messages.Values)
|
||||
foreach (RecordDataValue record in messages.Values)
|
||||
{
|
||||
if (message is RecordDataValue record)
|
||||
DataValue sourceRecord = record;
|
||||
if (record.Properties.Count == 1 && record.Properties.TryGetValue("Value", out DataValue? singleColumn))
|
||||
{
|
||||
if (record.Properties.Count == 1 && record.Properties.TryGetValue("Value", out DataValue? singleColumn))
|
||||
{
|
||||
record = singleColumn as RecordDataValue ?? record;
|
||||
}
|
||||
ChatMessage? convertedMessage = record.ToChatMessage();
|
||||
if (convertedMessage is not null)
|
||||
{
|
||||
yield return convertedMessage;
|
||||
}
|
||||
sourceRecord = singleColumn;
|
||||
}
|
||||
else if (message is StringDataValue text)
|
||||
ChatMessage? convertedMessage = sourceRecord.ToChatMessage();
|
||||
if (convertedMessage is not null)
|
||||
{
|
||||
yield return ToChatMessage(text);
|
||||
yield return convertedMessage;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -143,7 +137,7 @@ internal static class ChatMessageExtensions
|
||||
private static ChatRole GetRole(this RecordDataValue message)
|
||||
{
|
||||
StringDataValue? roleValue = message.GetProperty<StringDataValue>(TypeSchema.Message.Fields.Role);
|
||||
if (roleValue is null || string.IsNullOrWhiteSpace(roleValue.Value))
|
||||
if (string.IsNullOrWhiteSpace(roleValue?.Value))
|
||||
{
|
||||
return ChatRole.User;
|
||||
}
|
||||
@@ -164,13 +158,13 @@ internal static class ChatMessageExtensions
|
||||
{
|
||||
foreach (RecordDataValue contentItem in content.Values)
|
||||
{
|
||||
StringDataValue? contentValue = contentItem?.GetProperty<StringDataValue>(TypeSchema.Message.Fields.ContentValue);
|
||||
StringDataValue? contentValue = contentItem.GetProperty<StringDataValue>(TypeSchema.Message.Fields.ContentValue);
|
||||
if (contentValue is null || string.IsNullOrWhiteSpace(contentValue.Value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
yield return
|
||||
contentItem?.GetProperty<StringDataValue>(TypeSchema.Message.Fields.ContentType)?.Value switch
|
||||
contentItem.GetProperty<StringDataValue>(TypeSchema.Message.Fields.ContentType)?.Value switch
|
||||
{
|
||||
TypeSchema.Message.ContentTypes.ImageUrl => GetImageContent(contentValue.Value),
|
||||
TypeSchema.Message.ContentTypes.ImageFile => new HostedFileContent(contentValue.Value),
|
||||
@@ -218,6 +212,7 @@ internal static class ChatMessageExtensions
|
||||
UriContent uriContent => CreateContentRecord(TypeSchema.Message.ContentTypes.ImageUrl, uriContent.Uri.ToString()),
|
||||
HostedFileContent fileContent => CreateContentRecord(TypeSchema.Message.ContentTypes.ImageFile, fileContent.FileId),
|
||||
TextContent textContent => CreateContentRecord(TypeSchema.Message.ContentTypes.Text, textContent.Text),
|
||||
DataContent dataContent => CreateContentRecord(TypeSchema.Message.ContentTypes.ImageUrl, dataContent.Uri),
|
||||
_ => []
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ internal static class ExpandoObjectExtensions
|
||||
|
||||
foreach (KeyValuePair<string, object?> property in value)
|
||||
{
|
||||
recordType.Add(property.Key, property.Value.GetFormulaType());
|
||||
recordType = recordType.Add(property.Key, property.Value.GetFormulaType());
|
||||
}
|
||||
|
||||
return recordType;
|
||||
|
||||
+669
@@ -0,0 +1,669 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
|
||||
using Microsoft.Agents.AI.Workflows.Declarative.PowerFx;
|
||||
using Microsoft.Bot.ObjectModel;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.PowerFx.Types;
|
||||
|
||||
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.Extensions;
|
||||
|
||||
public sealed class ChatMessageExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void ToRecordWithSimpleTextMessage()
|
||||
{
|
||||
// Arrange
|
||||
ChatMessage message = new(ChatRole.User, "Hello World");
|
||||
|
||||
// Act
|
||||
RecordValue result = message.ToRecord();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Contains(result.Fields, f => f.Name == TypeSchema.Message.Fields.Role);
|
||||
Assert.Contains(result.Fields, f => f.Name == TypeSchema.Message.Fields.Text);
|
||||
|
||||
FormulaValue roleField = result.GetField(TypeSchema.Message.Fields.Role);
|
||||
StringValue roleValue = Assert.IsType<StringValue>(roleField);
|
||||
Assert.Equal(ChatRole.User.Value, roleValue.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToRecordWithAssistantMessage()
|
||||
{
|
||||
// Arrange
|
||||
ChatMessage message = new(ChatRole.Assistant, "I can help you");
|
||||
|
||||
// Act
|
||||
RecordValue result = message.ToRecord();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Contains(result.Fields, f => f.Name == TypeSchema.Message.Fields.Role);
|
||||
|
||||
FormulaValue roleField = result.GetField(TypeSchema.Message.Fields.Role);
|
||||
StringValue roleValue = Assert.IsType<StringValue>(roleField);
|
||||
Assert.Equal(ChatRole.Assistant.Value, roleValue.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToRecordIncludesAllStandardFields()
|
||||
{
|
||||
// Arrange
|
||||
ChatMessage message = new(ChatRole.User, "Test")
|
||||
{
|
||||
MessageId = "msg-123"
|
||||
};
|
||||
|
||||
// Act
|
||||
RecordValue result = message.ToRecord();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result.GetField(TypeSchema.Discriminator));
|
||||
Assert.NotNull(result.GetField(TypeSchema.Message.Fields.Id));
|
||||
Assert.NotNull(result.GetField(TypeSchema.Message.Fields.Role));
|
||||
Assert.NotNull(result.GetField(TypeSchema.Message.Fields.Content));
|
||||
Assert.NotNull(result.GetField(TypeSchema.Message.Fields.Text));
|
||||
Assert.NotNull(result.GetField(TypeSchema.Message.Fields.Metadata));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToTableWithMultipleMessages()
|
||||
{
|
||||
// Arrange
|
||||
IEnumerable<ChatMessage> messages =
|
||||
[
|
||||
new(ChatRole.User, "First message"),
|
||||
new(ChatRole.Assistant, "Second message"),
|
||||
new(ChatRole.User, "Third message")
|
||||
];
|
||||
|
||||
// Act
|
||||
TableValue result = messages.ToTable();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(3, result.Rows.Count());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToTableWithEmptyMessages()
|
||||
{
|
||||
// Arrange
|
||||
IEnumerable<ChatMessage> messages = [];
|
||||
|
||||
// Act
|
||||
TableValue result = messages.ToTable();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Empty(result.Rows);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessagesWithNull()
|
||||
{
|
||||
// Arrange
|
||||
DataValue? value = null;
|
||||
|
||||
// Act
|
||||
IEnumerable<ChatMessage>? result = value.ToChatMessages();
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessagesWithBlankDataValue()
|
||||
{
|
||||
// Arrange
|
||||
DataValue value = DataValue.Blank();
|
||||
|
||||
// Act
|
||||
IEnumerable<ChatMessage>? result = value.ToChatMessages();
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessagesWithStringDataValue()
|
||||
{
|
||||
// Arrange
|
||||
DataValue value = StringDataValue.Create("Hello");
|
||||
|
||||
// Act
|
||||
IEnumerable<ChatMessage>? result = value.ToChatMessages();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
ChatMessage message = Assert.Single(result);
|
||||
Assert.Equal(ChatRole.User, message.Role);
|
||||
Assert.Equal("Hello", message.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessagesWithRecordDataValue()
|
||||
{
|
||||
// Arrange
|
||||
ChatMessage source = new(ChatRole.User, "Test");
|
||||
DataValue record = source.ToRecord().ToDataValue();
|
||||
|
||||
// Act
|
||||
IEnumerable<ChatMessage>? result = record.ToChatMessages();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
ChatMessage message = Assert.Single(result);
|
||||
Assert.Equal(source.Role, message.Role);
|
||||
Assert.Equal(source.Text, message.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessagesWithTableDataValue()
|
||||
{
|
||||
// Arrange
|
||||
ChatMessage[] source = [new(ChatRole.User, "Test")];
|
||||
DataValue table = source.ToTable().ToDataValue();
|
||||
|
||||
// Act
|
||||
IEnumerable<ChatMessage>? result = table.ToChatMessages();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
ChatMessage message = Assert.Single(result);
|
||||
Assert.Equal(source[0].Role, message.Role);
|
||||
Assert.Equal(source[0].Text, message.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessagesWithTableOfDataValue()
|
||||
{
|
||||
// Arrange
|
||||
TableDataValue table = DataValue.TableFromValues([new StringDataValue("test")]);
|
||||
|
||||
// Act
|
||||
IEnumerable<ChatMessage>? result = table.ToChatMessages();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
ChatMessage message = Assert.Single(result);
|
||||
Assert.Equal(ChatRole.User, message.Role);
|
||||
Assert.Equal("test", message.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessagesWithUnsupportedValue()
|
||||
{
|
||||
// Arrange
|
||||
BooleanDataValue booleanValue = new(true);
|
||||
|
||||
// Act
|
||||
IEnumerable<ChatMessage>? messages = booleanValue.ToChatMessages();
|
||||
|
||||
// Assert
|
||||
Assert.Null(messages);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessageFromStringDataValue()
|
||||
{
|
||||
// Arrange
|
||||
StringDataValue value = StringDataValue.Create("Test message");
|
||||
|
||||
// Act
|
||||
ChatMessage result = value.ToChatMessage();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(ChatRole.User, result.Role);
|
||||
Assert.Equal("Test message", result.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessageFromDataValueRecord()
|
||||
{
|
||||
// Arrange
|
||||
ChatMessage source = new(ChatRole.User, "Test");
|
||||
DataValue record = source.ToRecord().ToDataValue();
|
||||
|
||||
// Act
|
||||
ChatMessage? result = record.ToChatMessage();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(ChatRole.User, result.Role);
|
||||
Assert.Equal("Test", result.Text);
|
||||
}
|
||||
[Fact]
|
||||
public void ToChatMessageFromDataValueString()
|
||||
{
|
||||
// Arrange
|
||||
DataValue value = StringDataValue.Create("Test message");
|
||||
|
||||
// Act
|
||||
ChatMessage? result = value.ToChatMessage();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(ChatRole.User, result.Role);
|
||||
Assert.Equal("Test message", result.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessageFromBlankDataValue()
|
||||
{
|
||||
// Arrange
|
||||
DataValue value = DataValue.Blank();
|
||||
|
||||
// Act
|
||||
ChatMessage? result = value.ToChatMessage();
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessageFromUnsupportedValue()
|
||||
{
|
||||
// Arrange
|
||||
DataValue value = BooleanDataValue.Create(true);
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<DeclarativeActionException>(() => value.ToChatMessage());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessageFromRecordDataValue()
|
||||
{
|
||||
// Arrange
|
||||
// Note: Use "Agent" not "Assistant" - AgentMessageRole.Agent maps to ChatRole.Assistant
|
||||
RecordDataValue record = DataValue.RecordFromFields(
|
||||
new KeyValuePair<string, DataValue>(TypeSchema.Message.Fields.Role, StringDataValue.Create("Agent")),
|
||||
new KeyValuePair<string, DataValue>(TypeSchema.Message.Fields.Content, DataValue.EmptyTable));
|
||||
|
||||
// Act
|
||||
ChatMessage result = record.ToChatMessage();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(ChatRole.Assistant, result.Role);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessageWithImpliedRole()
|
||||
{
|
||||
// Arrange
|
||||
RecordValue source =
|
||||
FormulaValue.NewRecordFromFields(
|
||||
new NamedValue(TypeSchema.Message.Fields.Role, FormulaValue.New(string.Empty)),
|
||||
new NamedValue(
|
||||
TypeSchema.Message.Fields.Content,
|
||||
FormulaValue.NewTable(
|
||||
TypeSchema.Message.ContentRecordType,
|
||||
FormulaValue.NewRecordFromFields(
|
||||
new NamedValue(TypeSchema.Message.Fields.ContentType, TypeSchema.Message.ContentTypes.Text.ToFormula()),
|
||||
new NamedValue(TypeSchema.Message.Fields.ContentValue, FormulaValue.New("Test"))))));
|
||||
RecordDataValue record = source.ToRecord();
|
||||
|
||||
// Act
|
||||
ChatMessage? result = record.ToChatMessage();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(ChatRole.User, result.Role);
|
||||
Assert.Equal("Test", result.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessageWithImageUrlContentType()
|
||||
{
|
||||
// Arrange
|
||||
ChatMessage source = new(ChatRole.User, [AgentMessageContentType.ImageUrl.ToContent("https://example.com/image.jpg")!]);
|
||||
DataValue record = source.ToRecord().ToDataValue();
|
||||
|
||||
// Act
|
||||
ChatMessage? result = record.ToChatMessage();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
AIContent content = Assert.Single(result.Contents);
|
||||
Assert.IsType<UriContent>(content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessageWithWithImageDataContentType()
|
||||
{
|
||||
// Arrange
|
||||
ChatMessage source = new(ChatRole.User, [AgentMessageContentType.ImageUrl.ToContent("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA")!]);
|
||||
DataValue record = source.ToRecord().ToDataValue();
|
||||
|
||||
// Act
|
||||
ChatMessage? result = record.ToChatMessage();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
AIContent content = Assert.Single(result.Contents);
|
||||
Assert.IsType<DataContent>(content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessageWithWithImageFileContentType()
|
||||
{
|
||||
// Arrange
|
||||
ChatMessage source = new(ChatRole.User, [AgentMessageContentType.ImageFile.ToContent("file-id-123")!]);
|
||||
DataValue record = source.ToRecord().ToDataValue();
|
||||
|
||||
// Act
|
||||
ChatMessage? result = record.ToChatMessage();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
AIContent content = Assert.Single(result.Contents);
|
||||
Assert.IsType<HostedFileContent>(content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessageWithUnsupportedContent()
|
||||
{
|
||||
// Arrange
|
||||
ChatMessage source = new(ChatRole.User, "Test");
|
||||
RecordDataValue record = source.ToRecord().ToRecord();
|
||||
DataValue contentValue = record.Properties[TypeSchema.Message.Fields.Content];
|
||||
TableDataValue contentValues = Assert.IsType<TableDataValue>(contentValue, exactMatch: false);
|
||||
RecordDataValue badContent = DataValue.RecordFromFields(
|
||||
new KeyValuePair<string, DataValue>(TypeSchema.Message.Fields.ContentType, StringDataValue.Create(TypeSchema.Message.ContentTypes.Text)),
|
||||
new KeyValuePair<string, DataValue>(TypeSchema.Message.Fields.ContentValue, BooleanDataValue.Create(true)));
|
||||
contentValues.Values.Add(badContent);
|
||||
|
||||
// Act
|
||||
ChatMessage message = record.ToChatMessage();
|
||||
|
||||
// Assert
|
||||
Assert.Single(message.Contents);
|
||||
Assert.Equal("Test", message.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessageWithEmptyContent()
|
||||
{
|
||||
// Arrange
|
||||
ChatMessage source = new(ChatRole.User, "Test");
|
||||
source.Contents.Add(new TextContent(string.Empty));
|
||||
RecordDataValue record = source.ToRecord().ToRecord();
|
||||
|
||||
// Act
|
||||
ChatMessage message = record.ToChatMessage();
|
||||
|
||||
// Assert
|
||||
Assert.Single(message.Contents);
|
||||
Assert.Equal("Test", message.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToMetadataWithNull()
|
||||
{
|
||||
// Arrange
|
||||
RecordDataValue? metadata = null;
|
||||
|
||||
// Act
|
||||
AdditionalPropertiesDictionary? result = metadata.ToMetadata();
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToMetadataWithProperties()
|
||||
{
|
||||
// Arrange
|
||||
RecordDataValue metadata = DataValue.RecordFromFields(
|
||||
new KeyValuePair<string, DataValue>("key1", StringDataValue.Create("value1")),
|
||||
new KeyValuePair<string, DataValue>("key2", NumberDataValue.Create(42)));
|
||||
|
||||
// Act
|
||||
AdditionalPropertiesDictionary? result = metadata.ToMetadata();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Equal("value1", result["key1"]);
|
||||
Assert.Equal(42m, result["key2"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatRoleFromAgentMessageRole()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.Equal(ChatRole.Assistant, AgentMessageRole.Agent.ToChatRole());
|
||||
Assert.Equal(ChatRole.User, AgentMessageRole.User.ToChatRole());
|
||||
Assert.Equal(ChatRole.User, ((AgentMessageRole)99).ToChatRole());
|
||||
Assert.Equal(ChatRole.User, ((AgentMessageRole?)null).ToChatRole());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AgentMessageContentTypeToContentMissing()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.Null(AgentMessageContentType.Text.ToContent(string.Empty));
|
||||
Assert.Null(AgentMessageContentType.Text.ToContent(null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AgentMessageContentTypeToContentText()
|
||||
{
|
||||
// Arrange & Act
|
||||
AIContent? result = AgentMessageContentType.Text.ToContent("Sample text");
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
TextContent textContent = Assert.IsType<TextContent>(result);
|
||||
Assert.Equal("Sample text", textContent.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToContentWithImageUrlContentType()
|
||||
{
|
||||
// Arrange & Act
|
||||
AIContent? result = AgentMessageContentType.ImageUrl.ToContent("https://example.com/image.jpg");
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
UriContent uriContent = Assert.IsType<UriContent>(result);
|
||||
Assert.Equal("https://example.com/image.jpg", uriContent.Uri.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToContentWithImageUrlContentTypeDataUri()
|
||||
{
|
||||
// Arrange & Act
|
||||
AIContent? result = AgentMessageContentType.ImageUrl.ToContent("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA");
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
DataContent dataContent = Assert.IsType<DataContent>(result);
|
||||
Assert.False(dataContent.Data.IsEmpty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToContentWithImageFileContentType()
|
||||
{
|
||||
// Arrange & Act
|
||||
AIContent? result = AgentMessageContentType.ImageFile.ToContent("file-id-123");
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
HostedFileContent fileContent = Assert.IsType<HostedFileContent>(result);
|
||||
Assert.Equal("file-id-123", fileContent.FileId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessageFromFunctionResultContents()
|
||||
{
|
||||
// Arrange
|
||||
IEnumerable<FunctionResultContent> functionResults =
|
||||
[
|
||||
new(callId: "call1", result: "Result 1"),
|
||||
new(callId: "call2", result: "Result 2")
|
||||
];
|
||||
|
||||
// Act
|
||||
ChatMessage result = functionResults.ToChatMessage();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(ChatRole.Tool, result.Role);
|
||||
Assert.Equal(2, result.Contents.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessagesFromTableDataValueWithStrings()
|
||||
{
|
||||
// Arrange
|
||||
TableDataValue table =
|
||||
DataValue.TableFromValues(
|
||||
[
|
||||
StringDataValue.Create("Message 1"),
|
||||
StringDataValue.Create("Message 2")
|
||||
]);
|
||||
|
||||
// Act
|
||||
IEnumerable<ChatMessage> result = table.ToChatMessages();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(2, result.Count());
|
||||
Assert.All(result, msg => Assert.Equal(ChatRole.User, msg.Role));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessagesFromTableDataValueWithRecords()
|
||||
{
|
||||
// Arrange
|
||||
RecordDataValue record1 = DataValue.RecordFromFields(
|
||||
new KeyValuePair<string, DataValue>(TypeSchema.Message.Fields.Role, StringDataValue.Create("User")),
|
||||
new KeyValuePair<string, DataValue>(TypeSchema.Message.Fields.Content, DataValue.EmptyTable));
|
||||
|
||||
RecordDataValue record2 = DataValue.RecordFromFields(
|
||||
new KeyValuePair<string, DataValue>(TypeSchema.Message.Fields.Role, StringDataValue.Create("Assistant")),
|
||||
new KeyValuePair<string, DataValue>(TypeSchema.Message.Fields.Content, DataValue.EmptyTable));
|
||||
|
||||
TableDataValue table = DataValue.TableFromRecords(record1, record2);
|
||||
|
||||
// Act
|
||||
IEnumerable<ChatMessage> result = table.ToChatMessages();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(2, result.Count());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessagesFromTableDataValueWithSingleColumnRecords()
|
||||
{
|
||||
// Arrange
|
||||
RecordDataValue innerRecord = DataValue.RecordFromFields(
|
||||
new KeyValuePair<string, DataValue>(TypeSchema.Message.Fields.Role, StringDataValue.Create("User")),
|
||||
new KeyValuePair<string, DataValue>(TypeSchema.Message.Fields.Content, DataValue.EmptyTable));
|
||||
|
||||
RecordDataValue wrappedRecord = DataValue.RecordFromFields(
|
||||
new KeyValuePair<string, DataValue>("Value", innerRecord));
|
||||
|
||||
TableDataValue table = DataValue.TableFromRecords(wrappedRecord);
|
||||
|
||||
// Act
|
||||
IEnumerable<ChatMessage> result = table.ToChatMessages();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
ChatMessage message = Assert.Single(result);
|
||||
Assert.Equal(ChatRole.User, message.Role);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToRecordWithMessageContainingMultipleContentItems()
|
||||
{
|
||||
// Arrange
|
||||
ChatMessage message =
|
||||
new(ChatRole.User,
|
||||
[
|
||||
new TextContent("First part"),
|
||||
new TextContent("Second part")
|
||||
]);
|
||||
|
||||
// Act
|
||||
RecordValue result = message.ToRecord();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
FormulaValue contentField = result.GetField(TypeSchema.Message.Fields.Content);
|
||||
TableValue contentTable = Assert.IsType<TableValue>(contentField, exactMatch: false);
|
||||
Assert.Equal(2, contentTable.Rows.Count());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToRecordWithMessageContainingUriContent()
|
||||
{
|
||||
// Arrange
|
||||
ChatMessage message =
|
||||
new(ChatRole.User,
|
||||
[
|
||||
new UriContent("https://example.com/image.jpg", "image/*")
|
||||
]);
|
||||
|
||||
// Act
|
||||
RecordValue result = message.ToRecord();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
FormulaValue contentField = result.GetField(TypeSchema.Message.Fields.Content);
|
||||
TableValue contentTable = Assert.IsType<TableValue>(contentField, exactMatch: false);
|
||||
Assert.Single(contentTable.Rows);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToRecordWithMessageContainingHostedFileContent()
|
||||
{
|
||||
// Arrange
|
||||
ChatMessage message =
|
||||
new(ChatRole.User,
|
||||
[
|
||||
new HostedFileContent("file-123")
|
||||
]);
|
||||
|
||||
// Act
|
||||
RecordValue result = message.ToRecord();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
FormulaValue contentField = result.GetField(TypeSchema.Message.Fields.Content);
|
||||
TableValue contentTable = Assert.IsType<TableValue>(contentField, exactMatch: false);
|
||||
Assert.Single(contentTable.Rows);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToRecordWithMessageContainingMetadata()
|
||||
{
|
||||
// Arrange
|
||||
ChatMessage message = new(ChatRole.User, "Test message")
|
||||
{
|
||||
AdditionalProperties = new AdditionalPropertiesDictionary
|
||||
{
|
||||
["custom_key"] = "custom_value",
|
||||
["count"] = 5
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
RecordValue result = message.ToRecord();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
FormulaValue metadataField = result.GetField(TypeSchema.Message.Fields.Metadata);
|
||||
RecordValue metadataRecord = Assert.IsType<RecordValue>(metadataField, exactMatch: false);
|
||||
Assert.Equal(2, metadataRecord.Fields.Count());
|
||||
}
|
||||
}
|
||||
+845
@@ -0,0 +1,845 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
|
||||
using Microsoft.Agents.AI.Workflows.Declarative.Kit;
|
||||
using Microsoft.Bot.ObjectModel;
|
||||
using Microsoft.PowerFx.Types;
|
||||
|
||||
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.Extensions;
|
||||
|
||||
public sealed class DataValueExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void ToDataValueWithNull()
|
||||
{
|
||||
// Arrange
|
||||
object? value = null;
|
||||
|
||||
// Act
|
||||
DataValue result = value.ToDataValue();
|
||||
|
||||
// Assert
|
||||
Assert.IsType<BlankDataValue>(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToDataValueWithUnassignedValue()
|
||||
{
|
||||
// Arrange
|
||||
object value = UnassignedValue.Instance;
|
||||
|
||||
// Act
|
||||
DataValue result = value.ToDataValue();
|
||||
|
||||
// Assert
|
||||
Assert.IsType<BlankDataValue>(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToDataValueWithBooleanTrue()
|
||||
{
|
||||
// Arrange
|
||||
const bool Value = true;
|
||||
|
||||
// Act
|
||||
DataValue result = Value.ToDataValue();
|
||||
|
||||
// Assert
|
||||
BooleanDataValue boolValue = Assert.IsType<BooleanDataValue>(result);
|
||||
Assert.True(boolValue.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToDataValueWithBooleanFalse()
|
||||
{
|
||||
// Arrange
|
||||
const bool Value = false;
|
||||
|
||||
// Act
|
||||
DataValue result = Value.ToDataValue();
|
||||
|
||||
// Assert
|
||||
BooleanDataValue boolValue = Assert.IsType<BooleanDataValue>(result);
|
||||
Assert.False(boolValue.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToDataValueWithInt()
|
||||
{
|
||||
// Arrange
|
||||
const int Value = 42;
|
||||
|
||||
// Act
|
||||
DataValue result = Value.ToDataValue();
|
||||
|
||||
// Assert
|
||||
NumberDataValue numberValue = Assert.IsType<NumberDataValue>(result);
|
||||
Assert.Equal(42, numberValue.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToDataValueWithLong()
|
||||
{
|
||||
// Arrange
|
||||
const long Value = 9876543210L;
|
||||
|
||||
// Act
|
||||
DataValue result = Value.ToDataValue();
|
||||
|
||||
// Assert
|
||||
NumberDataValue numberValue = Assert.IsType<NumberDataValue>(result);
|
||||
Assert.Equal(9876543210L, numberValue.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToDataValueWithFloat()
|
||||
{
|
||||
// Arrange
|
||||
const float Value = 3.14f;
|
||||
|
||||
// Act
|
||||
DataValue result = Value.ToDataValue();
|
||||
|
||||
// Assert
|
||||
FloatDataValue floatValue = Assert.IsType<FloatDataValue>(result);
|
||||
Assert.Equal(3.14f, floatValue.Value, precision: 2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToDataValueWithDecimal()
|
||||
{
|
||||
// Arrange
|
||||
const decimal Value = 123.456m;
|
||||
|
||||
// Act
|
||||
DataValue result = Value.ToDataValue();
|
||||
|
||||
// Assert
|
||||
NumberDataValue numberValue = Assert.IsType<NumberDataValue>(result);
|
||||
Assert.Equal(123.456m, numberValue.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToDataValueWithDouble()
|
||||
{
|
||||
// Arrange
|
||||
const double Value = 2.71828;
|
||||
|
||||
// Act
|
||||
DataValue result = Value.ToDataValue();
|
||||
|
||||
// Assert
|
||||
FloatDataValue floatValue = Assert.IsType<FloatDataValue>(result);
|
||||
Assert.Equal(2.71828, floatValue.Value, precision: 5);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToDataValueWithString()
|
||||
{
|
||||
// Arrange
|
||||
const string Value = "Test String";
|
||||
|
||||
// Act
|
||||
DataValue result = Value.ToDataValue();
|
||||
|
||||
// Assert
|
||||
StringDataValue stringValue = Assert.IsType<StringDataValue>(result);
|
||||
Assert.Equal("Test String", stringValue.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToDataValueWithDateTimeZeroTime()
|
||||
{
|
||||
// Arrange
|
||||
DateTime value = new(2025, 10, 17, 0, 0, 0);
|
||||
|
||||
// Act
|
||||
DataValue result = value.ToDataValue();
|
||||
|
||||
// Assert
|
||||
DateDataValue dateValue = Assert.IsType<DateDataValue>(result);
|
||||
Assert.Equal(new DateTime(2025, 10, 17), dateValue.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToDataValueWithDateTimeNonZeroTime()
|
||||
{
|
||||
// Arrange
|
||||
DateTime value = new(2025, 10, 17, 14, 30, 45);
|
||||
|
||||
// Act
|
||||
DataValue result = value.ToDataValue();
|
||||
|
||||
// Assert
|
||||
DateTimeDataValue dateTimeValue = Assert.IsType<DateTimeDataValue>(result);
|
||||
Assert.Equal(new DateTime(2025, 10, 17, 14, 30, 45), dateTimeValue.Value.DateTime);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToDataValueWithTimeSpan()
|
||||
{
|
||||
// Arrange
|
||||
TimeSpan value = TimeSpan.FromHours(2.5);
|
||||
|
||||
// Act
|
||||
DataValue result = value.ToDataValue();
|
||||
|
||||
// Assert
|
||||
TimeDataValue timeValue = Assert.IsType<TimeDataValue>(result);
|
||||
Assert.Equal(TimeSpan.FromHours(2.5), timeValue.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToDataValueWithDataValue()
|
||||
{
|
||||
// Arrange
|
||||
DataValue value = StringDataValue.Create("Already a DataValue");
|
||||
|
||||
// Act
|
||||
DataValue result = value.ToDataValue();
|
||||
|
||||
// Assert
|
||||
Assert.Same(value, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToDataValueWithFormulaValue()
|
||||
{
|
||||
// Arrange
|
||||
FormulaValue value = FormulaValue.New(123);
|
||||
|
||||
// Act
|
||||
DataValue result = value.ToDataValue();
|
||||
|
||||
// Assert
|
||||
NumberDataValue numberValue = Assert.IsType<NumberDataValue>(result);
|
||||
Assert.Equal(123, numberValue.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToFormulaWithNull()
|
||||
{
|
||||
// Arrange
|
||||
DataValue? value = null;
|
||||
|
||||
// Act
|
||||
FormulaValue result = value.ToFormula();
|
||||
|
||||
// Assert
|
||||
Assert.IsType<BlankValue>(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToFormulaWithBlankDataValue()
|
||||
{
|
||||
// Arrange
|
||||
DataValue value = DataValue.Blank();
|
||||
|
||||
// Act
|
||||
FormulaValue result = value.ToFormula();
|
||||
|
||||
// Assert
|
||||
Assert.IsType<BlankValue>(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToFormulaWithBooleanDataValue()
|
||||
{
|
||||
// Arrange
|
||||
DataValue value = BooleanDataValue.Create(true);
|
||||
|
||||
// Act
|
||||
FormulaValue result = value.ToFormula();
|
||||
|
||||
// Assert
|
||||
BooleanValue boolValue = Assert.IsType<BooleanValue>(result);
|
||||
Assert.True(boolValue.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToFormulaWithNumberDataValue()
|
||||
{
|
||||
// Arrange
|
||||
DataValue value = NumberDataValue.Create(99.5m);
|
||||
|
||||
// Act
|
||||
FormulaValue result = value.ToFormula();
|
||||
|
||||
// Assert
|
||||
DecimalValue decimalValue = Assert.IsType<DecimalValue>(result);
|
||||
Assert.Equal(99.5m, decimalValue.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToFormulaWithFloatDataValue()
|
||||
{
|
||||
// Arrange
|
||||
DataValue value = FloatDataValue.Create(1.23);
|
||||
|
||||
// Act
|
||||
FormulaValue result = value.ToFormula();
|
||||
|
||||
// Assert
|
||||
NumberValue numberValue = Assert.IsType<NumberValue>(result);
|
||||
Assert.Equal(1.23, numberValue.Value, precision: 2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToFormulaWithStringDataValue()
|
||||
{
|
||||
// Arrange
|
||||
DataValue value = StringDataValue.Create("Test");
|
||||
|
||||
// Act
|
||||
FormulaValue result = value.ToFormula();
|
||||
|
||||
// Assert
|
||||
StringValue stringValue = Assert.IsType<StringValue>(result);
|
||||
Assert.Equal("Test", stringValue.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToFormulaWithDateTimeDataValue()
|
||||
{
|
||||
// Arrange
|
||||
DateTime dateTime = new(2025, 10, 17, 12, 0, 0);
|
||||
DataValue value = DateTimeDataValue.Create(dateTime);
|
||||
|
||||
// Act
|
||||
FormulaValue result = value.ToFormula();
|
||||
|
||||
// Assert
|
||||
DateTimeValue dateTimeValue = Assert.IsType<DateTimeValue>(result);
|
||||
Assert.Equal(dateTime, dateTimeValue.GetConvertedValue(TimeZoneInfo.Utc));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToFormulaWithDateDataValue()
|
||||
{
|
||||
// Arrange
|
||||
DateTime date = new(2025, 10, 17);
|
||||
DataValue value = DateDataValue.Create(date);
|
||||
|
||||
// Act
|
||||
FormulaValue result = value.ToFormula();
|
||||
|
||||
// Assert
|
||||
DateValue dateValue = Assert.IsType<DateValue>(result);
|
||||
Assert.Equal(date, dateValue.GetConvertedValue(TimeZoneInfo.Utc));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToFormulaWithTimeDataValue()
|
||||
{
|
||||
// Arrange
|
||||
TimeSpan time = TimeSpan.FromHours(3);
|
||||
DataValue value = TimeDataValue.Create(time);
|
||||
|
||||
// Act
|
||||
FormulaValue result = value.ToFormula();
|
||||
|
||||
// Assert
|
||||
TimeValue timeValue = Assert.IsType<TimeValue>(result);
|
||||
Assert.Equal(time, timeValue.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToFormulaWithRecordDataValue()
|
||||
{
|
||||
// Arrange
|
||||
DataValue value = DataValue.RecordFromFields(
|
||||
new KeyValuePair<string, DataValue>("Name", StringDataValue.Create("John")),
|
||||
new KeyValuePair<string, DataValue>("Age", NumberDataValue.Create(30)));
|
||||
|
||||
// Act
|
||||
FormulaValue result = value.ToFormula();
|
||||
|
||||
// Assert
|
||||
RecordValue recordValue = Assert.IsType<RecordValue>(result, exactMatch: false);
|
||||
Assert.Equal(2, recordValue.Fields.Count());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToFormulaWithTableDataValue()
|
||||
{
|
||||
// Arrange
|
||||
RecordDataValue record = DataValue.RecordFromFields(
|
||||
new KeyValuePair<string, DataValue>("Field", StringDataValue.Create("Value")));
|
||||
DataValue value = DataValue.TableFromRecords(ImmutableArray.Create(record));
|
||||
|
||||
// Act
|
||||
FormulaValue result = value.ToFormula();
|
||||
|
||||
// Assert
|
||||
TableValue tableValue = Assert.IsType<TableValue>(result, exactMatch: false);
|
||||
Assert.Single(tableValue.Rows);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToFormulaTypeWithNull()
|
||||
{
|
||||
// Arrange
|
||||
DataValue? value = null;
|
||||
|
||||
// Act
|
||||
FormulaType result = value.ToFormulaType();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(FormulaType.Blank, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToFormulaTypeWithBooleanDataValue()
|
||||
{
|
||||
// Arrange
|
||||
DataValue value = BooleanDataValue.Create(true);
|
||||
|
||||
// Act
|
||||
FormulaType result = value.ToFormulaType();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(FormulaType.Boolean, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToFormulaTypeWithStringDataValue()
|
||||
{
|
||||
// Arrange
|
||||
DataValue value = StringDataValue.Create("Test");
|
||||
|
||||
// Act
|
||||
FormulaType result = value.ToFormulaType();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(FormulaType.String, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataTypeToFormulaTypeWithNull()
|
||||
{
|
||||
// Arrange
|
||||
DataType? type = null;
|
||||
|
||||
// Act
|
||||
FormulaType result = type.ToFormulaType();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(FormulaType.Blank, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataTypeToFormulaTypeWithBooleanDataType()
|
||||
{
|
||||
// Arrange
|
||||
DataType type = BooleanDataType.Instance;
|
||||
|
||||
// Act
|
||||
FormulaType result = type.ToFormulaType();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(FormulaType.Boolean, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataTypeToFormulaTypeWithNumberDataType()
|
||||
{
|
||||
// Arrange
|
||||
DataType type = NumberDataType.Instance;
|
||||
|
||||
// Act
|
||||
FormulaType result = type.ToFormulaType();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(FormulaType.Decimal, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataTypeToFormulaTypeWithFloatDataType()
|
||||
{
|
||||
// Arrange
|
||||
DataType type = FloatDataType.Instance;
|
||||
|
||||
// Act
|
||||
FormulaType result = type.ToFormulaType();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(FormulaType.Number, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataTypeToFormulaTypeWithStringDataType()
|
||||
{
|
||||
// Arrange
|
||||
DataType type = StringDataType.Instance;
|
||||
|
||||
// Act
|
||||
FormulaType result = type.ToFormulaType();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(FormulaType.String, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataTypeToFormulaTypeWithDateTimeDataType()
|
||||
{
|
||||
// Arrange
|
||||
DataType type = DateTimeDataType.Instance;
|
||||
|
||||
// Act
|
||||
FormulaType result = type.ToFormulaType();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(FormulaType.DateTime, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataTypeToFormulaTypeWithDateDataType()
|
||||
{
|
||||
// Arrange
|
||||
DataType type = DateDataType.Instance;
|
||||
|
||||
// Act
|
||||
FormulaType result = type.ToFormulaType();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(FormulaType.Date, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataTypeToFormulaTypeWithTimeDataType()
|
||||
{
|
||||
// Arrange
|
||||
DataType type = TimeDataType.Instance;
|
||||
|
||||
// Act
|
||||
FormulaType result = type.ToFormulaType();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(FormulaType.Time, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToObjectWithNull()
|
||||
{
|
||||
// Arrange
|
||||
DataValue? value = null;
|
||||
|
||||
// Act
|
||||
object? result = value.ToObject();
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToObjectWithBlankDataValue()
|
||||
{
|
||||
// Arrange
|
||||
DataValue value = DataValue.Blank();
|
||||
|
||||
// Act
|
||||
object? result = value.ToObject();
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToObjectWithBooleanDataValue()
|
||||
{
|
||||
// Arrange
|
||||
DataValue value = BooleanDataValue.Create(true);
|
||||
|
||||
// Act
|
||||
object? result = value.ToObject();
|
||||
|
||||
// Assert
|
||||
Assert.IsType<bool>(result);
|
||||
Assert.True((bool)result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToObjectWithNumberDataValue()
|
||||
{
|
||||
// Arrange
|
||||
DataValue value = NumberDataValue.Create(42.5m);
|
||||
|
||||
// Act
|
||||
object? result = value.ToObject();
|
||||
|
||||
// Assert
|
||||
Assert.IsType<decimal>(result);
|
||||
Assert.Equal(42.5m, (decimal)result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToObjectWithStringDataValue()
|
||||
{
|
||||
// Arrange
|
||||
DataValue value = StringDataValue.Create("Hello");
|
||||
|
||||
// Act
|
||||
object? result = value.ToObject();
|
||||
|
||||
// Assert
|
||||
Assert.IsType<string>(result);
|
||||
Assert.Equal("Hello", (string)result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToClrTypeWithBooleanDataType()
|
||||
{
|
||||
// Arrange
|
||||
DataType type = BooleanDataType.Instance;
|
||||
|
||||
// Act
|
||||
Type result = type.ToClrType();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(typeof(bool), result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToClrTypeWithNumberDataType()
|
||||
{
|
||||
// Arrange
|
||||
DataType type = NumberDataType.Instance;
|
||||
|
||||
// Act
|
||||
Type result = type.ToClrType();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(typeof(decimal), result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToClrTypeWithFloatDataType()
|
||||
{
|
||||
// Arrange
|
||||
DataType type = FloatDataType.Instance;
|
||||
|
||||
// Act
|
||||
Type result = type.ToClrType();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(typeof(double), result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToClrTypeWithStringDataType()
|
||||
{
|
||||
// Arrange
|
||||
DataType type = StringDataType.Instance;
|
||||
|
||||
// Act
|
||||
Type result = type.ToClrType();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(typeof(string), result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToClrTypeWithDateTimeDataType()
|
||||
{
|
||||
// Arrange
|
||||
DataType type = DateTimeDataType.Instance;
|
||||
|
||||
// Act
|
||||
Type result = type.ToClrType();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(typeof(DateTime), result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToClrTypeWithTimeDataType()
|
||||
{
|
||||
// Arrange
|
||||
DataType type = TimeDataType.Instance;
|
||||
|
||||
// Act
|
||||
Type result = type.ToClrType();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(typeof(TimeSpan), result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AsListWithNull()
|
||||
{
|
||||
// Arrange
|
||||
DataValue? value = null;
|
||||
|
||||
// Act
|
||||
IList<string>? result = value.AsList<string>();
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AsListWithBlankDataValue()
|
||||
{
|
||||
// Arrange
|
||||
DataValue value = DataValue.Blank();
|
||||
|
||||
// Act
|
||||
IList<string>? result = value.AsList<string>();
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NewBlankWithNullDataType()
|
||||
{
|
||||
// Arrange
|
||||
DataType? type = null;
|
||||
|
||||
// Act
|
||||
FormulaValue result = type.NewBlank();
|
||||
|
||||
// Assert
|
||||
Assert.IsType<BlankValue>(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NewBlankWithBooleanDataType()
|
||||
{
|
||||
// Arrange
|
||||
DataType type = BooleanDataType.Instance;
|
||||
|
||||
// Act
|
||||
FormulaValue result = type.NewBlank();
|
||||
|
||||
// Assert
|
||||
Assert.IsType<BlankValue>(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToRecordValueWithRecordDataValue()
|
||||
{
|
||||
// Arrange
|
||||
RecordDataValue recordDataValue = DataValue.RecordFromFields(
|
||||
new KeyValuePair<string, DataValue>("Field1", StringDataValue.Create("Value1")),
|
||||
new KeyValuePair<string, DataValue>("Field2", NumberDataValue.Create(123)));
|
||||
|
||||
// Act
|
||||
RecordValue result = recordDataValue.ToRecordValue();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(2, result.Fields.Count());
|
||||
|
||||
Assert.NotNull(result.GetField("Field1"));
|
||||
Assert.NotNull(result.GetField("Field2"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToRecordTypeWithRecordDataType()
|
||||
{
|
||||
// Arrange
|
||||
RecordDataType recordDataType = new RecordDataType.Builder
|
||||
{
|
||||
Properties =
|
||||
{
|
||||
["Name"] = new PropertyInfo.Builder
|
||||
{
|
||||
Type = StringDataType.Instance
|
||||
}.Build(),
|
||||
["Count"] = new PropertyInfo.Builder
|
||||
{
|
||||
Type = NumberDataType.Instance
|
||||
}.Build()
|
||||
}
|
||||
}.Build();
|
||||
|
||||
// Act
|
||||
RecordType result = recordDataType.ToRecordType();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
IEnumerable<NamedFormulaType> fieldTypes = result.GetFieldTypes();
|
||||
List<NamedFormulaType> fieldTypesList = fieldTypes.ToList();
|
||||
Assert.Equal(2, fieldTypesList.Count);
|
||||
|
||||
IEnumerable<string> fieldNames = fieldTypesList.Select(f => f.Name.Value);
|
||||
Assert.Contains("Name", fieldNames);
|
||||
Assert.Contains("Count", fieldNames);
|
||||
|
||||
NamedFormulaType nameField = fieldTypesList.First(f => f.Name.Value == "Name");
|
||||
NamedFormulaType countField = fieldTypesList.First(f => f.Name.Value == "Count");
|
||||
Assert.Equal(FormulaType.String, nameField.Type);
|
||||
Assert.Equal(FormulaType.Decimal, countField.Type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToRecordValueWithDictionary()
|
||||
{
|
||||
// Arrange
|
||||
IDictionary dictionary = new Dictionary<string, object>
|
||||
{
|
||||
["Key1"] = "Value1",
|
||||
["Key2"] = 42
|
||||
};
|
||||
|
||||
// Act
|
||||
RecordDataValue result = dictionary.ToRecordValue();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(2, result.Properties.Count);
|
||||
Assert.True(result.Properties.ContainsKey("Key1"));
|
||||
Assert.True(result.Properties.ContainsKey("Key2"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToTableValueWithEmptyEnumerable()
|
||||
{
|
||||
// Arrange
|
||||
IEnumerable enumerable = Array.Empty<object>();
|
||||
|
||||
// Act
|
||||
TableDataValue result = enumerable.ToTableValue();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Empty(result.Values);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToTableValueWithDictionaryEnumerable()
|
||||
{
|
||||
// Arrange
|
||||
IEnumerable enumerable = new List<IDictionary>
|
||||
{
|
||||
new Dictionary<string, object> { ["Name"] = "Alice", ["Age"] = 30 },
|
||||
new Dictionary<string, object> { ["Name"] = "Bob", ["Age"] = 25 }
|
||||
};
|
||||
|
||||
// Act
|
||||
TableDataValue result = enumerable.ToTableValue();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToTableValueWithPrimitiveEnumerable()
|
||||
{
|
||||
// Arrange
|
||||
IEnumerable enumerable = new List<int> { 1, 2, 3 };
|
||||
|
||||
// Act
|
||||
TableDataValue result = enumerable.ToTableValue();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(3, result.Values.Length);
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
|
||||
using Microsoft.PowerFx;
|
||||
using Moq;
|
||||
|
||||
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.Extensions;
|
||||
|
||||
public sealed class DeclarativeWorkflowOptionsExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void NullContext_UsesDefaultMaximumExpressionLength()
|
||||
{
|
||||
// Arrange
|
||||
DeclarativeWorkflowOptions? options = null;
|
||||
|
||||
// Act
|
||||
RecalcEngine engine = options.CreateRecalcEngine();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(engine);
|
||||
Assert.Equal(10000, engine.Config.MaximumExpressionLength);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OptionsWithoutLimits_UsesDefaults()
|
||||
{
|
||||
// Arrange
|
||||
DeclarativeWorkflowOptions options = CreateOptions();
|
||||
|
||||
// Act
|
||||
RecalcEngine engine = options.CreateRecalcEngine();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(engine);
|
||||
Assert.Equal(10000, engine.Config.MaximumExpressionLength);
|
||||
Assert.True(engine.Config.MaxCallDepth >= 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OptionsWithBothLimits()
|
||||
{
|
||||
// Arrange
|
||||
const int ExpectedLength = 5000;
|
||||
const int ExpectedDepth = 12;
|
||||
DeclarativeWorkflowOptions context = CreateOptions(ExpectedLength, ExpectedDepth);
|
||||
|
||||
// Act
|
||||
RecalcEngine engine = context.CreateRecalcEngine();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(ExpectedLength, engine.Config.MaximumExpressionLength);
|
||||
Assert.Equal(ExpectedDepth, engine.Config.MaxCallDepth);
|
||||
}
|
||||
|
||||
// Factory for creating options and mock provider
|
||||
private static DeclarativeWorkflowOptions CreateOptions(
|
||||
int? maximumExpressionLength = null,
|
||||
int? maximumCallDepth = null)
|
||||
{
|
||||
Mock<WorkflowAgentProvider> providerMock = new(MockBehavior.Strict);
|
||||
return
|
||||
new(providerMock.Object)
|
||||
{
|
||||
MaximumExpressionLength = maximumExpressionLength,
|
||||
MaximumCallDepth = maximumCallDepth
|
||||
};
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
|
||||
using Microsoft.Bot.ObjectModel;
|
||||
|
||||
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for <see cref="DialogBaseExtensions"/>.
|
||||
/// </summary>
|
||||
public sealed class DialogBaseExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void WrapWithBotCreatesValidBotDefinition()
|
||||
{
|
||||
// Arrange
|
||||
AdaptiveDialog dialog = new AdaptiveDialog.Builder()
|
||||
{
|
||||
BeginDialog = new OnActivity.Builder()
|
||||
{
|
||||
Id = "test_dialog",
|
||||
},
|
||||
}.Build();
|
||||
|
||||
// Assert
|
||||
Assert.False(dialog.HasSchemaName);
|
||||
|
||||
// Act
|
||||
AdaptiveDialog wrappedDialog = dialog.WrapWithBot();
|
||||
|
||||
// Assert
|
||||
VerifyWrappedDialog(wrappedDialog);
|
||||
|
||||
// Act & Assert
|
||||
VerifyWrappedDialog(wrappedDialog.WrapWithBot());
|
||||
}
|
||||
|
||||
private static void VerifyWrappedDialog(AdaptiveDialog wrappedDialog)
|
||||
{
|
||||
Assert.NotNull(wrappedDialog);
|
||||
Assert.NotNull(wrappedDialog.BeginDialog);
|
||||
Assert.Equal("test_dialog", wrappedDialog.BeginDialog.Id);
|
||||
Assert.True(wrappedDialog.HasSchemaName);
|
||||
}
|
||||
}
|
||||
+217
@@ -0,0 +1,217 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
|
||||
using Microsoft.PowerFx.Types;
|
||||
|
||||
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.Extensions;
|
||||
|
||||
public sealed class ExpandoObjectExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void ToRecordTypeWithEmptyExpandoObject()
|
||||
{
|
||||
// Arrange
|
||||
ExpandoObject expando = new();
|
||||
|
||||
// Act
|
||||
RecordType recordType = expando.ToRecordType();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(recordType);
|
||||
Assert.Empty(recordType.GetFieldTypes());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToRecordTypeWithStringProperty()
|
||||
{
|
||||
// Arrange
|
||||
dynamic expando = new ExpandoObject();
|
||||
expando.Name = "John Doe";
|
||||
|
||||
// Act
|
||||
RecordType recordType = ((ExpandoObject)expando).ToRecordType();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(recordType);
|
||||
IEnumerable<NamedFormulaType> fieldTypes = recordType.GetFieldTypes();
|
||||
Assert.Single(fieldTypes);
|
||||
NamedFormulaType field = fieldTypes.First();
|
||||
Assert.Equal("Name", field.Name.Value);
|
||||
Assert.Equal(FormulaType.String, field.Type);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToRecordTypeWithMultipleProperties()
|
||||
{
|
||||
// Arrange
|
||||
dynamic expando = new ExpandoObject();
|
||||
expando.Name = "Alice";
|
||||
expando.Age = 30;
|
||||
expando.IsActive = true;
|
||||
|
||||
// Act
|
||||
RecordType recordType = ((ExpandoObject)expando).ToRecordType();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(recordType);
|
||||
IEnumerable<NamedFormulaType> fieldTypes = recordType.GetFieldTypes();
|
||||
Assert.Equal(3, fieldTypes.Count());
|
||||
IEnumerable<string> fieldNames = fieldTypes.Select(f => f.Name.Value);
|
||||
Assert.Contains("Name", fieldNames);
|
||||
Assert.Contains("Age", fieldNames);
|
||||
Assert.Contains("IsActive", fieldNames);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToRecordTypeWithNullProperty()
|
||||
{
|
||||
// Arrange
|
||||
dynamic expando = new ExpandoObject();
|
||||
expando.Name = "Test";
|
||||
expando.NullValue = null;
|
||||
|
||||
// Act
|
||||
RecordType recordType = ((ExpandoObject)expando).ToRecordType();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(recordType);
|
||||
IEnumerable<NamedFormulaType> fieldTypes = recordType.GetFieldTypes();
|
||||
Assert.Equal(2, fieldTypes.Count());
|
||||
IEnumerable<string> fieldNames = fieldTypes.Select(f => f.Name.Value);
|
||||
Assert.Contains("Name", fieldNames);
|
||||
Assert.Contains("NullValue", fieldNames);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToRecordWithEmptyExpandoObject()
|
||||
{
|
||||
// Arrange
|
||||
ExpandoObject expando = new();
|
||||
|
||||
// Act
|
||||
RecordValue recordValue = expando.ToRecord();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(recordValue);
|
||||
Assert.Empty(recordValue.Fields);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToRecordWithStringProperty()
|
||||
{
|
||||
// Arrange
|
||||
dynamic expando = new ExpandoObject();
|
||||
expando.Message = "Hello World";
|
||||
|
||||
// Act
|
||||
RecordValue recordValue = ((ExpandoObject)expando).ToRecord();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(recordValue);
|
||||
Assert.Single(recordValue.Fields);
|
||||
NamedValue field = recordValue.Fields.First();
|
||||
Assert.Equal("Message", field.Name);
|
||||
StringValue stringValue = Assert.IsType<StringValue>(field.Value);
|
||||
Assert.Equal("Hello World", stringValue.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToRecordWithMultiplePropertiesOfDifferentTypes()
|
||||
{
|
||||
// Arrange
|
||||
dynamic expando = new ExpandoObject();
|
||||
expando.Name = "Bob";
|
||||
expando.Count = 42;
|
||||
expando.Active = true;
|
||||
|
||||
// Act
|
||||
RecordValue recordValue = ((ExpandoObject)expando).ToRecord();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(recordValue);
|
||||
Assert.Equal(3, recordValue.Fields.Count());
|
||||
|
||||
FormulaValue nameField = recordValue.GetField("Name");
|
||||
StringValue nameValue = Assert.IsType<StringValue>(nameField);
|
||||
Assert.Equal("Bob", nameValue.Value);
|
||||
|
||||
FormulaValue countField = recordValue.GetField("Count");
|
||||
DecimalValue countValue = Assert.IsType<DecimalValue>(countField);
|
||||
Assert.Equal(42, countValue.Value);
|
||||
|
||||
FormulaValue activeField = recordValue.GetField("Active");
|
||||
BooleanValue activeValue = Assert.IsType<BooleanValue>(activeField);
|
||||
Assert.True(activeValue.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToRecordWithNestedExpandoObject()
|
||||
{
|
||||
// Arrange
|
||||
dynamic nested = new ExpandoObject();
|
||||
nested.InnerValue = "Inner";
|
||||
|
||||
dynamic expando = new ExpandoObject();
|
||||
expando.Outer = "Outer";
|
||||
expando.Nested = nested;
|
||||
|
||||
// Act
|
||||
RecordValue recordValue = ((ExpandoObject)expando).ToRecord();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(recordValue);
|
||||
Assert.Equal(2, recordValue.Fields.Count());
|
||||
|
||||
Assert.NotNull(recordValue.GetField("Outer"));
|
||||
FormulaValue nestedField = recordValue.GetField("Nested");
|
||||
Assert.NotNull(nestedField);
|
||||
|
||||
RecordValue nestedRecord = Assert.IsType<RecordValue>(nestedField, exactMatch: false);
|
||||
Assert.Single(nestedRecord.Fields);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToRecordWithNullProperty()
|
||||
{
|
||||
// Arrange
|
||||
dynamic expando = new ExpandoObject();
|
||||
expando.Name = "Test";
|
||||
expando.NullValue = null;
|
||||
|
||||
// Act
|
||||
RecordValue recordValue = ((ExpandoObject)expando).ToRecord();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(recordValue);
|
||||
Assert.Equal(2, recordValue.Fields.Count());
|
||||
|
||||
FormulaValue nullField = recordValue.GetField("NullValue");
|
||||
Assert.IsType<BlankValue>(nullField);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToRecordTypeAndToRecordAreConsistent()
|
||||
{
|
||||
// Arrange
|
||||
dynamic expando = new ExpandoObject();
|
||||
expando.StringField = "Value";
|
||||
expando.IntField = 123;
|
||||
expando.BoolField = false;
|
||||
|
||||
// Act
|
||||
RecordType recordType = ((ExpandoObject)expando).ToRecordType();
|
||||
RecordValue recordValue = ((ExpandoObject)expando).ToRecord();
|
||||
|
||||
// Assert
|
||||
List<NamedFormulaType> fieldTypesList = recordType.GetFieldTypes().ToList();
|
||||
Assert.Equal(fieldTypesList.Count, recordValue.Fields.Count());
|
||||
|
||||
foreach (NamedFormulaType fieldType in fieldTypesList)
|
||||
{
|
||||
Assert.Contains(recordValue.Fields, f => f.Name == fieldType.Name.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Agents.AI.Workflows.Declarative.Extensions;
|
||||
using Microsoft.Bot.ObjectModel;
|
||||
using Microsoft.PowerFx;
|
||||
|
||||
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.Extensions;
|
||||
|
||||
public sealed class TemplateExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void FormatTemplateWithTextSegments()
|
||||
{
|
||||
// Arrange
|
||||
RecalcEngine engine = new();
|
||||
IEnumerable<TemplateLine> template = new List<TemplateLine>
|
||||
{
|
||||
new TemplateLine.Builder
|
||||
{
|
||||
Segments =
|
||||
{
|
||||
new TextSegment.Builder { Value = "Hello " },
|
||||
new TextSegment.Builder { Value = "World" }
|
||||
}
|
||||
}.Build()
|
||||
};
|
||||
|
||||
// Act
|
||||
string result = engine.Format(template);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Hello World", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatTemplateWithMultipleLines()
|
||||
{
|
||||
// Arrange
|
||||
RecalcEngine engine = new();
|
||||
IEnumerable<TemplateLine> template = new List<TemplateLine>
|
||||
{
|
||||
new TemplateLine.Builder
|
||||
{
|
||||
Segments =
|
||||
{
|
||||
new TextSegment.Builder { Value = "Line 1" }
|
||||
}
|
||||
}.Build(),
|
||||
new TemplateLine.Builder
|
||||
{
|
||||
Segments =
|
||||
{
|
||||
new TextSegment.Builder { Value = "Line 2" }
|
||||
}
|
||||
}.Build()
|
||||
};
|
||||
|
||||
// Act
|
||||
string result = engine.Format(template);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Line 1Line 2", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatSingleTemplateLineWithNullValue()
|
||||
{
|
||||
// Arrange
|
||||
RecalcEngine engine = new();
|
||||
TemplateLine? line = null;
|
||||
|
||||
// Act
|
||||
string result = engine.Format(line);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(string.Empty, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatSingleTemplateLineWithTextSegment()
|
||||
{
|
||||
// Arrange
|
||||
RecalcEngine engine = new();
|
||||
TemplateLine line = new TemplateLine.Builder
|
||||
{
|
||||
Segments =
|
||||
{
|
||||
new TextSegment.Builder { Value = "Test" }
|
||||
}
|
||||
}.Build();
|
||||
|
||||
// Act
|
||||
string result = engine.Format(line);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Test", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatTextSegmentWithNullValue()
|
||||
{
|
||||
// Arrange
|
||||
RecalcEngine engine = new();
|
||||
TextSegment segment = new TextSegment.Builder { Value = null }.Build();
|
||||
|
||||
// Act
|
||||
string result = engine.Format(segment);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(string.Empty, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatTextSegmentWithEmptyValue()
|
||||
{
|
||||
// Arrange
|
||||
RecalcEngine engine = new();
|
||||
TextSegment segment = new TextSegment.Builder { Value = "" }.Build();
|
||||
|
||||
// Act
|
||||
string result = engine.Format(segment);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(string.Empty, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatTextSegmentWithValue()
|
||||
{
|
||||
// Arrange
|
||||
RecalcEngine engine = new();
|
||||
TextSegment segment = new TextSegment.Builder { Value = "Hello World" }.Build();
|
||||
|
||||
// Act
|
||||
string result = engine.Format(segment);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Hello World", result);
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Agents.AI.Workflows.Declarative.PowerFx;
|
||||
using Microsoft.Agents.AI.Workflows.Declarative.PowerFx.Functions;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.PowerFx.Types;
|
||||
|
||||
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.PowerFx.Functions;
|
||||
|
||||
public class UserMessageTests
|
||||
{
|
||||
[Fact]
|
||||
public void Construct_Function()
|
||||
{
|
||||
UserMessage function = new();
|
||||
Assert.NotNull(function);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_ReturnsBlank_ForEmptyInput()
|
||||
{
|
||||
// Arrange
|
||||
FormulaValue sourceValue = FormulaValue.New(string.Empty);
|
||||
StringValue stringValue = Assert.IsType<StringValue>(sourceValue);
|
||||
|
||||
// Act
|
||||
FormulaValue result = UserMessage.Execute(stringValue);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<BlankValue>(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_ReturnsExpectedRecord_ForNonEmptyInput()
|
||||
{
|
||||
const string Text = "Hello";
|
||||
FormulaValue sourceValue = FormulaValue.New(Text);
|
||||
StringValue stringValue = Assert.IsType<StringValue>(sourceValue);
|
||||
|
||||
FormulaValue result = UserMessage.Execute(stringValue);
|
||||
|
||||
RecordValue recordResult = Assert.IsType<RecordValue>(result, exactMatch: false);
|
||||
|
||||
// Discriminator
|
||||
FormulaValue discriminator = recordResult.GetField(TypeSchema.Discriminator);
|
||||
StringValue discriminatorValue = Assert.IsType<StringValue>(discriminator);
|
||||
Assert.Equal(nameof(ChatMessage), discriminatorValue.Value);
|
||||
|
||||
// Role
|
||||
FormulaValue role = recordResult.GetField(TypeSchema.Message.Fields.Role);
|
||||
StringValue roleValue = Assert.IsType<StringValue>(role);
|
||||
Assert.Equal(ChatRole.User.Value, roleValue.Value);
|
||||
|
||||
// Content table
|
||||
FormulaValue content = recordResult.GetField(TypeSchema.Message.Fields.Content);
|
||||
TableValue table = Assert.IsType<TableValue>(content, exactMatch: false);
|
||||
|
||||
List<RecordValue> rows = table.Rows.Select(value => value.Value).ToList();
|
||||
Assert.Single(rows);
|
||||
|
||||
StringValue contentType = Assert.IsType<StringValue>(rows[0].GetField(TypeSchema.Message.Fields.ContentType));
|
||||
Assert.Equal(TypeSchema.Message.ContentTypes.Text, contentType.Value);
|
||||
|
||||
StringValue contentValue = Assert.IsType<StringValue>(rows[0].GetField(TypeSchema.Message.Fields.ContentValue));
|
||||
Assert.Equal(Text, contentValue.Value);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user