Skip to content

Commit 9765c2a

Browse files
authored
[package_config] Implement relational operators for LanguageVersion (#2016)
1 parent b51f39d commit 9765c2a

File tree

5 files changed

+179
-4
lines changed

5 files changed

+179
-4
lines changed

pkgs/package_config/CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
## 2.1.2-wip
1+
## 2.2.0-wip
2+
3+
- Add relational operators to `LanguageVersion` with extension methods
4+
exported under `LanguageVersionRelationalOperators`.
25

36
- Include correct parameter names in errors when validating
47
the `major` and `minor` versions in the `LanguageVersion.new` constructor.

pkgs/package_config/lib/package_config_types.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,9 @@ library;
1414

1515
export 'src/errors.dart' show PackageConfigError;
1616
export 'src/package_config.dart'
17-
show InvalidLanguageVersion, LanguageVersion, Package, PackageConfig;
17+
show
18+
InvalidLanguageVersion,
19+
LanguageVersion,
20+
LanguageVersionRelationalOperators,
21+
Package,
22+
PackageConfig;

pkgs/package_config/lib/src/package_config.dart

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ abstract class LanguageVersion implements Comparable<LanguageVersion> {
355355
/// Two language versions are considered equal if they have the
356356
/// same major and minor version numbers.
357357
///
358-
/// A language version is greater then another if the former's major version
358+
/// A language version is greater than another if the former's major version
359359
/// is greater than the latter's major version, or if they have
360360
/// the same major version and the former's minor version is greater than
361361
/// the latter's.
@@ -406,3 +406,90 @@ abstract class InvalidLanguageVersion implements LanguageVersion {
406406
@override
407407
String toString();
408408
}
409+
410+
/// Relational operators for [LanguageVersion] that
411+
/// compare valid versions with [LanguageVersion.compareTo].
412+
///
413+
/// If either operand is an [InvalidLanguageVersion], a [StateError] is thrown.
414+
/// Versions should be verified as valid after parsing and before using them.
415+
extension LanguageVersionRelationalOperators on LanguageVersion {
416+
/// Whether this language version is less than [other].
417+
///
418+
/// If either version being compared is an [InvalidLanguageVersion],
419+
/// a [StateError] is thrown. Verify versions are valid before comparing them.
420+
///
421+
/// For details on how valid language versions are compared,
422+
/// check out [LanguageVersion.compareTo].
423+
bool operator <(LanguageVersion other) {
424+
// Throw an error if comparing as or with an invalid language version.
425+
if (this is InvalidLanguageVersion) {
426+
_throwThisInvalid();
427+
} else if (other is InvalidLanguageVersion) {
428+
_throwOtherInvalid();
429+
}
430+
431+
return compareTo(other) < 0;
432+
}
433+
434+
/// Whether this language version is less than or equal to [other].
435+
///
436+
/// If either version being compared is an [InvalidLanguageVersion],
437+
/// a [StateError] is thrown. Verify versions are valid before comparing them.
438+
///
439+
/// For details on how valid language versions are compared,
440+
/// check out [LanguageVersion.compareTo].
441+
bool operator <=(LanguageVersion other) {
442+
// Throw an error if comparing as or with an invalid language version.
443+
if (this is InvalidLanguageVersion) {
444+
_throwThisInvalid();
445+
} else if (other is InvalidLanguageVersion) {
446+
_throwOtherInvalid();
447+
}
448+
449+
return compareTo(other) <= 0;
450+
}
451+
452+
/// Whether this language version is greater than [other].
453+
///
454+
/// If either version being compared is an [InvalidLanguageVersion],
455+
/// a [StateError] is thrown. Verify versions are valid before comparing them.
456+
///
457+
/// For details on how valid language versions are compared,
458+
/// check out [LanguageVersion.compareTo].
459+
bool operator >(LanguageVersion other) {
460+
// Throw an error if comparing as or with an invalid language version.
461+
if (this is InvalidLanguageVersion) {
462+
_throwThisInvalid();
463+
} else if (other is InvalidLanguageVersion) {
464+
_throwOtherInvalid();
465+
}
466+
467+
return compareTo(other) > 0;
468+
}
469+
470+
/// Whether this language version is greater than or equal to [other].
471+
///
472+
/// If either version being compared is an [InvalidLanguageVersion],
473+
/// a [StateError] is thrown. Verify versions are valid before comparing them.
474+
///
475+
/// For details on how valid language versions are compared,
476+
/// check out [LanguageVersion.compareTo].
477+
bool operator >=(LanguageVersion other) {
478+
// Throw an error if comparing as or with an invalid language version.
479+
if (this is InvalidLanguageVersion) {
480+
_throwThisInvalid();
481+
} else if (other is InvalidLanguageVersion) {
482+
_throwOtherInvalid();
483+
}
484+
485+
return compareTo(other) >= 0;
486+
}
487+
488+
static Never _throwThisInvalid() => throw StateError(
489+
'Can\'t compare an invalid language version to another language version. '
490+
'Verify language versions are valid after parsing.');
491+
492+
static Never _throwOtherInvalid() => throw StateError(
493+
'Can\'t compare a language version to an invalid language version. '
494+
'Verify language versions are valid after parsing.');
495+
}

pkgs/package_config/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: package_config
2-
version: 2.1.2-wip
2+
version: 2.2.0-wip
33
description: Support for reading and writing Dart Package Configuration files.
44
repository: https://github.com/dart-lang/tools/tree/main/pkgs/package_config
55
issue_tracker: https://github.com/dart-lang/tools/labels/package%3Apackage_config

pkgs/package_config/test/package_config_impl_test.dart

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,86 @@ void main() {
6969
failParse('WhiteSpace 2', '1 .1');
7070
failParse('WhiteSpace 3', '1. 1');
7171
failParse('WhiteSpace 4', '1.1 ');
72+
73+
test('compareTo valid', () {
74+
var version = LanguageVersion(3, 5);
75+
76+
for (var (otherVersion, matcher) in [
77+
(version, isZero), // Identical.
78+
(LanguageVersion(3, 5), isZero), // Same major, same minor.
79+
(LanguageVersion(3, 4), isPositive), // Same major, lower minor.
80+
(LanguageVersion(3, 6), isNegative), // Same major, greater minor.
81+
(LanguageVersion(2, 5), isPositive), // Lower major, same minor.
82+
(LanguageVersion(2, 4), isPositive), // Lower major, lower minor.
83+
(LanguageVersion(2, 6), isPositive), // Lower major, greater minor.
84+
(LanguageVersion(4, 5), isNegative), // Greater major, same minor.
85+
(LanguageVersion(4, 4), isNegative), // Greater major, lower minor.
86+
(LanguageVersion(4, 6), isNegative), // Greater major, greater minor.
87+
]) {
88+
expect(version.compareTo(otherVersion), matcher);
89+
}
90+
});
91+
92+
test('compareTo invalid', () {
93+
var validVersion = LanguageVersion(3, 5);
94+
var invalidVersion = LanguageVersion.parse('', onError: (_) {});
95+
96+
expect(validVersion.compareTo(invalidVersion), isPositive);
97+
expect(invalidVersion.compareTo(validVersion), isNegative);
98+
});
99+
100+
test('relational valid', () {
101+
/// Test that the relational comparisons between two valid versions
102+
/// match the results of `compareTo`.
103+
void testComparisons(
104+
LanguageVersion version, LanguageVersion otherVersion) {
105+
expect(version == otherVersion, version.compareTo(otherVersion) == 0);
106+
107+
expect(version < otherVersion, version.compareTo(otherVersion) < 0);
108+
expect(version <= otherVersion, version.compareTo(otherVersion) <= 0);
109+
110+
expect(version > otherVersion, version.compareTo(otherVersion) > 0);
111+
expect(version >= otherVersion, version.compareTo(otherVersion) >= 0);
112+
}
113+
114+
var version = LanguageVersion(3, 5);
115+
116+
// Check relational comparisons of a version to itself.
117+
testComparisons(version, version);
118+
119+
// Check relational comparisons of a version to versions with all
120+
// possible combinations of minor and major versions that are
121+
// the same, lower, and greater.
122+
for (final major in [2, 3, 4]) {
123+
for (final minor in [4, 5, 6]) {
124+
testComparisons(version, LanguageVersion(major, minor));
125+
}
126+
}
127+
});
128+
129+
test('relational invalid', () {
130+
void testComparisonsWithInvalid(
131+
LanguageVersion version,
132+
LanguageVersion otherVersion,
133+
) {
134+
expect(version == otherVersion, identical(version, otherVersion));
135+
136+
expect(() => version < otherVersion, throwsA(isA<StateError>()));
137+
expect(() => version <= otherVersion, throwsA(isA<StateError>()));
138+
139+
expect(() => version > otherVersion, throwsA(isA<StateError>()));
140+
expect(() => version >= otherVersion, throwsA(isA<StateError>()));
141+
}
142+
143+
var validVersion = LanguageVersion(3, 5);
144+
var invalidVersion = LanguageVersion.parse('', onError: (_) {});
145+
var differentInvalidVersion = LanguageVersion.parse('-', onError: (_) {});
146+
147+
testComparisonsWithInvalid(validVersion, invalidVersion);
148+
testComparisonsWithInvalid(invalidVersion, validVersion);
149+
testComparisonsWithInvalid(invalidVersion, invalidVersion);
150+
testComparisonsWithInvalid(invalidVersion, differentInvalidVersion);
151+
});
72152
});
73153

74154
group('Package', () {

0 commit comments

Comments
 (0)