1- using NUnit . Framework ;
2- using EmailValidation ;
1+ using NUnit . Framework ;
32
4- namespace OutSystems . YAEmailValidalitor . Tests
3+ namespace OutSystems . YAEmailValidator . UnitTests
54{
5+ /// <summary>
6+ /// Unit tests for <see cref="YAEmailValidator.EmailValidate"/>.
7+ /// All tests exercise the wrapper (not the underlying EmailValidation library directly).
8+ ///
9+ /// TEST INDEX
10+ /// ──────────────────────────────────────────────────────────────────
11+ /// # Method Cases Line
12+ /// ──────────────────────────────────────────────────────────────────
13+ /// 1. Validate_ValidEmails_ReturnsTrue 8 30
14+ /// 2. Validate_InvalidEmails_ReturnsFalse 10 45
15+ /// 3. Validate_EmptyOrWhitespace_ReturnsFalse 2 62
16+ /// 4. Validate_NullEmail_ThrowsArgumentNullException 1 69
17+ /// 5. Validate_LeadingTrailingWhitespace_WhenNotAllowed 3 80
18+ /// 6. Validate_LeadingTrailingWhitespace_WhenAllowed 3 89
19+ /// 7. Validate_InternationalEmails_WhenAllowed_ReturnsTrue 2 99
20+ /// 8. Validate_InternationalEmails_WhenNotAllowed_ReturnsFalse 1 108
21+ /// 9. Validate_TopLevelDomain_WhenAllowed_ReturnsTrue 1 116
22+ /// 10. Validate_TopLevelDomain_WhenNotAllowed_ReturnsFalse 1 123
23+ /// 11. Validate_ShouldRejectDisplayNamesAndComments 2 131
24+ /// 12. Validate_LocalPartBoundary 2 142
25+ /// 13. Validate_TotalLengthBoundary 3 157
26+ /// 14. Validate_ShouldRejectInvalidDotPlacement 3 179
27+ /// ──────────────────────────────────────────────────────────────────
28+ /// Total: 39
29+ ///
30+ /// COVERAGE BY FEATURE
31+ /// ──────────────────────────────────────────────────────────────────
32+ /// Feature / Flag Tests
33+ /// ──────────────────────────────────────────────────────────────────
34+ /// Basic valid/invalid emails #1, #2
35+ /// Empty/whitespace/null input #3, #4
36+ /// allowLeadingTrailingWhitespace flag #5, #6
37+ /// allowInternational flag (RFC 6531) #7, #8
38+ /// allowTopLevelDomains flag #9, #10
39+ /// RFC 5321 compliance #11 (display names), #12 (local part 64-char),
40+ /// #13 (total 254-char), #14 (dot placement)
41+ /// ──────────────────────────────────────────────────────────────────
42+ /// </summary>
643 [ TestFixture ]
7- public class EmailValidatorTests
44+ public class YAEmailValidatorTests
845 {
9- // Tests for valid email addresses
46+ private readonly YAEmailValidator _validator = new ( ) ;
47+
48+ private bool Validate ( string email ,
49+ bool allowWhitespace = false ,
50+ bool allowInternational = false ,
51+ bool allowTopLevelDomains = false )
52+ {
53+ _validator . EmailValidate ( email , allowWhitespace , allowInternational , allowTopLevelDomains , out bool result ) ;
54+ return result ;
55+ }
56+
57+ // --- Valid emails ---
58+
1059 [ TestCase ( "test@example.com" ) ]
1160 [ TestCase ( "firstname.lastname@domain.com" ) ]
1261 [ TestCase ( "email@subdomain.domain.com" ) ]
@@ -17,11 +66,11 @@ public class EmailValidatorTests
1766 [ TestCase ( "email@domain.co.jp" ) ]
1867 public void Validate_ValidEmails_ReturnsTrue ( string email )
1968 {
20- bool result = EmailValidator . Validate ( email ) ;
21- Assert . That ( result , Is . True , $ "Expected '{ email } ' to be valid.") ;
69+ Assert . That ( Validate ( email ) , Is . True , $ "Expected '{ email } ' to be valid.") ;
2270 }
2371
24- // Tests for invalid email addresses
72+ // --- Invalid emails ---
73+
2574 [ TestCase ( "plainaddress" ) ] // No @ or domain
2675 [ TestCase ( "#@%^%#$@#$@#.com" ) ] // Garbage characters
2776 [ TestCase ( "@domain.com" ) ] // Missing username
@@ -34,81 +83,136 @@ public void Validate_ValidEmails_ReturnsTrue(string email)
3483 [ TestCase ( "email@domain..com" ) ] // Double dots in domain
3584 public void Validate_InvalidEmails_ReturnsFalse ( string email )
3685 {
37- bool result = EmailValidator . Validate ( email ) ;
38- Assert . That ( result , Is . False , $ "Expected '{ email } ' to be invalid.") ;
86+ Assert . That ( Validate ( email ) , Is . False , $ "Expected '{ email } ' to be invalid.") ;
3987 }
4088
41- // Tests for whitespace
89+ // --- Empty and whitespace ---
90+
4291 [ TestCase ( "" ) ]
4392 [ TestCase ( " " ) ]
44- public void Validate_EmptyOrNull_ReturnsFalse ( string email )
93+ public void Validate_EmptyOrWhitespace_ReturnsFalse ( string email )
94+ {
95+ Assert . That ( Validate ( email ) , Is . False ) ;
96+ }
97+
98+ // --- Null handling ---
99+
100+ [ Test ]
101+ public void Validate_NullEmail_ThrowsArgumentNullException ( )
102+ {
103+ Assert . Throws < ArgumentNullException > ( ( ) =>
104+ _validator . EmailValidate ( null ! , false , false , false , out _ ) ) ;
105+ }
106+
107+ // --- Whitespace flag ---
108+
109+ [ TestCase ( " test@example.com" ) ]
110+ [ TestCase ( "test@example.com " ) ]
111+ [ TestCase ( " test@example.com " ) ]
112+ public void Validate_LeadingTrailingWhitespace_WhenNotAllowed_ReturnsFalse ( string email )
113+ {
114+ Assert . That ( Validate ( email , allowWhitespace : false ) , Is . False ,
115+ $ "Expected '{ email } ' to be invalid when whitespace is not allowed.") ;
116+ }
117+
118+ [ TestCase ( " test@example.com" ) ]
119+ [ TestCase ( "test@example.com " ) ]
120+ [ TestCase ( " test@example.com " ) ]
121+ public void Validate_LeadingTrailingWhitespace_WhenAllowed_ReturnsTrue ( string email )
122+ {
123+ Assert . That ( Validate ( email , allowWhitespace : true ) , Is . True ,
124+ $ "Expected '{ email } ' to be valid when whitespace is allowed (trimmed before validation).") ;
125+ }
126+
127+ // --- International support (RFC 6531) ---
128+
129+ [ TestCase ( "t\u00e9 st@domain.com" ) ]
130+ [ TestCase ( "\u7528 \u6237 @\u4f8b \u5b50 .\u5e7f \u544a " ) ]
131+ public void Validate_InternationalEmails_WhenAllowed_ReturnsTrue ( string email )
132+ {
133+ Assert . That ( Validate ( email , allowInternational : true ) , Is . True ,
134+ $ "Expected international email '{ email } ' to be valid.") ;
135+ }
136+
137+ [ TestCase ( "t\u00e9 st@domain.com" ) ]
138+ public void Validate_InternationalEmails_WhenNotAllowed_ReturnsFalse ( string email )
45139 {
46- bool result = EmailValidator . Validate ( email ) ;
47- Assert . That ( result , Is . False ) ;
140+ Assert . That ( Validate ( email , allowInternational : false ) , Is . False ,
141+ $ "Expected international email ' { email } ' to be invalid when international is not allowed." ) ;
48142 }
49143
50- // To truly validate that your library is adhering to RFC 5321, you should use these specific test cases.
51- // These are designed to catch "loose" validators that fail to enforce the technical limits of the SMTP protocol.
144+ // --- Top-level domain flag ---
145+
146+ [ Test ]
147+ public void Validate_TopLevelDomain_WhenAllowed_ReturnsTrue ( )
148+ {
149+ Assert . That ( Validate ( "user@localhost" , allowTopLevelDomains : true ) , Is . True ,
150+ "Expected 'user@localhost' to be valid when TLDs are allowed." ) ;
151+ }
52152
53- // INTERNATIONALIZATION (RFC 6531)
54- [ TestCase ( "tést@domain.com" ) ]
55- [ TestCase ( "用户@例子.广告" ) ]
56- public void Validate_InternationalEmails ( string email )
153+ [ Test ]
154+ public void Validate_TopLevelDomain_WhenNotAllowed_ReturnsFalse ( )
57155 {
58- // Jeffrey's lib supports this if the overload is called correctly
59- Assert . That ( EmailValidator . Validate ( email , allowInternational : true ) , Is . True ) ;
156+ Assert . That ( Validate ( "user@localhost" , allowTopLevelDomains : false ) , Is . False ,
157+ "Expected 'user@localhost' to be invalid when TLDs are not allowed." ) ;
60158 }
61159
62- // 1. THE "DISPLAY NAME" TRAP
63- // MailAddress passes this; EmailValidation correctly fails it.
160+ // --- Display name rejection (RFC 5321) ---
161+
64162 [ TestCase ( "Jeffrey Stedfast <jestedfa@microsoft.com>" ) ]
65163 [ TestCase ( "jestedfa@microsoft.com (Jeffrey Stedfast)" ) ]
66164 public void Validate_ShouldRejectDisplayNamesAndComments ( string email )
67165 {
68- Assert . That ( EmailValidator . Validate ( email ) , Is . False ,
166+ Assert . That ( Validate ( email ) , Is . False ,
69167 "RFC 5321 Address literals should not include display names or comments." ) ;
70168 }
71169
72- // 2. LOCAL PART LENGTH (Exactly 64 chars is allowed, 65 is not)
170+ // --- Local part length boundary (64 chars max) ---
171+
73172 [ Test ]
74173 public void Validate_LocalPartBoundary ( )
75174 {
76175 string sixtyFourChars = new string ( 'a' , 64 ) ;
77176 string sixtyFiveChars = new string ( 'a' , 65 ) ;
78177
79- Assert . That ( EmailValidator . Validate ( $ "{ sixtyFourChars } @domain.com") , Is . True , "64 chars should pass." ) ;
80- Assert . That ( EmailValidator . Validate ( $ "{ sixtyFiveChars } @domain.com") , Is . False , "65 chars must fail." ) ;
178+ Assert . Multiple ( ( ) =>
179+ {
180+ Assert . That ( Validate ( $ "{ sixtyFourChars } @domain.com") , Is . True , "64 chars should pass." ) ;
181+ Assert . That ( Validate ( $ "{ sixtyFiveChars } @domain.com") , Is . False , "65 chars must fail." ) ;
182+ } ) ;
81183 }
82184
83- // 3. TOTAL LENGTH (Maximum 254 characters)
185+ // --- Total length boundary (254 chars max) ---
186+
84187 [ Test ]
85188 public void Validate_TotalLengthBoundary ( )
86- { // A valid domain must have labels no longer than 63 characters
189+ {
190+ // A valid domain must have labels no longer than 63 characters
87191 string label63 = new string ( 'b' , 63 ) ;
88192 string domain = $ "{ label63 } .{ label63 } .{ label63 } .com"; // 63*3 + 3 dots + 3 'com' = 195 chars
89193
90194 // 254 - 1 (@) - 195 (domain) = 58
91195 string local = new string ( 'a' , 58 ) ;
92-
93196 string valid254 = $ "{ local } @{ domain } ";
94197
95198 Assert . Multiple ( ( ) =>
96199 {
97200 Assert . That ( valid254 . Length , Is . EqualTo ( 254 ) , "Manual check that string is 254" ) ;
98- Assert . That ( EmailValidator . Validate ( valid254 ) , Is . True , "254 chars with valid labels should pass." ) ;
201+ Assert . That ( Validate ( valid254 ) , Is . True , "254 chars with valid labels should pass." ) ;
99202
100203 string invalid255 = "a" + valid254 ;
101- Assert . That ( EmailValidator . Validate ( invalid255 ) , Is . False , "255 chars must fail." ) ;
204+ Assert . That ( Validate ( invalid255 ) , Is . False , "255 chars must fail." ) ;
102205 } ) ;
103206 }
104207
105- // 4. THE "DOUBLE DOT" AND PURE SYNTAX
208+ // --- Invalid dot placement ---
209+
106210 [ TestCase ( "user..name@domain.com" ) ] // Consecutive dots
107211 [ TestCase ( ".user@domain.com" ) ] // Leading dot
108212 [ TestCase ( "user.@domain.com" ) ] // Trailing dot in local part
109213 public void Validate_ShouldRejectInvalidDotPlacement ( string email )
110214 {
111- Assert . That ( EmailValidator . Validate ( email ) , Is . False ) ;
215+ Assert . That ( Validate ( email ) , Is . False ) ;
112216 }
113217 }
114- }
218+ }
0 commit comments