From 506581dbfe3e86a3cb30e6214e9a26aeab0cb776 Mon Sep 17 00:00:00 2001 From: Frank Boucher Date: Fri, 12 Dec 2025 20:00:18 -0500 Subject: [PATCH 1/2] Fixes failing note endpoint tests Corrects assertions in note endpoint tests to accurately reflect expected behavior. Addresses issues where the test expected a `ReadingNote` object instead of a `Note` object after the type renaming. Also removes a redundant non-null assertion as the subsequent `BeEmpty()` assertion already implies a non-null value. Fixes #83 --- src/NoteBookmark.Api.Tests/Endpoints/NoteEndpointsTests.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/NoteBookmark.Api.Tests/Endpoints/NoteEndpointsTests.cs b/src/NoteBookmark.Api.Tests/Endpoints/NoteEndpointsTests.cs index e4f26e0..c1bd0be 100644 --- a/src/NoteBookmark.Api.Tests/Endpoints/NoteEndpointsTests.cs +++ b/src/NoteBookmark.Api.Tests/Endpoints/NoteEndpointsTests.cs @@ -86,7 +86,7 @@ public async Task GetNotes_ReturnsAllNotes() // Assert response.StatusCode.Should().Be(HttpStatusCode.OK); - var notes = await response.Content.ReadFromJsonAsync>(); + var notes = await response.Content.ReadFromJsonAsync>(); notes.Should().NotBeNull(); notes.Should().NotBeEmpty(); } @@ -122,7 +122,6 @@ public async Task GetNotesForSummary_WithInvalidReadingNotesId_ReturnsEmptyList( response.StatusCode.Should().Be(HttpStatusCode.OK); var readingNotes = await response.Content.ReadFromJsonAsync>(); - readingNotes.Should().NotBeNull(); readingNotes.Should().BeEmpty(); } From 2b53edc649440e4d259191159df74e540a241fb5 Mon Sep 17 00:00:00 2001 From: Frank Boucher Date: Sat, 13 Dec 2025 17:04:41 -0500 Subject: [PATCH 2/2] Adds unit tests for domain models Introduces unit tests for domain models, including: - `ContainsPlaceholderAttribute` - `NoteCategories` - `Note` - `PostSuggestion` - `ReadingNote` - `SearchCriterias` These tests cover various aspects of the domain models, such as validation, serialization/deserialization, and property setting. The old `NoteTests` and `ReadingNoteTests` files were deleted since they were duplicated. The goal is to ensure the correctness and reliability of the core domain logic. --- .../ContainsPlaceholderAttributeTests.cs | 135 ++++++++++ .../Domain/NoteCategoriesTests.cs | 100 ++++++++ .../Domain/NoteTests.cs | 87 +++++++ .../Domain/PostSuggestionTests.cs | 230 ++++++++++++++++++ .../Domain/ReadingNoteTests.cs | 102 ++++++++ .../Domain/SearchCriteriasTests.cs | 162 ++++++++++++ 6 files changed, 816 insertions(+) create mode 100644 src/NoteBookmark.Api.Tests/Domain/ContainsPlaceholderAttributeTests.cs create mode 100644 src/NoteBookmark.Api.Tests/Domain/NoteCategoriesTests.cs create mode 100644 src/NoteBookmark.Api.Tests/Domain/PostSuggestionTests.cs create mode 100644 src/NoteBookmark.Api.Tests/Domain/SearchCriteriasTests.cs diff --git a/src/NoteBookmark.Api.Tests/Domain/ContainsPlaceholderAttributeTests.cs b/src/NoteBookmark.Api.Tests/Domain/ContainsPlaceholderAttributeTests.cs new file mode 100644 index 0000000..5f0cf7f --- /dev/null +++ b/src/NoteBookmark.Api.Tests/Domain/ContainsPlaceholderAttributeTests.cs @@ -0,0 +1,135 @@ +using System.ComponentModel.DataAnnotations; +using FluentAssertions; +using NoteBookmark.Domain; +using Xunit; + +namespace NoteBookmark.Api.Tests.Domain; + +public class ContainsPlaceholderAttributeTests +{ + [Fact] + public void IsValid_ShouldReturnSuccess_WhenValueContainsPlaceholder() + { + // Arrange + var attribute = new ContainsPlaceholderAttribute("topic"); + var validationContext = new ValidationContext(new object()); + + // Act + var result = attribute.GetValidationResult("Find articles about {topic}", validationContext); + + // Assert + result.Should().Be(ValidationResult.Success); + } + + [Fact] + public void IsValid_ShouldReturnError_WhenValueDoesNotContainPlaceholder() + { + // Arrange + var attribute = new ContainsPlaceholderAttribute("topic"); + var validationContext = new ValidationContext(new object()); + + // Act + var result = attribute.GetValidationResult("Find articles about something", validationContext); + + // Assert + result.Should().NotBe(ValidationResult.Success); + result?.ErrorMessage.Should().Contain("topic"); + } + + [Fact] + public void IsValid_ShouldReturnSuccess_WhenValueIsNull() + { + // Arrange + var attribute = new ContainsPlaceholderAttribute("content"); + var validationContext = new ValidationContext(new object()); + + // Act + var result = attribute.GetValidationResult(null, validationContext); + + // Assert + result.Should().Be(ValidationResult.Success); + } + + [Fact] + public void IsValid_ShouldReturnSuccess_WhenValueIsEmpty() + { + // Arrange + var attribute = new ContainsPlaceholderAttribute("content"); + var validationContext = new ValidationContext(new object()); + + // Act + var result = attribute.GetValidationResult("", validationContext); + + // Assert + result.Should().Be(ValidationResult.Success); + } + + [Fact] + public void IsValid_ShouldReturnSuccess_WhenValueIsWhitespace() + { + // Arrange + var attribute = new ContainsPlaceholderAttribute("content"); + var validationContext = new ValidationContext(new object()); + + // Act + var result = attribute.GetValidationResult(" ", validationContext); + + // Assert + result.Should().Be(ValidationResult.Success); + } + + [Fact] + public void Constructor_ShouldSetPlaceholder() + { + // Arrange & Act + var attribute = new ContainsPlaceholderAttribute("custom"); + var validationContext = new ValidationContext(new object()); + + // Assert + var result = attribute.GetValidationResult("text with {custom} placeholder", validationContext); + result.Should().Be(ValidationResult.Success); + } + + [Fact] + public void ErrorMessage_ShouldContainPlaceholderName() + { + // Arrange + var attribute = new ContainsPlaceholderAttribute("myplaceholder"); + var validationContext = new ValidationContext(new object()); + + // Act + var result = attribute.GetValidationResult("text without placeholder", validationContext); + + // Assert + result?.ErrorMessage.Should().Contain("myplaceholder"); + result?.ErrorMessage.Should().Contain("must contain"); + } + + [Theory] + [InlineData("Summary of {content}", "content", true)] + [InlineData("Summary of content", "content", false)] + [InlineData("Use {topic} for search", "topic", true)] + [InlineData("Use topic for search", "topic", false)] + [InlineData("Multiple {var1} and {var2}", "var1", true)] + [InlineData("Multiple {var1} and {var2}", "var2", true)] + [InlineData("Multiple var1 and var2", "var1", false)] + public void IsValid_ShouldValidateCorrectly_ForVariousInputs(string value, string placeholder, bool shouldBeValid) + { + // Arrange + var attribute = new ContainsPlaceholderAttribute(placeholder); + var validationContext = new ValidationContext(new object()); + + // Act + var result = attribute.GetValidationResult(value, validationContext); + + // Assert + if (shouldBeValid) + { + result.Should().Be(ValidationResult.Success); + } + else + { + result.Should().NotBe(ValidationResult.Success); + } + } +} diff --git a/src/NoteBookmark.Api.Tests/Domain/NoteCategoriesTests.cs b/src/NoteBookmark.Api.Tests/Domain/NoteCategoriesTests.cs new file mode 100644 index 0000000..7e46ad1 --- /dev/null +++ b/src/NoteBookmark.Api.Tests/Domain/NoteCategoriesTests.cs @@ -0,0 +1,100 @@ +using FluentAssertions; +using NoteBookmark.Domain; +using Xunit; + +namespace NoteBookmark.Api.Tests.Domain; + +public class NoteCategoriesTests +{ + [Theory] + [InlineData("ai", "AI")] + [InlineData("AI", "AI")] + [InlineData("cloud", "Cloud")] + [InlineData("CLOUD", "Cloud")] + [InlineData("data", "Data")] + [InlineData("database", "Databases")] + [InlineData("dev", "Programming")] + [InlineData("devops", "DevOps")] + [InlineData("lowcode", "LowCode")] + [InlineData("misc", "Miscellaneous")] + [InlineData("top", "Suggestion of the week")] + [InlineData("oss", "Open Source")] + [InlineData("del", "del")] + public void GetCategory_ShouldReturnCorrectCategory_ForValidInput(string input, string expected) + { + // Act + var result = NoteCategories.GetCategory(input); + + // Assert + result.Should().Be(expected); + } + + [Theory] + [InlineData("unknown")] + [InlineData("invalid")] + [InlineData("")] + public void GetCategory_ShouldReturnMiscellaneous_ForInvalidCategory(string input) + { + // Act + var result = NoteCategories.GetCategory(input); + + // Assert + result.Should().Be("Miscellaneous"); + } + + [Fact] + public void GetCategory_ShouldReturnMiscellaneous_ForNullInput() + { + // Act + var result = NoteCategories.GetCategory(null); + + // Assert + result.Should().Be("Miscellaneous"); + } + + [Fact] + public void GetCategory_ShouldBeCaseInsensitive() + { + // Arrange + var inputs = new[] { "AI", "ai", "Ai", "aI" }; + + // Act & Assert + foreach (var input in inputs) + { + var result = NoteCategories.GetCategory(input); + result.Should().Be("AI"); + } + } + + [Fact] + public void GetCategories_ShouldReturnAllCategories() + { + // Act + var result = NoteCategories.GetCategories(); + + // Assert + result.Should().NotBeNull(); + result.Should().HaveCount(11); + result.Should().Contain("AI"); + result.Should().Contain("Cloud"); + result.Should().Contain("Data"); + result.Should().Contain("Databases"); + result.Should().Contain("DevOps"); + result.Should().Contain("LowCode"); + result.Should().Contain("Miscellaneous"); + result.Should().Contain("Programming"); + result.Should().Contain("Open Source"); + result.Should().Contain("Suggestion of the week"); + result.Should().Contain("del"); + } + + [Fact] + public void GetCategories_ShouldReturnListType() + { + // Act + var result = NoteCategories.GetCategories(); + + // Assert + result.Should().BeOfType>(); + } +} diff --git a/src/NoteBookmark.Api.Tests/Domain/NoteTests.cs b/src/NoteBookmark.Api.Tests/Domain/NoteTests.cs index 35bdeff..7c6ebc5 100644 --- a/src/NoteBookmark.Api.Tests/Domain/NoteTests.cs +++ b/src/NoteBookmark.Api.Tests/Domain/NoteTests.cs @@ -19,6 +19,41 @@ public void Note_WhenCreated_HasCorrectDefaultValues() note.Category.Should().BeNull(); } + [Fact] + public void Note_Constructor_ShouldInitializePartitionKey_WithCurrentYearMonth() + { + // Act + var note = new Note(); + + // Assert + note.PartitionKey.Should().Be(DateTime.UtcNow.ToString("yyyy-MM")); + } + + [Fact] + public void Note_Constructor_ShouldInitializeRowKey_WithValidGuid() + { + // Act + var note = new Note(); + + // Assert + note.RowKey.Should().NotBeNullOrEmpty(); + Guid.TryParse(note.RowKey, out _).Should().BeTrue(); + } + + [Fact] + public void Note_Constructor_ShouldInitializeDateAdded_WithCurrentUtcTime() + { + // Arrange + var before = DateTime.UtcNow; + + // Act + var note = new Note(); + var after = DateTime.UtcNow; + + // Assert + note.DateAdded.Should().BeOnOrAfter(before).And.BeOnOrBefore(after); + } + [Fact] public void Note_WhenPropertiesSet_ReturnsCorrectValues() { @@ -41,4 +76,56 @@ public void Note_WhenPropertiesSet_ReturnsCorrectValues() note.Tags.Should().Be("azure, functions, serverless"); note.Category.Should().Be("Technology"); } + + [Fact] + public void Validate_ShouldReturnTrue_WhenCommentIsNotEmpty() + { + // Arrange + var note = new Note { Comment = "This is a valid comment" }; + + // Act + var result = note.Validate(); + + // Assert + result.Should().BeTrue(); + } + + [Fact] + public void Validate_ShouldReturnFalse_WhenCommentIsNull() + { + // Arrange + var note = new Note { Comment = null }; + + // Act + var result = note.Validate(); + + // Assert + result.Should().BeFalse(); + } + + [Fact] + public void Validate_ShouldReturnFalse_WhenCommentIsEmpty() + { + // Arrange + var note = new Note { Comment = "" }; + + // Act + var result = note.Validate(); + + // Assert + result.Should().BeFalse(); + } + + [Fact] + public void Validate_ShouldReturnFalse_WhenCommentIsWhitespace() + { + // Arrange + var note = new Note { Comment = " " }; + + // Act + var result = note.Validate(); + + // Assert + result.Should().BeFalse(); + } } diff --git a/src/NoteBookmark.Api.Tests/Domain/PostSuggestionTests.cs b/src/NoteBookmark.Api.Tests/Domain/PostSuggestionTests.cs new file mode 100644 index 0000000..f229a00 --- /dev/null +++ b/src/NoteBookmark.Api.Tests/Domain/PostSuggestionTests.cs @@ -0,0 +1,230 @@ +using System.Text.Json; +using FluentAssertions; +using NoteBookmark.Domain; +using Xunit; + +namespace NoteBookmark.Api.Tests.Domain; + +public class PostSuggestionTests +{ + [Fact] + public void PostSuggestion_ShouldSerializeToJson() + { + // Arrange + var postSuggestion = new PostSuggestion + { + Title = "Test Article", + Author = "John Doe", + Summary = "This is a summary", + PublicationDate = "2024-01-15", + Url = "https://example.com/article" + }; + + // Act + var json = JsonSerializer.Serialize(postSuggestion); + + // Assert + json.Should().Contain("\"title\":\"Test Article\""); + json.Should().Contain("\"author\":\"John Doe\""); + json.Should().Contain("\"summary\":\"This is a summary\""); + json.Should().Contain("\"publication_date\":\"2024-01-15\""); + json.Should().Contain("\"url\":\"https://example.com/article\""); + } + + [Fact] + public void PostSuggestion_ShouldDeserializeFromJson() + { + // Arrange + var json = @"{ + ""title"": ""Test Article"", + ""author"": ""Jane Doe"", + ""summary"": ""A great summary"", + ""publication_date"": ""2024-12-01"", + ""url"": ""https://test.com"" + }"; + + // Act + var result = JsonSerializer.Deserialize(json); + + // Assert + result.Should().NotBeNull(); + result!.Title.Should().Be("Test Article"); + result.Author.Should().Be("Jane Doe"); + result.Summary.Should().Be("A great summary"); + result.PublicationDate.Should().Be("2024-12-01"); + result.Url.Should().Be("https://test.com"); + } + + [Fact] + public void PostSuggestion_ShouldHandleNullAuthor() + { + // Arrange + var json = @"{ + ""title"": ""Test"", + ""author"": null, + ""summary"": ""Summary"", + ""url"": ""https://test.com"" + }"; + + // Act + var result = JsonSerializer.Deserialize(json); + + // Assert + result.Should().NotBeNull(); + result!.Author.Should().BeNull(); + } + + [Fact] + public void PostSuggestion_ShouldHandleNullPublicationDate() + { + // Arrange + var json = @"{ + ""title"": ""Test"", + ""summary"": ""Summary"", + ""publication_date"": null, + ""url"": ""https://test.com"" + }"; + + // Act + var result = JsonSerializer.Deserialize(json); + + // Assert + result.Should().NotBeNull(); + result!.PublicationDate.Should().BeNull(); + } + + [Fact] + public void PostSuggestion_RoundTrip_ShouldMaintainValues() + { + // Arrange + var original = new PostSuggestion + { + Title = "Test", + Summary = "Summary", + PublicationDate = "2024-12-13", + Url = "https://test.com", + Author = "Test Author" + }; + + // Act + var json = JsonSerializer.Serialize(original); + var deserialized = JsonSerializer.Deserialize(json); + + // Assert + deserialized.Should().NotBeNull(); + deserialized!.Title.Should().Be(original.Title); + deserialized.Summary.Should().Be(original.Summary); + deserialized.PublicationDate.Should().Be(original.PublicationDate); + deserialized.Url.Should().Be(original.Url); + deserialized.Author.Should().Be(original.Author); + } +} + +public class DateOnlyJsonConverterTests +{ + private readonly JsonSerializerOptions _options; + + public DateOnlyJsonConverterTests() + { + _options = new JsonSerializerOptions(); + _options.Converters.Add(new DateOnlyJsonConverter()); + } + + [Fact] + public void Read_ShouldParseValidDate() + { + // Arrange + var json = "\"2024-01-15\""; + + // Act + var result = JsonSerializer.Deserialize(json, _options); + + // Assert + result.Should().Be("2024-01-15"); + } + + [Fact] + public void Read_ShouldHandleFullDateTime() + { + // Arrange + var json = "\"2024-01-15T10:30:00\""; + + // Act + var result = JsonSerializer.Deserialize(json, _options); + + // Assert + result.Should().Be("2024-01-15"); + } + + [Fact] + public void Read_ShouldHandleNull() + { + // Arrange + var json = "null"; + + // Act + var result = JsonSerializer.Deserialize(json, _options); + + // Assert + result.Should().BeNull(); + } + + [Fact] + public void Read_ShouldHandleEmptyString() + { + // Arrange + var json = "\"\""; + + // Act + var result = JsonSerializer.Deserialize(json, _options); + + // Assert + result.Should().BeNull(); + } + + [Fact] + public void Write_ShouldWriteValue() + { + // Arrange + var date = "2024-01-15"; + + // Act + var json = JsonSerializer.Serialize(date, _options); + + // Assert + json.Should().Be("\"2024-01-15\""); + } + + [Fact] + public void Write_ShouldWriteNull() + { + // Arrange + string? date = null; + + // Act + var json = JsonSerializer.Serialize(date, _options); + + // Assert + json.Should().Be("null"); + } + + [Fact] + public void DateConverter_ShouldFormatWithYearMonthDay() + { + // Arrange + var postSuggestion = new PostSuggestion + { + Title = "Test", + Summary = "Summary", + PublicationDate = "2024-12-01", + Url = "https://test.com" + }; + + // Act + var json = JsonSerializer.Serialize(postSuggestion); + var deserialized = JsonSerializer.Deserialize(json); + + // Assert + deserialized!.PublicationDate.Should().Match("????-??-??"); + } +} diff --git a/src/NoteBookmark.Api.Tests/Domain/ReadingNoteTests.cs b/src/NoteBookmark.Api.Tests/Domain/ReadingNoteTests.cs index aa1a1d4..2f34e9b 100644 --- a/src/NoteBookmark.Api.Tests/Domain/ReadingNoteTests.cs +++ b/src/NoteBookmark.Api.Tests/Domain/ReadingNoteTests.cs @@ -53,4 +53,106 @@ public void ReadingNote_WhenPropertiesSet_ReturnsCorrectValues() readingNote.Category.Should().Be("Performance"); readingNote.ReadingNotesID.Should().Be("reading-notes-123"); } + + [Fact] + public void ToMarkDown_ShouldGenerateCorrectMarkdown_WithAllProperties() + { + // Arrange + var note = new ReadingNote + { + Title = "Test Article", + Url = "https://example.com/article", + Author = "John Doe", + Comment = "Great article!" + }; + + // Act + var result = note.ToMarkDown(); + + // Assert + result.Should().NotBeNull(); + result.Should().Contain("**[Test Article](https://example.com/article)**"); + result.Should().Contain("(John Doe)"); + result.Should().Contain("Great article!"); + } + + [Fact] + public void ToMarkDown_ShouldHandleMissingUrl() + { + // Arrange + var note = new ReadingNote + { + Title = "Test Article", + Url = null, + Author = "John Doe", + Comment = "Great article!" + }; + + // Act + var result = note.ToMarkDown(); + + // Assert + result.Should().NotBeNull(); + result.Should().Contain("**[Test Article]()**"); + result.Should().Contain("(John Doe)"); + result.Should().Contain("Great article!"); + } + + [Fact] + public void ToMarkDown_ShouldHandleMissingTitle() + { + // Arrange + var note = new ReadingNote + { + Title = null, + Url = "https://example.com/article", + Author = "John Doe", + Comment = "Great article!" + }; + + // Act + var result = note.ToMarkDown(); + + // Assert + result.Should().NotBeNull(); + result.Should().Contain("**[](#)**"); + result.Should().Contain("(John Doe)"); + result.Should().Contain("Great article!"); + } + + [Fact] + public void ToMarkDown_ShouldHandleMissingAuthor() + { + // Arrange + var note = new ReadingNote + { + Title = "Test Article", + Url = "https://example.com/article", + Author = null, + Comment = "Great article!" + }; + + // Act + var result = note.ToMarkDown(); + + // Assert + result.Should().NotBeNull(); + result.Should().Contain("**[Test Article](https://example.com/article)**"); + result.Should().NotContain("(John"); + result.Should().Contain("Great article!"); + } + + [Fact] + public void ToMarkDown_ShouldStartWithNewLineAndHyphen() + { + // Arrange + var note = new ReadingNote { Comment = "Test" }; + + // Act + var result = note.ToMarkDown(); + + // Assert + result.Should().StartWith(Environment.NewLine); + result.Should().Contain("- "); + } } diff --git a/src/NoteBookmark.Api.Tests/Domain/SearchCriteriasTests.cs b/src/NoteBookmark.Api.Tests/Domain/SearchCriteriasTests.cs new file mode 100644 index 0000000..41ba009 --- /dev/null +++ b/src/NoteBookmark.Api.Tests/Domain/SearchCriteriasTests.cs @@ -0,0 +1,162 @@ +using FluentAssertions; +using NoteBookmark.Domain; +using Xunit; + +namespace NoteBookmark.Api.Tests.Domain; + +public class SearchCriteriasTests +{ + [Fact] + public void Constructor_ShouldSetSearchPrompt() + { + // Arrange + var searchPrompt = "Find articles about {topic} from the last week"; + + // Act + var criterias = new SearchCriterias(searchPrompt); + + // Assert + var result = criterias.GetSearchPrompt(); + result.Should().Contain("Find articles about"); + } + + [Fact] + public void GetSplittedAllowedDomains_ShouldReturnNull_WhenAllowedDomainsIsNull() + { + // Arrange + var criterias = new SearchCriterias("test") { AllowedDomains = null }; + + // Act + var result = criterias.GetSplittedAllowedDomains(); + + // Assert + result.Should().BeNull(); + } + + [Fact] + public void GetSplittedAllowedDomains_ShouldSplitAndTrim_WhenAllowedDomainsProvided() + { + // Arrange + var criterias = new SearchCriterias("test") + { + AllowedDomains = "example.com, test.com , another.com" + }; + + // Act + var result = criterias.GetSplittedAllowedDomains(); + + // Assert + result.Should().NotBeNull(); + result.Should().HaveCount(3); + result.Should().Contain("example.com"); + result.Should().Contain("test.com"); + result.Should().Contain("another.com"); + } + + [Fact] + public void GetSplittedAllowedDomains_ShouldHandleSingleDomain() + { + // Arrange + var criterias = new SearchCriterias("test") { AllowedDomains = "example.com" }; + + // Act + var result = criterias.GetSplittedAllowedDomains(); + + // Assert + result.Should().NotBeNull(); + result.Should().HaveCount(1); + result.Should().Contain("example.com"); + } + + [Fact] + public void GetSplittedBlockedDomains_ShouldReturnNull_WhenBlockedDomainsIsNull() + { + // Arrange + var criterias = new SearchCriterias("test") { BlockedDomains = null }; + + // Act + var result = criterias.GetSplittedBlockedDomains(); + + // Assert + result.Should().BeNull(); + } + + [Fact] + public void GetSplittedBlockedDomains_ShouldSplitAndTrim_WhenBlockedDomainsProvided() + { + // Arrange + var criterias = new SearchCriterias("test") + { + BlockedDomains = "spam.com, bad.com, malicious.com " + }; + + // Act + var result = criterias.GetSplittedBlockedDomains(); + + // Assert + result.Should().NotBeNull(); + result.Should().HaveCount(3); + result.Should().Contain("spam.com"); + result.Should().Contain("bad.com"); + result.Should().Contain("malicious.com"); + } + + [Fact] + public void GetSearchPrompt_ShouldReplaceTopicPlaceholder() + { + // Arrange + var criterias = new SearchCriterias("Find articles about {topic}") + { + SearchTopic = "Azure DevOps" + }; + + // Act + var result = criterias.GetSearchPrompt(); + + // Assert + result.Should().Be("Find articles about Azure DevOps "); + } + + [Fact] + public void GetSearchPrompt_ShouldHandleNullSearchTopic() + { + // Arrange + var criterias = new SearchCriterias("Find articles about {topic}") { SearchTopic = null }; + + // Act + var result = criterias.GetSearchPrompt(); + + // Assert + result.Should().Be("Find articles about "); + } + + [Fact] + public void GetSearchPrompt_ShouldHandleEmptySearchTopic() + { + // Arrange + var criterias = new SearchCriterias("Find articles about {topic}") { SearchTopic = "" }; + + // Act + var result = criterias.GetSearchPrompt(); + + // Assert + result.Should().Be("Find articles about "); + } + + [Fact] + public void Properties_ShouldBeSettable() + { + // Arrange + var criterias = new SearchCriterias("test"); + + // Act + criterias.SearchTopic = "Kubernetes"; + criterias.AllowedDomains = "k8s.io"; + criterias.BlockedDomains = "spam.com"; + + // Assert + criterias.SearchTopic.Should().Be("Kubernetes"); + criterias.AllowedDomains.Should().Be("k8s.io"); + criterias.BlockedDomains.Should().Be("spam.com"); + } +}