Skip to content

Commit d997630

Browse files
committed
feat: create validator for IPv4 addresses
Closes #97
1 parent 3dc92b1 commit d997630

File tree

6 files changed

+156
-1
lines changed

6 files changed

+156
-1
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ and this project adheres to [Dart Package Versioning](https://dart.dev/tools/pub
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- IPv4 and ReqIPv4 classes to validate both optional and mandatory IPv4 form
13+
fields — [97](https://github.com/dartoos-dev/formdator/issues/97).
14+
1015
## [0.12.2] - 2021-12-15
1116

1217
### Fixed

lib/net.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
/// Internet related validators.
22
///
3-
/// E.g. email, ipv4, ipv6, mac, url.
3+
/// E.g. Email, IPv4, IPv6, MacAddress, Url.
44
library net;
55

66
export 'src/net/email.dart';
7+
export 'src/net/ipv4.dart';
78
export 'src/net/req_email.dart';
9+
export 'src/net/req_ipv4.dart';

lib/src/net/ipv4.dart

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import 'package:formdator/formdator.dart';
2+
3+
/// Validator of optional IP (version 4) addresses.
4+
///
5+
/// Blank field - null value - is a valid input!
6+
///
7+
/// If the IP address is required, see [ReqIPv4] or [Req].
8+
///
9+
/// It uses the "Dot-decimal notation", which consists of four octets of the
10+
/// address expressed individually in decimal numbers and separated by periods.
11+
/// Examples of valid input:
12+
///
13+
/// - 192.0.2.235
14+
/// - 172.16.254.1
15+
/// - 127.0.0.1
16+
/// - 10.0.0.1
17+
/// - 0.0.0.0
18+
///
19+
/// See also:
20+
/// - [Dot Decimal Notation](https://en.wikipedia.org/wiki/Dot-decimal_notation)
21+
class IPv4 {
22+
/// Validates IPv4 addresses using a regular expression that is suitable for
23+
/// manually entered IP's. Examples:
24+
///
25+
///
26+
/// If the ipv4 field is mandatory, see [ReqIPv4] or [Req].
27+
///
28+
/// [mal] the error message in case of a malformed IP address; if omitted, the
29+
/// default message will be 'malformed IP address'.
30+
IPv4({String? mal})
31+
: _ipv4Val = ((String? ipv4) {
32+
return (ipv4 == null || _matcher.hasMatch(ipv4))
33+
? null
34+
: mal ?? 'malformed IP address';
35+
});
36+
37+
// email validation logic.
38+
final ValStr _ipv4Val;
39+
40+
// lazy loading (on-demand) initialization.
41+
static late final RegExp _matcher = _ipv4Pattern();
42+
43+
/// a suitable pattern for IPv4 addresses.
44+
static RegExp _ipv4Pattern() {
45+
return RegExp(
46+
r'^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$',
47+
);
48+
}
49+
50+
/// Valid - returns null - if [ipv4] is either a well-formed IPV4 address or
51+
/// null.
52+
String? call(String? ipv4) => _ipv4Val(ipv4);
53+
}

lib/src/net/req_ipv4.dart

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import '../core/pair.dart';
2+
import '../core/req.dart';
3+
import '../type.dart';
4+
5+
import 'ipv4.dart';
6+
7+
/// Convenience validator for required IPv4 addresses.
8+
///
9+
/// It is the composition between the validators [Req] and [IPv4].
10+
class ReqIPv4 {
11+
/// Non-blank and well-formed IPv4 values.
12+
///
13+
/// [blank] the error message in case of an IPv4 address left blank; if
14+
/// omitted, the default message will be 'required IP'.
15+
/// [mal] the error message in case of a malformed IP address; if omitted, the
16+
/// default message will be 'malformed IP address'.
17+
ReqIPv4({String? blank, String? mal})
18+
: this._set(IPv4(mal: mal), blank: blank);
19+
20+
/// Helper ctor.
21+
ReqIPv4._set(IPv4 ip, {String? blank})
22+
: _reqIPv4 = Pair.str2(Req(blank: blank ?? 'required IP address'), ip);
23+
24+
// the required IPv4 logic.
25+
final ValObj _reqIPv4;
26+
27+
/// Valid — returns null — if [ipv4] is a non-blank well-formed IPv4;
28+
/// otherwise, returns the blank error message if [ipv4] is null, or the
29+
/// malformed error message if [ipv4] is malformed.
30+
String? call(String? ipv4) => _reqIPv4(ipv4);
31+
}

test/net/ipv4_test.dart

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import 'package:formdator/formdator.dart';
2+
import 'package:test/test.dart';
3+
4+
/// Most of the test cases were taken from:
5+
/// - [valid-ipv4-addresses](https://en.wikipedia.org/wiki/ipv4_address#Valid_ipv4_addresses)
6+
void main() {
7+
group('IPv4', () {
8+
const error = 'malformed IP';
9+
final ipv4 = IPv4(mal: error);
10+
test('valid values:', () {
11+
expect(ipv4('0.0.0.0'), null);
12+
expect(ipv4('1.1.1.10'), null);
13+
expect(ipv4('10.0.0.1'), null);
14+
expect(ipv4('10.10.10.10'), null);
15+
expect(ipv4('127.0.0.1'), null);
16+
expect(ipv4('192.0.2.235'), null);
17+
expect(ipv4('192.168.18.1'), null);
18+
expect(ipv4('172.16.254.1'), null);
19+
expect(ipv4('189.47.19.149'), null);
20+
expect(ipv4('255.255.255.255'), null);
21+
});
22+
test('invalid values', () {
23+
expect(ipv4('1'), error);
24+
expect(ipv4('10.10'), error);
25+
expect(ipv4('10.10.10.'), error);
26+
expect(ipv4('00.0.0.0'), error);
27+
expect(ipv4('0.00.0.0'), error);
28+
expect(ipv4('0.0.00.0'), error);
29+
expect(ipv4('0.0.0.00'), error);
30+
expect(ipv4('0.0.0.0.'), error);
31+
expect(ipv4('010.0.0.1'), error);
32+
expect(ipv4('127.00.0.1'), error);
33+
expect(ipv4('000.021.01.0'), error);
34+
expect(ipv4('255.255.255.256'), error);
35+
expect(ipv4('256.255.255.255'), error);
36+
expect(ipv4('033.033.33.033'), error);
37+
expect(ipv4('192.168.000.1'), error);
38+
expect(ipv4('999.999.999.999'), error);
39+
});
40+
});
41+
}

test/net/req_ipv4_test.dart

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import 'package:formdator/formdator.dart';
2+
import 'package:test/test.dart';
3+
4+
void main() {
5+
group('ReqIPv4', () {
6+
const blank = 'required IP address';
7+
const mal = 'malformed IP address';
8+
final reqIPv4 = ReqIPv4(blank: blank, mal: mal);
9+
test('null - blank', () {
10+
expect(reqIPv4(null), blank);
11+
});
12+
test('empty - blank', () {
13+
expect(reqIPv4(''), blank);
14+
});
15+
test('invalid IPv4', () {
16+
const invalid = '10.10.10.256';
17+
expect(reqIPv4(invalid), mal);
18+
});
19+
test('valid IPv4', () {
20+
expect(reqIPv4('10.0.1.1'), null);
21+
});
22+
});
23+
}

0 commit comments

Comments
 (0)