using ChatBot.Services.Telegram.Commands; using FluentAssertions; using Xunit; namespace ChatBot.Tests.Telegram.Commands; public class CommandAttributeTests { [Fact] public void CommandAttribute_ShouldHaveCorrectAttributeUsage() { // Arrange var attributeType = typeof(CommandAttribute); var attributeUsage = attributeType .GetCustomAttributes(typeof(AttributeUsageAttribute), false) .Cast() .FirstOrDefault(); // Assert attributeUsage.Should().NotBeNull(); attributeUsage!.ValidOn.Should().Be(AttributeTargets.Class); attributeUsage.AllowMultiple.Should().BeFalse(); } [Fact] public void CommandAttribute_ShouldSetCommandNameAndDescription() { // Arrange var commandName = "/test"; var description = "Test command"; // Act var attribute = new CommandAttribute(commandName, description); // Assert attribute.CommandName.Should().Be(commandName); attribute.Description.Should().Be(description); attribute.Priority.Should().Be(0); // Default value } [Fact] public void CommandAttribute_ShouldAllowSettingPriority() { // Arrange var commandName = "/test"; var description = "Test command"; var priority = 5; // Act var attribute = new CommandAttribute(commandName, description) { Priority = priority }; // Assert attribute.CommandName.Should().Be(commandName); attribute.Description.Should().Be(description); attribute.Priority.Should().Be(priority); } [Theory] [InlineData("/start", "Start the bot")] [InlineData("/help", "Show help")] [InlineData("/status", "Show status")] [InlineData("/clear", "Clear chat history")] [InlineData("/settings", "Show settings")] public void CommandAttribute_ShouldAcceptValidCommandNames( string commandName, string description ) { // Act var attribute = new CommandAttribute(commandName, description); // Assert attribute.CommandName.Should().Be(commandName); attribute.Description.Should().Be(description); } [Theory] [InlineData("")] [InlineData("start")] [InlineData("help")] [InlineData("status")] [InlineData("clear")] [InlineData("settings")] public void CommandAttribute_ShouldAcceptCommandNamesWithoutSlash(string commandName) { // Arrange var description = "Test command"; // Act var attribute = new CommandAttribute(commandName, description); // Assert attribute.CommandName.Should().Be(commandName); attribute.Description.Should().Be(description); } [Theory] [InlineData("")] [InlineData("A simple description")] [InlineData( "A very long description that contains multiple words and explains what the command does in detail" )] [InlineData("Описание на русском языке")] [InlineData("Description with special characters: !@#$%^&*()_+-=[]{}|;':\",./<>?")] [InlineData("Description with unicode: 用户 ユーザー مستخدم")] public void CommandAttribute_ShouldAcceptVariousDescriptions(string description) { // Arrange var commandName = "/test"; // Act var attribute = new CommandAttribute(commandName, description); // Assert attribute.CommandName.Should().Be(commandName); attribute.Description.Should().Be(description); } [Theory] [InlineData(0)] [InlineData(1)] [InlineData(10)] [InlineData(100)] [InlineData(int.MaxValue)] [InlineData(int.MinValue)] [InlineData(-1)] [InlineData(-100)] public void CommandAttribute_ShouldAcceptVariousPriorities(int priority) { // Arrange var commandName = "/test"; var description = "Test command"; // Act var attribute = new CommandAttribute(commandName, description) { Priority = priority }; // Assert attribute.Priority.Should().Be(priority); } [Fact] public void CommandAttribute_ShouldAllowNullCommandName() { // Arrange string? commandName = null; var description = "Test command"; // Act var attribute = new CommandAttribute(commandName!, description); // Assert attribute.CommandName.Should().BeNull(); attribute.Description.Should().Be(description); } [Fact] public void CommandAttribute_ShouldAllowNullDescription() { // Arrange var commandName = "/test"; string? description = null; // Act var attribute = new CommandAttribute(commandName, description!); // Assert attribute.CommandName.Should().Be(commandName); attribute.Description.Should().BeNull(); } [Fact] public void CommandAttribute_ShouldAllowBothNullValues() { // Arrange string? commandName = null; string? description = null; // Act var attribute = new CommandAttribute(commandName!, description!); // Assert attribute.CommandName.Should().BeNull(); attribute.Description.Should().BeNull(); } [Fact] public void CommandAttribute_ShouldBeImmutableAfterConstruction() { // Arrange var commandName = "/test"; var description = "Test command"; var attribute = new CommandAttribute(commandName, description); // Act & Assert // CommandName and Description should be read-only var commandNameProperty = typeof(CommandAttribute).GetProperty( nameof(CommandAttribute.CommandName) ); var descriptionProperty = typeof(CommandAttribute).GetProperty( nameof(CommandAttribute.Description) ); commandNameProperty!.CanWrite.Should().BeFalse(); descriptionProperty!.CanWrite.Should().BeFalse(); } [Fact] public void CommandAttribute_ShouldAllowPriorityModification() { // Arrange var commandName = "/test"; var description = "Test command"; var attribute = new CommandAttribute(commandName, description); // Act attribute.Priority = 42; // Assert attribute.Priority.Should().Be(42); } [Fact] public void CommandAttribute_ShouldInheritFromAttribute() { // Arrange & Act var attribute = new CommandAttribute("/test", "Test command"); // Assert attribute.Should().BeAssignableTo(); } [Fact] public void CommandAttribute_ShouldBeSerializable() { // Arrange var commandName = "/test"; var description = "Test command"; var priority = 5; var attribute = new CommandAttribute(commandName, description) { Priority = priority }; // Act & Assert // Check if the attribute can be serialized (basic check) attribute.Should().NotBeNull(); // Note: In .NET 5+, IsSerializable is obsolete and returns false for most types // This test verifies the attribute can be created and used attribute.GetType().Should().NotBeNull(); } [Fact] public void CommandAttribute_ShouldHandleVeryLongCommandName() { // Arrange var commandName = new string('a', 1000); // Very long command name var description = "Test command"; // Act var attribute = new CommandAttribute(commandName, description); // Assert attribute.CommandName.Should().Be(commandName); attribute.CommandName.Should().HaveLength(1000); } [Fact] public void CommandAttribute_ShouldHandleVeryLongDescription() { // Arrange var commandName = "/test"; var description = new string('a', 10000); // Very long description // Act var attribute = new CommandAttribute(commandName, description); // Assert attribute.Description.Should().Be(description); attribute.Description.Should().HaveLength(10000); } [Fact] public void CommandAttribute_ShouldHandleCommandNameWithSpecialCharacters() { // Arrange var commandName = "/test-command_with.special@chars#123"; var description = "Test command"; // Act var attribute = new CommandAttribute(commandName, description); // Assert attribute.CommandName.Should().Be(commandName); } [Fact] public void CommandAttribute_ShouldHandleDescriptionWithNewlines() { // Arrange var commandName = "/test"; var description = "Line 1\nLine 2\nLine 3"; // Act var attribute = new CommandAttribute(commandName, description); // Assert attribute.Description.Should().Be(description); } [Fact] public void CommandAttribute_ShouldHandleDescriptionWithTabs() { // Arrange var commandName = "/test"; var description = "Column1\tColumn2\tColumn3"; // Act var attribute = new CommandAttribute(commandName, description); // Assert attribute.Description.Should().Be(description); } [Fact] public void CommandAttribute_ShouldHandleDescriptionWithCarriageReturns() { // Arrange var commandName = "/test"; var description = "Line 1\r\nLine 2\r\nLine 3"; // Act var attribute = new CommandAttribute(commandName, description); // Assert attribute.Description.Should().Be(description); } [Fact] public void CommandAttribute_ShouldHandleWhitespaceOnlyCommandName() { // Arrange var commandName = " "; var description = "Test command"; // Act var attribute = new CommandAttribute(commandName, description); // Assert attribute.CommandName.Should().Be(commandName); } [Fact] public void CommandAttribute_ShouldHandleWhitespaceOnlyDescription() { // Arrange var commandName = "/test"; var description = " "; // Act var attribute = new CommandAttribute(commandName, description); // Assert attribute.Description.Should().Be(description); } [Fact] public void CommandAttribute_ShouldHandleCommandNameWithUnicode() { // Arrange var commandName = "/команда_命令_コマンド_أمر"; var description = "Test command"; // Act var attribute = new CommandAttribute(commandName, description); // Assert attribute.CommandName.Should().Be(commandName); } [Fact] public void CommandAttribute_ShouldHandleDescriptionWithUnicode() { // Arrange var commandName = "/test"; var description = "Описание команды 命令描述 コマンドの説明 وصف الأمر"; // Act var attribute = new CommandAttribute(commandName, description); // Assert attribute.Description.Should().Be(description); } [Fact] public void CommandAttribute_ShouldHandleCommandNameWithSpaces() { // Arrange var commandName = "/test command with spaces"; var description = "Test command"; // Act var attribute = new CommandAttribute(commandName, description); // Assert attribute.CommandName.Should().Be(commandName); } [Fact] public void CommandAttribute_ShouldHandleDescriptionWithSpaces() { // Arrange var commandName = "/test"; var description = "This is a test command with multiple spaces"; // Act var attribute = new CommandAttribute(commandName, description); // Assert attribute.Description.Should().Be(description); } [Fact] public void CommandAttribute_ShouldHandleCommandNameWithNumbers() { // Arrange var commandName = "/test123"; var description = "Test command"; // Act var attribute = new CommandAttribute(commandName, description); // Assert attribute.CommandName.Should().Be(commandName); } [Fact] public void CommandAttribute_ShouldHandleDescriptionWithNumbers() { // Arrange var commandName = "/test"; var description = "Test command version 1.0.0 build 123"; // Act var attribute = new CommandAttribute(commandName, description); // Assert attribute.Description.Should().Be(description); } }