Skip to content

Commit a8cd44a

Browse files
committed
Little Update.
Added support for erroring out on addresses at top-level domains
1 parent 74a65e9 commit a8cd44a

File tree

3 files changed

+71
-39
lines changed

3 files changed

+71
-39
lines changed

EmailValidation.Test/src/EmailValidationTest.pas

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ procedure TEmailValidationTest.TestValidAddressesOneBased;
117117
for LoopCount := 0 to Length(FValidAddresses) - 1 do
118118
begin
119119
Assert.IsTrue(uEmailValidation.TEmailValidator.Validate(FValidAddresses
120-
[LoopCount]), Format('Valid Address %d: %s',
120+
[LoopCount], True), Format('Valid Address %d: %s',
121121
[LoopCount, FValidAddresses[LoopCount]]));
122122
end;
123123

@@ -130,7 +130,7 @@ procedure TEmailValidationTest.TestValidAddressesZeroBased;
130130
for LoopCount := 0 to Length(FValidAddresses) - 1 do
131131
begin
132132
Assert.IsTrue(uEmailValidationZeroBased.TEmailValidator.Validate
133-
(FValidAddresses[LoopCount]), Format('Valid Address %d: %s',
133+
(FValidAddresses[LoopCount], True), Format('Valid Address %d: %s',
134134
[LoopCount, FValidAddresses[LoopCount]]));
135135
end;
136136

@@ -143,7 +143,7 @@ procedure TEmailValidationTest.TestInvalidAddressesOneBased;
143143
for LoopCount := 0 to Length(FInvalidAddresses) - 1 do
144144
begin
145145
Assert.IsFalse(uEmailValidation.TEmailValidator.Validate(FInvalidAddresses
146-
[LoopCount]), Format('Invalid Address %d: %s',
146+
[LoopCount], True), Format('Invalid Address %d: %s',
147147
[LoopCount, FInvalidAddresses[LoopCount]]));
148148
end;
149149

@@ -156,7 +156,7 @@ procedure TEmailValidationTest.TestInvalidAddressesZeroBased;
156156
for LoopCount := 0 to Length(FInvalidAddresses) - 1 do
157157
begin
158158
Assert.IsFalse(uEmailValidationZeroBased.TEmailValidator.Validate
159-
(FInvalidAddresses[LoopCount]), Format('Invalid Address %d: %s',
159+
(FInvalidAddresses[LoopCount], True), Format('Invalid Address %d: %s',
160160
[LoopCount, FInvalidAddresses[LoopCount]]));
161161
end;
162162

@@ -169,7 +169,7 @@ procedure TEmailValidationTest.TestValidInternationalAddressesOneBased;
169169
for LoopCount := 0 to Length(FValidInternationalAddresses) - 1 do
170170
begin
171171
Assert.IsTrue(uEmailValidation.TEmailValidator.Validate
172-
(FValidInternationalAddresses[LoopCount], True),
172+
(FValidInternationalAddresses[LoopCount], True, True),
173173
Format('Valid International Address %d: %s',
174174
[LoopCount, FValidInternationalAddresses[LoopCount]]));
175175
end;
@@ -183,7 +183,7 @@ procedure TEmailValidationTest.TestValidInternationalAddressesZeroBased;
183183
for LoopCount := 0 to Length(FValidInternationalAddresses) - 1 do
184184
begin
185185
Assert.IsTrue(uEmailValidationZeroBased.TEmailValidator.Validate
186-
(FValidInternationalAddresses[LoopCount], True),
186+
(FValidInternationalAddresses[LoopCount], True, True),
187187
Format('Valid International Address %d: %s',
188188
[LoopCount, FValidInternationalAddresses[LoopCount]]));
189189
end;

EmailValidatorOneBasedIndex/src/Main/uEmailValidation.pas

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ TEmailValidator = class
4848
class function SkipSubDomain(const Text: String; var Index: Integer;
4949
allowInternational: Boolean): Boolean; static;
5050
class function SkipDomain(const Text: String; var Index: Integer;
51-
allowInternational: Boolean): Boolean; static;
51+
allowTopLevelDomains, allowInternational: Boolean): Boolean; static;
5252
class function SkipQuoted(const Text: String; var Index: Integer;
5353
allowInternational: Boolean): Boolean; static;
5454
class function SkipWord(const Text: String; var Index: Integer;
@@ -71,12 +71,14 @@ TEmailValidator = class
7171
/// </remarks>
7272
/// <returns><c>true</c> if the email address is valid; otherwise <c>false</c>.</returns>
7373
/// <param name="Email">An email address.</param>
74+
/// <param name="allowTopLevelDomains"><value>true</value> if the validator should allow addresses at top-level domains; otherwise, <value>false</value>.</param>
7475
/// <param name="allowInternational"><value>true</value> if the validator should allow international characters; otherwise, <value>false</value>.</param>
7576
/// <exception cref="System.SysUtils.EArgumentNilException">
7677
/// <paramref name="Email"/> is <c>Empty</c>.
7778
/// </exception>
7879

7980
class function Validate(const Email: String;
81+
allowTopLevelDomains: Boolean = False;
8082
allowInternational: Boolean = False): Boolean; static;
8183

8284
end;
@@ -158,7 +160,8 @@ class function TEmailValidator.SkipSubDomain(const Text: String;
158160
end;
159161

160162
class function TEmailValidator.SkipDomain(const Text: String;
161-
var Index: Integer; allowInternational: Boolean): Boolean;
163+
var Index: Integer; allowTopLevelDomains, allowInternational
164+
: Boolean): Boolean;
162165

163166
begin
164167

@@ -167,21 +170,32 @@ class function TEmailValidator.SkipDomain(const Text: String;
167170
Result := False;
168171
Exit;
169172
end;
170-
while ((Index < Length(Text)) and ((Text[Index + 1]) = '.')) do
173+
if ((Index < Length(Text)) and ((Text[Index + 1]) = '.')) then
171174
begin
172-
Inc(Index);
173-
if (Index = Length(Text)) then
174-
begin
175-
Result := False;
176-
Exit;
177-
end;
178175

179-
if (not SkipSubDomain(Text, Index, allowInternational)) then
176+
while (Index < Length(Text)) and ((Text[Index + 1]) = '.') do
180177
begin
181-
Result := False;
182-
Exit;
178+
Inc(Index);
179+
if (Index = Length(Text)) then
180+
begin
181+
Result := False;
182+
Exit;
183+
end;
184+
185+
if (not SkipSubDomain(Text, Index, allowInternational)) then
186+
begin
187+
Result := False;
188+
Exit;
189+
end;
190+
183191
end;
184192

193+
end
194+
else if (not allowTopLevelDomains) then
195+
196+
begin
197+
Result := False;
198+
Exit;
185199
end;
186200

187201
Result := True;
@@ -408,6 +422,7 @@ class function TEmailValidator.SkipIPv6Literal(const Text: String;
408422
end;
409423

410424
class function TEmailValidator.Validate(const Email: String;
425+
allowTopLevelDomains: Boolean = False;
411426
allowInternational: Boolean = False): Boolean;
412427
var
413428
Index: Integer;
@@ -463,7 +478,8 @@ class function TEmailValidator.Validate(const Email: String;
463478
if (Email[Index + 1] <> '[') then
464479
begin
465480
// domain
466-
if (not SkipDomain(Email, Index, allowInternational)) then
481+
if (not SkipDomain(Email, Index, allowTopLevelDomains, allowInternational))
482+
then
467483
begin
468484
Result := False;
469485
Exit;

EmailValidatorZeroBasedIndex/src/Main/uEmailValidationZeroBased.pas

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ TEmailValidator = class
2929
class function SkipSubDomain(const Text: String; var Index: Integer;
3030
allowInternational: Boolean): Boolean; static;
3131
class function SkipDomain(const Text: String; var Index: Integer;
32-
allowInternational: Boolean): Boolean; static;
32+
allowTopLevelDomains, allowInternational: Boolean): Boolean; static;
3333
class function SkipQuoted(const Text: String; var Index: Integer;
3434
allowInternational: Boolean): Boolean; static;
3535
class function SkipWord(const Text: String; var Index: Integer;
@@ -52,13 +52,15 @@ TEmailValidator = class
5252
/// </remarks>
5353
/// <returns><c>true</c> if the email address is valid; otherwise <c>false</c>.</returns>
5454
/// <param name="Email">An email address.</param>
55+
/// <param name="allowTopLevelDomains"><value>true</value> if the validator should allow addresses at top-level domains; otherwise, <value>false</value>.</param>
5556
/// <param name="allowInternational"><value>true</value> if the validator should allow international characters; otherwise, <value>false</value>.</param>
5657
/// <exception cref="System.SysUtils.EArgumentNilException">
5758
/// <paramref name="Email"/> is <c>Empty</c>.
5859
/// </exception>
5960

60-
class function Validate(const Email: String; allowInternational: Boolean = False)
61-
: Boolean; static;
61+
class function Validate(const Email: String;
62+
allowTopLevelDomains: Boolean = False;
63+
allowInternational: Boolean = False): Boolean; static;
6264

6365
end;
6466

@@ -106,8 +108,8 @@ class function TEmailValidator.SkipAtom(const Text: String; var Index: Integer;
106108
Result := Index > startIndex;
107109
end;
108110

109-
class function TEmailValidator.SkipSubDomain(const Text: String; var Index: Integer;
110-
allowInternational: Boolean): Boolean;
111+
class function TEmailValidator.SkipSubDomain(const Text: String;
112+
var Index: Integer; allowInternational: Boolean): Boolean;
111113
var
112114
startIndex: Integer;
113115

@@ -128,8 +130,9 @@ class function TEmailValidator.SkipSubDomain(const Text: String; var Index: Inte
128130
Result := ((Index - startIndex) < 64) and (Text.Chars[Index - 1] <> '-');
129131
end;
130132

131-
class function TEmailValidator.SkipDomain(const Text: String; var Index: Integer;
132-
allowInternational: Boolean): Boolean;
133+
class function TEmailValidator.SkipDomain(const Text: String;
134+
var Index: Integer; allowTopLevelDomains, allowInternational
135+
: Boolean): Boolean;
133136

134137
begin
135138

@@ -138,28 +141,39 @@ class function TEmailValidator.SkipDomain(const Text: String; var Index: Integer
138141
Result := False;
139142
Exit;
140143
end;
141-
while ((Index < Text.Length) and ((Text.Chars[Index]) = '.')) do
144+
145+
if ((Index < Text.Length) and ((Text.Chars[Index]) = '.')) then
142146
begin
143-
Inc(Index);
144-
if (Index = Text.Length) then
145-
begin
146-
Result := False;
147-
Exit;
148-
end;
149147

150-
if (not SkipSubDomain(Text, Index, allowInternational)) then
148+
while ((Index < Text.Length) and ((Text.Chars[Index]) = '.')) do
151149
begin
152-
Result := False;
153-
Exit;
150+
Inc(Index);
151+
if (Index = Text.Length) then
152+
begin
153+
Result := False;
154+
Exit;
155+
end;
156+
157+
if (not SkipSubDomain(Text, Index, allowInternational)) then
158+
begin
159+
Result := False;
160+
Exit;
161+
end;
154162
end;
155163

164+
end
165+
else if (not allowTopLevelDomains) then
166+
167+
begin
168+
Result := False;
169+
Exit;
156170
end;
157171

158172
Result := True;
159173
end;
160174

161-
class function TEmailValidator.SkipQuoted(const Text: String; var Index: Integer;
162-
allowInternational: Boolean): Boolean;
175+
class function TEmailValidator.SkipQuoted(const Text: String;
176+
var Index: Integer; allowInternational: Boolean): Boolean;
163177
var
164178
Escaped: Boolean;
165179

@@ -378,6 +392,7 @@ class function TEmailValidator.SkipIPv6Literal(const Text: String;
378392
end;
379393

380394
class function TEmailValidator.Validate(const Email: String;
395+
allowTopLevelDomains: Boolean = False;
381396
allowInternational: Boolean = False): Boolean;
382397
var
383398
Index: Integer;
@@ -433,7 +448,8 @@ class function TEmailValidator.Validate(const Email: String;
433448
if (Email.Chars[Index] <> '[') then
434449
begin
435450
// domain
436-
if (not SkipDomain(Email, Index, allowInternational)) then
451+
if (not SkipDomain(Email, Index, allowTopLevelDomains, allowInternational))
452+
then
437453
begin
438454
Result := False;
439455
Exit;

0 commit comments

Comments
 (0)