Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions CSharpExtender/DataAnnotations/AlphaOnlyAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.ComponentModel.DataAnnotations;

namespace CSharpExtender.DataAnnotations;

public class AlphaOnlyAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value == null)
{
return ValidationResult.Success;
}

string input = value.ToString();

if (string.IsNullOrEmpty(input))
{
return ValidationResult.Success;
}

ReadOnlySpan<char> span = input.AsSpan();

for (int i = 0; i < span.Length; i++)
{
if (!char.IsLetter(span[i]))
{
return new ValidationResult(ErrorMessage ?? "Must contain only letters.");
}
}

return ValidationResult.Success;
}
}
139 changes: 139 additions & 0 deletions Test.CSharpExtender/DataAnnotations/Test_AlphaOnlyAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
using CSharpExtender.DataAnnotations;
using System.ComponentModel.DataAnnotations;

namespace Test.CSharpExtender.DataAnnotations;

public class Test_AlphaOnlyAttribute
{
// Helper method to validate an input string with the attribute
private static ValidationResult Validate(string? input, string? errorMessage = null)
{
var attribute = errorMessage == null
? new AlphaOnlyAttribute()
: new AlphaOnlyAttribute { ErrorMessage = errorMessage };

var context = new ValidationContext(new object());

return attribute.GetValidationResult(input, context);

Check warning on line 17 in Test.CSharpExtender/DataAnnotations/Test_AlphaOnlyAttribute.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference return.

Check warning on line 17 in Test.CSharpExtender/DataAnnotations/Test_AlphaOnlyAttribute.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference return.
}

[Fact]
public void NullInput_ReturnsSuccess()
{
// Arrange & Act
var result = Validate(null);

// Assert
Assert.Equal(ValidationResult.Success, result);
}

[Fact]
public void EmptyString_ReturnsSuccess()
{
// Arrange & Act
var result = Validate("");

// Assert
Assert.Equal(ValidationResult.Success, result);
}

[Theory]
[InlineData("abc")]
[InlineData("ABC")]
[InlineData("HelloWorld")]
[InlineData("a")]
[InlineData("Z")]
public void ValidAlphaOnlyStrings_ReturnsSuccess(string input)
{
// Arrange & Act
var result = Validate(input);

// Assert
Assert.Equal(ValidationResult.Success, result);
}

[Theory]
[InlineData("123", "Must contain only letters.")]
[InlineData("abc123", "Must contain only letters.")]
[InlineData("abc 123", "Must contain only letters.")]
[InlineData("abc!", "Must contain only letters.")]
[InlineData(" ", "Must contain only letters.")]
[InlineData("@#$%", "Must contain only letters.")]
public void InvalidStrings_ReturnsDefaultErrorMessage(string input, string expectedError)
{
// Arrange & Act
var result = Validate(input);

// Assert
Assert.NotEqual(ValidationResult.Success, result);
Assert.Equal(expectedError, result.ErrorMessage);
}

[Theory]
[InlineData("abc123", "Only letters allowed here.")]
[InlineData("abc 123", "Only letters allowed here.")]
[InlineData("123", "Only letters allowed here.")]
public void InvalidStrings_ReturnsCustomErrorMessage(string input, string customError)
{
// Arrange & Act
var result = Validate(input, customError);

// Assert
Assert.NotEqual(ValidationResult.Success, result);
Assert.Equal(customError, result.ErrorMessage);
}

[Fact]
public void MixedCaseString_ReturnsSuccess()
{
// Arrange
string input = "HelloWorld123".Substring(0, 10);

// Act
var result = Validate(input);

// Assert
Assert.Equal(ValidationResult.Success, result);
}

[Fact]
public void SingleNonLetterAtStart_ReturnsFailure()
{
// Arrange
string input = "1abc";

// Act
var result = Validate(input);

// Assert
Assert.NotEqual(ValidationResult.Success, result);
Assert.Equal("Must contain only letters.", result.ErrorMessage);
}

[Fact]
public void SingleNonLetterAtEnd_ReturnsFailure()
{
// Arrange
string input = "abc1";

// Act
var result = Validate(input);

// Assert
Assert.NotEqual(ValidationResult.Success, result);
Assert.Equal("Must contain only letters.", result.ErrorMessage);
}

[Fact]
public void UnicodeLetters_ReturnsSuccess()
{
// Arrange
string input = "café"; // Contains 'é', a Unicode letter

// Act
var result = Validate(input);

// Assert
Assert.Equal(ValidationResult.Success, result);
}
}
Loading