-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
11aabf1
commit e112882
Showing
3 changed files
with
177 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
namespace BrazilModels; | ||
|
||
using System; | ||
using System.ComponentModel; | ||
using System.Diagnostics; | ||
|
||
/// <summary> | ||
/// Basic strongly typed E-mail representation | ||
/// </summary> | ||
[System.Text.Json.Serialization.JsonConverter(typeof(StringSystemTextJsonConverter<Email>))] | ||
[TypeConverter(typeof(StringTypeConverter<Email>))] | ||
[DebuggerDisplay("{DebuggerDisplay(),nq}")] | ||
[Swashbuckle.AspNetCore.Annotations.SwaggerSchemaFilter(typeof(StringSchemaFilter))] | ||
public readonly record struct Email : IComparable<Email> | ||
{ | ||
/// <summary> | ||
/// String representation of the Email | ||
/// </summary> | ||
public string Value { get; } | ||
|
||
/// <summary> | ||
/// Create a new email instance | ||
/// </summary> | ||
/// <exception cref="InvalidOperationException"></exception> | ||
/// <exception cref="ArgumentNullException"></exception> | ||
public Email(string email) | ||
{ | ||
ArgumentNullException.ThrowIfNull(email); | ||
this.Value = email.ToLowerInvariant(); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public override string ToString() => Value; | ||
|
||
/// <summary> | ||
/// Get Email instance of an Value string | ||
/// </summary> | ||
/// <exception cref="InvalidOperationException"></exception> | ||
/// <exception cref="ArgumentNullException"></exception> | ||
public static explicit operator Email(string value) | ||
=> Parse(value); | ||
|
||
/// <summary> | ||
/// Return string representation of Email | ||
/// </summary> | ||
public static implicit operator string(Email email) | ||
=> email.Value; | ||
|
||
/// <summary> | ||
/// Try parse an Value string to an Email instance | ||
/// </summary> | ||
public static bool TryParse(string? value, out Email email) | ||
{ | ||
email = default; | ||
if (value is null || !IsValid(value)) | ||
return false; | ||
|
||
email = new(value); | ||
return true; | ||
} | ||
|
||
/// <summary> | ||
/// Parse an Value string to an Email instance | ||
/// </summary> | ||
/// <exception cref="InvalidOperationException"></exception> | ||
/// <exception cref="ArgumentNullException"></exception> | ||
public static Email Parse(string value) => | ||
TryParse(value, out var valid) | ||
? valid | ||
: throw new InvalidOperationException($"Invalid E-mail {value}"); | ||
|
||
/// <summary> | ||
/// Validate Email string | ||
/// </summary> | ||
/// <param name="value"></param> | ||
/// <returns></returns> | ||
public static bool IsValid(string? value) | ||
{ | ||
const string at = "@"; | ||
if (value is null) | ||
return false; | ||
|
||
var index = value.IndexOf(at, StringComparison.OrdinalIgnoreCase); | ||
|
||
return index > 0 && | ||
index != value.Length - 1 && | ||
index == value.LastIndexOf(at, StringComparison.OrdinalIgnoreCase); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public int CompareTo(Email other) => | ||
string.Compare(Value, other.Value, StringComparison.OrdinalIgnoreCase); | ||
|
||
string DebuggerDisplay() => $"EMAIL{{{Value}}}"; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
namespace BrazilModels.Tests; | ||
|
||
using System.Text.Json; | ||
|
||
public class EmailTests : BaseTest | ||
{ | ||
[Test] | ||
public void ShouldReturnValidForValidEmail() | ||
{ | ||
var emailStr = faker.Person.Email; | ||
Email.IsValid(emailStr).Should().BeTrue(); | ||
} | ||
|
||
[Test] | ||
public void ShouldReturnFalseForInvalid() | ||
{ | ||
var emailStr = faker.Person.FirstName; | ||
Email.IsValid(emailStr).Should().BeFalse(); | ||
} | ||
|
||
[Test] | ||
public void ShouldParseEmail() | ||
{ | ||
var emailStr = "[email protected]"; | ||
var sut = Email.Parse(emailStr); | ||
sut.Value.Should().Be(emailStr); | ||
} | ||
|
||
[Test] | ||
public void ShouldThrowInvalidEmail() | ||
{ | ||
var emailStr = faker.Person.FirstName; | ||
var action = () => Email.Parse(emailStr); | ||
action.Should().Throw<InvalidOperationException>(); | ||
} | ||
|
||
[Test] | ||
public void ShouldTryParseSuccessfully() | ||
{ | ||
var emailStr = faker.Person.Email; | ||
Email.TryParse(emailStr, out var email).Should().BeTrue(); | ||
email.Value.Should().Be(emailStr.ToLower()); | ||
} | ||
|
||
[Test] | ||
public void ShouldTryParseReturnFalse() | ||
{ | ||
var emailStr = faker.Person.FirstName; | ||
Email.TryParse(emailStr, out _).Should().BeFalse(); | ||
} | ||
|
||
[Test] | ||
public void ShouldCompareEmail() | ||
{ | ||
var emailStr = faker.Person.Email; | ||
Email emailLower = Email.Parse(emailStr.ToLowerInvariant()); | ||
Email emailUpper = Email.Parse(emailStr.ToUpperInvariant()); | ||
emailLower.Should().Be(emailUpper); | ||
} | ||
|
||
|
||
record Sut(Email Value); | ||
|
||
[Test] | ||
public void ShouldSerializeEmail() | ||
{ | ||
var data = faker.Person.Email; | ||
var json = JsonSerializer.Serialize(new Sut(Email.Parse(data))); | ||
json.Should().Be(@$"{{""Value"":""{data.ToLowerInvariant()}""}}"); | ||
} | ||
|
||
[Test] | ||
public void ShouldDeserializeEmail() | ||
{ | ||
var value = Email.Parse(faker.Person.Email); | ||
var body = @$"{{""Value"":""{value.Value}""}}"; | ||
var parsed = JsonSerializer.Deserialize<Sut>(body)!; | ||
var expected = Email.Parse(value); | ||
parsed.Value.Should().Be(expected); | ||
} | ||
} |