// Copyright (c) Microsoft. All rights reserved. using System; using System.Collections.Generic; using System.Linq; using System.Text.Json; using System.Threading; using System.Threading.Tasks; namespace Microsoft.Extensions.AI.Agents.Abstractions.UnitTests; /// /// Contains tests for the class. /// public class InMemoryChatMessageStoreTests { [Fact] public async Task AddMessagesAsyncAddsMessagesAndReturnsNullThreadIdAsync() { var store = new InMemoryChatMessageStore(); var messages = new List { new(ChatRole.User, "Hello"), new(ChatRole.Assistant, "Hi there!") }; await store.AddMessagesAsync(messages, CancellationToken.None); Assert.Equal(2, store.Count); Assert.Equal("Hello", store[0].Text); Assert.Equal("Hi there!", store[1].Text); } [Fact] public async Task AddMessagesAsyncWithEmptyDoesNotFailAsync() { var store = new InMemoryChatMessageStore(); await store.AddMessagesAsync([], CancellationToken.None); Assert.Empty(store); } [Fact] public async Task GetMessagesAsyncReturnsAllMessagesAsync() { var store = new InMemoryChatMessageStore { new ChatMessage(ChatRole.User, "Test1"), new ChatMessage(ChatRole.Assistant, "Test2") }; var result = (await store.GetMessagesAsync(CancellationToken.None)).ToList(); Assert.Equal(2, result.Count); Assert.Contains(result, m => m.Text == "Test1"); Assert.Contains(result, m => m.Text == "Test2"); } [Fact] public async Task DeserializeWithEmptyElementAsync() { var newStore = new InMemoryChatMessageStore(); var emptyObject = JsonSerializer.Deserialize("{}"); await newStore.DeserializeStateAsync(emptyObject); Assert.Empty(newStore); } [Fact] public async Task SerializeAndDeserializeRoundtripsAsync() { var store = new InMemoryChatMessageStore { new ChatMessage(ChatRole.User, "A"), new ChatMessage(ChatRole.Assistant, "B") }; var jsonElement = await store.SerializeStateAsync(); var newStore = new InMemoryChatMessageStore(); await newStore.DeserializeStateAsync(jsonElement); Assert.Equal(2, newStore.Count); Assert.Equal("A", newStore[0].Text); Assert.Equal("B", newStore[1].Text); } [Fact] public async Task AddMessagesAsyncWithEmptyMessagesDoesNotChangeStoreAsync() { var store = new InMemoryChatMessageStore(); var messages = new List(); await store.AddMessagesAsync(messages, CancellationToken.None); Assert.Empty(store); } [Fact] public async Task AddMessagesAsync_WithNullMessages_ThrowsArgumentNullExceptionAsync() { // Arrange var store = new InMemoryChatMessageStore(); // Act & Assert await Assert.ThrowsAsync(() => store.AddMessagesAsync(null!, CancellationToken.None)); } [Fact] public async Task DeserializeStateAsync_WithNullSerializedState_DoesNothingAsync() { // Arrange var store = new InMemoryChatMessageStore(); store.Add(new ChatMessage(ChatRole.User, "Existing message")); // Act await store.DeserializeStateAsync(null); // Assert - Should still have the existing message Assert.Single(store); Assert.Equal("Existing message", store[0].Text); } [Fact] public async Task DeserializeStateAsync_WithEmptyMessages_DoesNotAddMessagesAsync() { // Arrange var store = new InMemoryChatMessageStore(); var stateWithEmptyMessages = JsonSerializer.SerializeToElement(new { Messages = new List() }); // Act await store.DeserializeStateAsync(stateWithEmptyMessages); // Assert Assert.Empty(store); } [Fact] public async Task DeserializeStateAsync_WithNullMessages_DoesNotAddMessagesAsync() { // Arrange var store = new InMemoryChatMessageStore(); var stateWithNullMessages = JsonSerializer.SerializeToElement(new { Messages = (List?)null }); // Act await store.DeserializeStateAsync(stateWithNullMessages); // Assert Assert.Empty(store); } [Fact] public async Task DeserializeStateAsync_WithValidMessages_AddsMessagesAsync() { // Arrange var store = new InMemoryChatMessageStore(); var messages = new List { new(ChatRole.User, "User message"), new(ChatRole.Assistant, "Assistant message") }; var state = new { Messages = messages }; var serializedState = JsonSerializer.SerializeToElement(state); // Act await store.DeserializeStateAsync(serializedState); // Assert Assert.Equal(2, store.Count); Assert.Equal("User message", store[0].Text); Assert.Equal("Assistant message", store[1].Text); } [Fact] public void IndexerGet_ReturnsCorrectMessage() { // Arrange var store = new InMemoryChatMessageStore(); var message1 = new ChatMessage(ChatRole.User, "First"); var message2 = new ChatMessage(ChatRole.Assistant, "Second"); store.Add(message1); store.Add(message2); // Act & Assert Assert.Same(message1, store[0]); Assert.Same(message2, store[1]); } [Fact] public void IndexerSet_UpdatesMessage() { // Arrange var store = new InMemoryChatMessageStore(); var originalMessage = new ChatMessage(ChatRole.User, "Original"); var newMessage = new ChatMessage(ChatRole.User, "Updated"); store.Add(originalMessage); // Act store[0] = newMessage; // Assert Assert.Same(newMessage, store[0]); Assert.Equal("Updated", store[0].Text); } [Fact] public void IsReadOnly_ReturnsFalse() { // Arrange var store = new InMemoryChatMessageStore(); // Act & Assert Assert.False(store.IsReadOnly); } [Fact] public void IndexOf_ReturnsCorrectIndex() { // Arrange var store = new InMemoryChatMessageStore(); var message1 = new ChatMessage(ChatRole.User, "First"); var message2 = new ChatMessage(ChatRole.Assistant, "Second"); var message3 = new ChatMessage(ChatRole.User, "Third"); store.Add(message1); store.Add(message2); // Act & Assert Assert.Equal(0, store.IndexOf(message1)); Assert.Equal(1, store.IndexOf(message2)); Assert.Equal(-1, store.IndexOf(message3)); // Not in store } [Fact] public void Insert_InsertsMessageAtCorrectIndex() { // Arrange var store = new InMemoryChatMessageStore(); var message1 = new ChatMessage(ChatRole.User, "First"); var message2 = new ChatMessage(ChatRole.Assistant, "Second"); var insertMessage = new ChatMessage(ChatRole.User, "Inserted"); store.Add(message1); store.Add(message2); // Act store.Insert(1, insertMessage); // Assert Assert.Equal(3, store.Count); Assert.Same(message1, store[0]); Assert.Same(insertMessage, store[1]); Assert.Same(message2, store[2]); } [Fact] public void RemoveAt_RemovesMessageAtIndex() { // Arrange var store = new InMemoryChatMessageStore(); var message1 = new ChatMessage(ChatRole.User, "First"); var message2 = new ChatMessage(ChatRole.Assistant, "Second"); var message3 = new ChatMessage(ChatRole.User, "Third"); store.Add(message1); store.Add(message2); store.Add(message3); // Act store.RemoveAt(1); // Assert Assert.Equal(2, store.Count); Assert.Same(message1, store[0]); Assert.Same(message3, store[1]); } [Fact] public void Clear_RemovesAllMessages() { // Arrange var store = new InMemoryChatMessageStore(); store.Add(new ChatMessage(ChatRole.User, "First")); store.Add(new ChatMessage(ChatRole.Assistant, "Second")); // Act store.Clear(); // Assert Assert.Empty(store); } [Fact] public void Contains_ReturnsTrueForExistingMessage() { // Arrange var store = new InMemoryChatMessageStore(); var message1 = new ChatMessage(ChatRole.User, "First"); var message2 = new ChatMessage(ChatRole.Assistant, "Second"); store.Add(message1); // Act & Assert Assert.Contains(message1, store); Assert.DoesNotContain(message2, store); } [Fact] public void CopyTo_CopiesMessagesToArray() { // Arrange var store = new InMemoryChatMessageStore(); var message1 = new ChatMessage(ChatRole.User, "First"); var message2 = new ChatMessage(ChatRole.Assistant, "Second"); store.Add(message1); store.Add(message2); var array = new ChatMessage[4]; // Act store.CopyTo(array, 1); // Assert Assert.Null(array[0]); Assert.Same(message1, array[1]); Assert.Same(message2, array[2]); Assert.Null(array[3]); } [Fact] public void Remove_RemovesSpecificMessage() { // Arrange var store = new InMemoryChatMessageStore(); var message1 = new ChatMessage(ChatRole.User, "First"); var message2 = new ChatMessage(ChatRole.Assistant, "Second"); var message3 = new ChatMessage(ChatRole.User, "Third"); store.Add(message1); store.Add(message2); store.Add(message3); // Act var removed = store.Remove(message2); // Assert Assert.True(removed); Assert.Equal(2, store.Count); Assert.Same(message1, store[0]); Assert.Same(message3, store[1]); } [Fact] public void Remove_ReturnsFalseForNonExistentMessage() { // Arrange var store = new InMemoryChatMessageStore(); var message1 = new ChatMessage(ChatRole.User, "First"); var message2 = new ChatMessage(ChatRole.Assistant, "Second"); store.Add(message1); // Act var removed = store.Remove(message2); // Assert Assert.False(removed); Assert.Single(store); } [Fact] public void GetEnumerator_Generic_ReturnsAllMessages() { // Arrange var store = new InMemoryChatMessageStore(); var message1 = new ChatMessage(ChatRole.User, "First"); var message2 = new ChatMessage(ChatRole.Assistant, "Second"); store.Add(message1); store.Add(message2); // Act var messages = new List(); messages.AddRange(store); // Assert Assert.Equal(2, messages.Count); Assert.Same(message1, messages[0]); Assert.Same(message2, messages[1]); } [Fact] public void GetEnumerator_NonGeneric_ReturnsAllMessages() { // Arrange var store = new InMemoryChatMessageStore(); var message1 = new ChatMessage(ChatRole.User, "First"); var message2 = new ChatMessage(ChatRole.Assistant, "Second"); store.Add(message1); store.Add(message2); // Act var messages = new List(); var enumerator = ((System.Collections.IEnumerable)store).GetEnumerator(); while (enumerator.MoveNext()) { messages.Add((ChatMessage)enumerator.Current); } // Assert Assert.Equal(2, messages.Count); Assert.Same(message1, messages[0]); Assert.Same(message2, messages[1]); } }