465 lines
13 KiB
C#
465 lines
13 KiB
C#
using System.ComponentModel.DataAnnotations;
|
|
using System.ComponentModel.DataAnnotations.Schema;
|
|
using System.Text.Json;
|
|
using ChatBot.Models.Entities;
|
|
using FluentAssertions;
|
|
|
|
namespace ChatBot.Tests.Models;
|
|
|
|
public class ChatMessageEntityTests
|
|
{
|
|
[Fact]
|
|
public void Constructor_ShouldInitializePropertiesWithDefaultValues()
|
|
{
|
|
// Arrange & Act
|
|
var entity = new ChatMessageEntity();
|
|
|
|
// Assert
|
|
entity.Id.Should().Be(0);
|
|
entity.SessionId.Should().Be(0);
|
|
entity.Content.Should().Be(string.Empty);
|
|
entity.Role.Should().Be(string.Empty);
|
|
entity.CreatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(1));
|
|
entity.MessageOrder.Should().Be(0);
|
|
entity.Session.Should().BeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public void Id_ShouldBeSettable()
|
|
{
|
|
// Arrange
|
|
var entity = new ChatMessageEntity();
|
|
var expectedId = 123;
|
|
|
|
// Act
|
|
entity.Id = expectedId;
|
|
|
|
// Assert
|
|
entity.Id.Should().Be(expectedId);
|
|
}
|
|
|
|
[Fact]
|
|
public void SessionId_ShouldBeSettable()
|
|
{
|
|
// Arrange
|
|
var entity = new ChatMessageEntity();
|
|
var expectedSessionId = 456;
|
|
|
|
// Act
|
|
entity.SessionId = expectedSessionId;
|
|
|
|
// Assert
|
|
entity.SessionId.Should().Be(expectedSessionId);
|
|
}
|
|
|
|
[Fact]
|
|
public void Content_ShouldBeSettable()
|
|
{
|
|
// Arrange
|
|
var entity = new ChatMessageEntity();
|
|
var expectedContent = "Hello, world!";
|
|
|
|
// Act
|
|
entity.Content = expectedContent;
|
|
|
|
// Assert
|
|
entity.Content.Should().Be(expectedContent);
|
|
}
|
|
|
|
[Fact]
|
|
public void Role_ShouldBeSettable()
|
|
{
|
|
// Arrange
|
|
var entity = new ChatMessageEntity();
|
|
var expectedRole = "user";
|
|
|
|
// Act
|
|
entity.Role = expectedRole;
|
|
|
|
// Assert
|
|
entity.Role.Should().Be(expectedRole);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreatedAt_ShouldBeSettable()
|
|
{
|
|
// Arrange
|
|
var entity = new ChatMessageEntity();
|
|
var expectedDate = DateTime.UtcNow.AddDays(-1);
|
|
|
|
// Act
|
|
entity.CreatedAt = expectedDate;
|
|
|
|
// Assert
|
|
entity.CreatedAt.Should().Be(expectedDate);
|
|
}
|
|
|
|
[Fact]
|
|
public void MessageOrder_ShouldBeSettable()
|
|
{
|
|
// Arrange
|
|
var entity = new ChatMessageEntity();
|
|
var expectedOrder = 5;
|
|
|
|
// Act
|
|
entity.MessageOrder = expectedOrder;
|
|
|
|
// Assert
|
|
entity.MessageOrder.Should().Be(expectedOrder);
|
|
}
|
|
|
|
[Fact]
|
|
public void Session_ShouldBeSettable()
|
|
{
|
|
// Arrange
|
|
var entity = new ChatMessageEntity();
|
|
var expectedSession = new ChatSessionEntity();
|
|
|
|
// Act
|
|
entity.Session = expectedSession;
|
|
|
|
// Assert
|
|
entity.Session.Should().Be(expectedSession);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("user")]
|
|
[InlineData("assistant")]
|
|
[InlineData("system")]
|
|
[InlineData("function")]
|
|
public void Role_ShouldAcceptValidRoles(string role)
|
|
{
|
|
// Arrange
|
|
var entity = new ChatMessageEntity();
|
|
|
|
// Act
|
|
entity.Role = role;
|
|
|
|
// Assert
|
|
entity.Role.Should().Be(role);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("")]
|
|
[InlineData("a")]
|
|
[InlineData("very long role name that exceeds limit")]
|
|
public void Role_ShouldAcceptVariousLengths(string role)
|
|
{
|
|
// Arrange
|
|
var entity = new ChatMessageEntity();
|
|
|
|
// Act
|
|
entity.Role = role;
|
|
|
|
// Assert
|
|
entity.Role.Should().Be(role);
|
|
entity.Role.Length.Should().Be(role.Length);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("")]
|
|
[InlineData("Short message")]
|
|
[InlineData(
|
|
"A very long message that contains a lot of text and should still be valid for the content field"
|
|
)]
|
|
public void Content_ShouldAcceptVariousLengths(string content)
|
|
{
|
|
// Arrange
|
|
var entity = new ChatMessageEntity();
|
|
|
|
// Act
|
|
entity.Content = content;
|
|
|
|
// Assert
|
|
entity.Content.Should().Be(content);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreatedAt_ShouldDefaultToCurrentUtcTime()
|
|
{
|
|
// Arrange
|
|
var beforeCreation = DateTime.UtcNow;
|
|
|
|
// Act
|
|
var entity = new ChatMessageEntity();
|
|
|
|
// Assert
|
|
entity.CreatedAt.Should().BeOnOrAfter(beforeCreation);
|
|
entity.CreatedAt.Should().BeOnOrBefore(DateTime.UtcNow);
|
|
}
|
|
|
|
[Fact]
|
|
public void AllProperties_ShouldBeMutable()
|
|
{
|
|
// Arrange
|
|
var entity = new ChatMessageEntity();
|
|
var session = new ChatSessionEntity();
|
|
|
|
// Act
|
|
entity.Id = 1;
|
|
entity.SessionId = 2;
|
|
entity.Content = "Test content";
|
|
entity.Role = "user";
|
|
entity.CreatedAt = DateTime.UtcNow.AddDays(-1);
|
|
entity.MessageOrder = 3;
|
|
entity.Session = session;
|
|
|
|
// Assert
|
|
entity.Id.Should().Be(1);
|
|
entity.SessionId.Should().Be(2);
|
|
entity.Content.Should().Be("Test content");
|
|
entity.Role.Should().Be("user");
|
|
entity.CreatedAt.Should().BeCloseTo(DateTime.UtcNow.AddDays(-1), TimeSpan.FromSeconds(1));
|
|
entity.MessageOrder.Should().Be(3);
|
|
entity.Session.Should().Be(session);
|
|
}
|
|
|
|
[Fact]
|
|
public void Entity_ShouldHaveCorrectTableAttribute()
|
|
{
|
|
// Arrange
|
|
var entityType = typeof(ChatMessageEntity);
|
|
var tableAttribute =
|
|
entityType.GetCustomAttributes(typeof(TableAttribute), false).FirstOrDefault()
|
|
as TableAttribute;
|
|
|
|
// Assert
|
|
tableAttribute.Should().NotBeNull();
|
|
tableAttribute!.Name.Should().Be("chat_messages");
|
|
}
|
|
|
|
[Fact]
|
|
public void Id_ShouldHaveKeyAttribute()
|
|
{
|
|
// Arrange
|
|
var property = typeof(ChatMessageEntity).GetProperty(nameof(ChatMessageEntity.Id));
|
|
var keyAttribute =
|
|
property?.GetCustomAttributes(typeof(KeyAttribute), false).FirstOrDefault()
|
|
as KeyAttribute;
|
|
|
|
// Assert
|
|
keyAttribute.Should().NotBeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public void Id_ShouldHaveColumnAttribute()
|
|
{
|
|
// Arrange
|
|
var property = typeof(ChatMessageEntity).GetProperty(nameof(ChatMessageEntity.Id));
|
|
var columnAttribute =
|
|
property?.GetCustomAttributes(typeof(ColumnAttribute), false).FirstOrDefault()
|
|
as ColumnAttribute;
|
|
|
|
// Assert
|
|
columnAttribute.Should().NotBeNull();
|
|
columnAttribute!.Name.Should().Be("id");
|
|
}
|
|
|
|
[Fact]
|
|
public void SessionId_ShouldHaveRequiredAttribute()
|
|
{
|
|
// Arrange
|
|
var property = typeof(ChatMessageEntity).GetProperty(nameof(ChatMessageEntity.SessionId));
|
|
var requiredAttribute =
|
|
property?.GetCustomAttributes(typeof(RequiredAttribute), false).FirstOrDefault()
|
|
as RequiredAttribute;
|
|
|
|
// Assert
|
|
requiredAttribute.Should().NotBeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public void SessionId_ShouldHaveColumnAttribute()
|
|
{
|
|
// Arrange
|
|
var property = typeof(ChatMessageEntity).GetProperty(nameof(ChatMessageEntity.SessionId));
|
|
var columnAttribute =
|
|
property?.GetCustomAttributes(typeof(ColumnAttribute), false).FirstOrDefault()
|
|
as ColumnAttribute;
|
|
|
|
// Assert
|
|
columnAttribute.Should().NotBeNull();
|
|
columnAttribute!.Name.Should().Be("session_id");
|
|
}
|
|
|
|
[Fact]
|
|
public void Content_ShouldHaveRequiredAttribute()
|
|
{
|
|
// Arrange
|
|
var property = typeof(ChatMessageEntity).GetProperty(nameof(ChatMessageEntity.Content));
|
|
var requiredAttribute =
|
|
property?.GetCustomAttributes(typeof(RequiredAttribute), false).FirstOrDefault()
|
|
as RequiredAttribute;
|
|
|
|
// Assert
|
|
requiredAttribute.Should().NotBeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public void Content_ShouldHaveStringLengthAttribute()
|
|
{
|
|
// Arrange
|
|
var property = typeof(ChatMessageEntity).GetProperty(nameof(ChatMessageEntity.Content));
|
|
var stringLengthAttribute =
|
|
property?.GetCustomAttributes(typeof(StringLengthAttribute), false).FirstOrDefault()
|
|
as StringLengthAttribute;
|
|
|
|
// Assert
|
|
stringLengthAttribute.Should().NotBeNull();
|
|
stringLengthAttribute!.MaximumLength.Should().Be(10000);
|
|
}
|
|
|
|
[Fact]
|
|
public void Content_ShouldHaveColumnAttribute()
|
|
{
|
|
// Arrange
|
|
var property = typeof(ChatMessageEntity).GetProperty(nameof(ChatMessageEntity.Content));
|
|
var columnAttribute =
|
|
property?.GetCustomAttributes(typeof(ColumnAttribute), false).FirstOrDefault()
|
|
as ColumnAttribute;
|
|
|
|
// Assert
|
|
columnAttribute.Should().NotBeNull();
|
|
columnAttribute!.Name.Should().Be("content");
|
|
}
|
|
|
|
[Fact]
|
|
public void Role_ShouldHaveRequiredAttribute()
|
|
{
|
|
// Arrange
|
|
var property = typeof(ChatMessageEntity).GetProperty(nameof(ChatMessageEntity.Role));
|
|
var requiredAttribute =
|
|
property?.GetCustomAttributes(typeof(RequiredAttribute), false).FirstOrDefault()
|
|
as RequiredAttribute;
|
|
|
|
// Assert
|
|
requiredAttribute.Should().NotBeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public void Role_ShouldHaveStringLengthAttribute()
|
|
{
|
|
// Arrange
|
|
var property = typeof(ChatMessageEntity).GetProperty(nameof(ChatMessageEntity.Role));
|
|
var stringLengthAttribute =
|
|
property?.GetCustomAttributes(typeof(StringLengthAttribute), false).FirstOrDefault()
|
|
as StringLengthAttribute;
|
|
|
|
// Assert
|
|
stringLengthAttribute.Should().NotBeNull();
|
|
stringLengthAttribute!.MaximumLength.Should().Be(20);
|
|
}
|
|
|
|
[Fact]
|
|
public void Role_ShouldHaveColumnAttribute()
|
|
{
|
|
// Arrange
|
|
var property = typeof(ChatMessageEntity).GetProperty(nameof(ChatMessageEntity.Role));
|
|
var columnAttribute =
|
|
property?.GetCustomAttributes(typeof(ColumnAttribute), false).FirstOrDefault()
|
|
as ColumnAttribute;
|
|
|
|
// Assert
|
|
columnAttribute.Should().NotBeNull();
|
|
columnAttribute!.Name.Should().Be("role");
|
|
}
|
|
|
|
[Fact]
|
|
public void CreatedAt_ShouldHaveRequiredAttribute()
|
|
{
|
|
// Arrange
|
|
var property = typeof(ChatMessageEntity).GetProperty(nameof(ChatMessageEntity.CreatedAt));
|
|
var requiredAttribute =
|
|
property?.GetCustomAttributes(typeof(RequiredAttribute), false).FirstOrDefault()
|
|
as RequiredAttribute;
|
|
|
|
// Assert
|
|
requiredAttribute.Should().NotBeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public void CreatedAt_ShouldHaveColumnAttribute()
|
|
{
|
|
// Arrange
|
|
var property = typeof(ChatMessageEntity).GetProperty(nameof(ChatMessageEntity.CreatedAt));
|
|
var columnAttribute =
|
|
property?.GetCustomAttributes(typeof(ColumnAttribute), false).FirstOrDefault()
|
|
as ColumnAttribute;
|
|
|
|
// Assert
|
|
columnAttribute.Should().NotBeNull();
|
|
columnAttribute!.Name.Should().Be("created_at");
|
|
}
|
|
|
|
[Fact]
|
|
public void MessageOrder_ShouldHaveColumnAttribute()
|
|
{
|
|
// Arrange
|
|
var property = typeof(ChatMessageEntity).GetProperty(
|
|
nameof(ChatMessageEntity.MessageOrder)
|
|
);
|
|
var columnAttribute =
|
|
property?.GetCustomAttributes(typeof(ColumnAttribute), false).FirstOrDefault()
|
|
as ColumnAttribute;
|
|
|
|
// Assert
|
|
columnAttribute.Should().NotBeNull();
|
|
columnAttribute!.Name.Should().Be("message_order");
|
|
}
|
|
|
|
[Fact]
|
|
public void Session_ShouldHaveForeignKeyAttribute()
|
|
{
|
|
// Arrange
|
|
var property = typeof(ChatMessageEntity).GetProperty(nameof(ChatMessageEntity.Session));
|
|
var foreignKeyAttribute =
|
|
property?.GetCustomAttributes(typeof(ForeignKeyAttribute), false).FirstOrDefault()
|
|
as ForeignKeyAttribute;
|
|
|
|
// Assert
|
|
foreignKeyAttribute.Should().NotBeNull();
|
|
foreignKeyAttribute!.Name.Should().Be("SessionId");
|
|
}
|
|
|
|
[Fact]
|
|
public void JsonSerialization_RoundTrip_ShouldPreserveScalarProperties()
|
|
{
|
|
// Arrange
|
|
var original = new ChatMessageEntity
|
|
{
|
|
Id = 42,
|
|
SessionId = 7,
|
|
Content = "Hello JSON",
|
|
Role = "user",
|
|
CreatedAt = DateTime.UtcNow.AddMinutes(-5),
|
|
MessageOrder = 3,
|
|
Session = null!, // ensure navigation not required for serialization
|
|
};
|
|
|
|
var options = new JsonSerializerOptions
|
|
{
|
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
WriteIndented = false,
|
|
DefaultIgnoreCondition = System
|
|
.Text
|
|
.Json
|
|
.Serialization
|
|
.JsonIgnoreCondition
|
|
.WhenWritingNull,
|
|
};
|
|
|
|
// Act
|
|
var json = JsonSerializer.Serialize(original, options);
|
|
var deserialized = JsonSerializer.Deserialize<ChatMessageEntity>(json, options)!;
|
|
|
|
// Assert
|
|
deserialized.Id.Should().Be(original.Id);
|
|
deserialized.SessionId.Should().Be(original.SessionId);
|
|
deserialized.Content.Should().Be(original.Content);
|
|
deserialized.Role.Should().Be(original.Role);
|
|
deserialized.MessageOrder.Should().Be(original.MessageOrder);
|
|
// Allow a small delta due to serialization precision
|
|
deserialized.CreatedAt.Should().BeCloseTo(original.CreatedAt, TimeSpan.FromSeconds(1));
|
|
}
|
|
}
|