Skip to content

Commit 66e11fd

Browse files
authored
Add tests for named arguments anywhere in constant (#2892)
1 parent f9cfab1 commit 66e11fd

File tree

4 files changed

+225
-64
lines changed

4 files changed

+225
-64
lines changed

pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ dev_dependencies:
3737
http: ^0.13.3
3838
lints: ^1.0.1
3939
test: ^1.19.0
40+
test_descriptor: ^2.0.0
4041

4142
executables:
4243
dartdoc: null

test/constant_values_test.dart

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:async/async.dart';
6+
import 'package:dartdoc/src/model/model.dart';
7+
import 'package:dartdoc/src/package_config_provider.dart';
8+
import 'package:dartdoc/src/package_meta.dart';
9+
import 'package:pub_semver/pub_semver.dart';
10+
import 'package:test/test.dart';
11+
import 'package:test_descriptor/test_descriptor.dart' as d;
12+
13+
import 'src/utils.dart' as utils;
14+
15+
void main() {
16+
// We can not use ExperimentalFeature.releaseVersion or even
17+
// ExperimentalFeature.experimentalReleaseVersion as these are set to null
18+
// even when partial analyzer implementations are available, and are often
19+
// set too high after release.
20+
final constructorTearoffsAllowed =
21+
VersionRange(min: Version.parse('2.15.0-0'), includeMin: true);
22+
23+
// We can not use ExperimentalFeature.releaseVersion or even
24+
// ExperimentalFeature.experimentalReleaseVersion as these are set to null
25+
// even when partial analyzer implementations are available.
26+
final namedArgumentsAnywhereAllowed =
27+
VersionRange(min: Version.parse('2.17.0-0'), includeMin: true);
28+
29+
group('constructor-tearoffs', () {
30+
late Library library;
31+
const libraryName = 'constructor_tearoffs';
32+
33+
final packageGraphMemo = AsyncMemoizer<PackageGraph>();
34+
Future<PackageGraph> bootstrapPackageGraph() =>
35+
packageGraphMemo.runOnce(() => utils.bootBasicPackage(
36+
d.dir(libraryName).io.path,
37+
pubPackageMetaProvider,
38+
PhysicalPackageConfigProvider(),
39+
additionalArguments: ['--no-link-to-remote']));
40+
41+
setUp(() async {
42+
await d.dir(libraryName, [
43+
d.file('pubspec.yaml', '''
44+
name: constructor_tearoffs
45+
version: 0.0.1
46+
environment:
47+
sdk: '>=2.15.0-0 <3.0.0'
48+
'''),
49+
d.file('analysis_options.yaml', '''
50+
analyzer:
51+
enable-experiment:
52+
- constructor-tearoffs
53+
'''),
54+
d.dir('lib', [
55+
d.file('lib.dart', '''
56+
library $libraryName;
57+
58+
class F<T> {
59+
F();
60+
61+
F.alternative();
62+
}
63+
64+
typedef Ft<T> = F<T>;
65+
66+
void func() {}
67+
void funcTypeParams<T extends String, U extends num>(
68+
T something, U different) {}
69+
70+
const aFunc = func;
71+
const aFuncParams = funcTypeParams;
72+
const aFuncWithArgs = funcTypeParams<String, int>;
73+
const aTearOffUnnamedConstructor = F.new;
74+
const aTearOffUnnamedConstructorArgs = F<String>.new;
75+
const aTearOffUnnamedConstructorTypedef = Fstring.new;
76+
const aTearOffUnnamedConstructorArgsTypedef = Ft<String>.new;
77+
const aTearOffNamedConstructor = F.alternative;
78+
const aTearOffNamedConstructorArgs = F<int>.alternative;
79+
'''),
80+
]),
81+
]).create();
82+
83+
library = (await bootstrapPackageGraph())
84+
.libraries
85+
.firstWhere((l) => l.name == libraryName);
86+
});
87+
88+
test('non-generic function reference', () {
89+
var aFuncConstant =
90+
library.constants.firstWhere((c) => c.name == 'aFunc');
91+
expect(aFuncConstant.constantValue, equals('func'));
92+
});
93+
94+
test('generic function reference', () {
95+
var aFuncParamsConstant =
96+
library.constants.firstWhere((c) => c.name == 'aFuncParams');
97+
expect(aFuncParamsConstant.constantValue, equals('funcTypeParams'));
98+
});
99+
100+
test('generic function reference w/ type args', () {
101+
var aFuncWithArgs =
102+
library.constants.firstWhere((c) => c.name == 'aFuncWithArgs');
103+
expect(aFuncWithArgs.constantValue,
104+
equals('funcTypeParams&lt;String, int&gt;'));
105+
});
106+
107+
test('named constructor reference', () {
108+
var aTearOffNamedConstructor = library.constants
109+
.firstWhere((c) => c.name == 'aTearOffNamedConstructor');
110+
expect(aTearOffNamedConstructor.constantValue, equals('F.alternative'));
111+
});
112+
113+
test('named constructor reference w/ type args', () {
114+
var aTearOffNamedConstructorArgs = library.constants
115+
.firstWhere((c) => c.name == 'aTearOffNamedConstructorArgs');
116+
expect(aTearOffNamedConstructorArgs.constantValue,
117+
equals('F&lt;int&gt;.alternative'));
118+
});
119+
120+
test('unnamed constructor reference', () {
121+
var aTearOffUnnamedConstructor = library.constants
122+
.firstWhere((c) => c.name == 'aTearOffUnnamedConstructor');
123+
expect(aTearOffUnnamedConstructor.constantValue, equals('F.new'));
124+
});
125+
126+
test('unnamed constructor reference w/ type args', () {
127+
var aTearOffUnnamedConstructorArgs = library.constants
128+
.firstWhere((c) => c.name == 'aTearOffUnnamedConstructorArgs');
129+
expect(aTearOffUnnamedConstructorArgs.constantValue,
130+
equals('F&lt;String&gt;.new'));
131+
});
132+
133+
test('unnamed typedef constructor reference', () {
134+
var aTearOffUnnamedConstructorTypedef = library.constants
135+
.firstWhere((c) => c.name == 'aTearOffUnnamedConstructorTypedef');
136+
expect(aTearOffUnnamedConstructorTypedef.constantValue,
137+
equals('Fstring.new'));
138+
});
139+
140+
test('unnamed typedef constructor reference w/ type args', () {
141+
var aTearOffUnnamedConstructorArgsTypedef = library.constants
142+
.firstWhere((c) => c.name == 'aTearOffUnnamedConstructorArgsTypedef');
143+
expect(aTearOffUnnamedConstructorArgsTypedef.constantValue,
144+
equals('Ft&lt;String&gt;.new'));
145+
});
146+
147+
test('constant rendering', () {}, skip: true);
148+
}, skip: !constructorTearoffsAllowed.allows(utils.platformVersion));
149+
150+
group('named-arguments-anywhere', () {
151+
late Library library;
152+
const placeholder = '%%__HTMLBASE_dartdoc_internal__%%';
153+
const libraryName = 'named_arguments_anywhere';
154+
const linkPrefix = '$placeholder$libraryName';
155+
156+
final _testPackageGraphExperimentsMemo = AsyncMemoizer<PackageGraph>();
157+
Future<PackageGraph> bootstrapPackageGraph() =>
158+
_testPackageGraphExperimentsMemo.runOnce(() => utils.bootBasicPackage(
159+
d.dir(libraryName).io.path,
160+
pubPackageMetaProvider,
161+
PhysicalPackageConfigProvider(),
162+
additionalArguments: ['--no-link-to-remote']));
163+
164+
setUp(() async {
165+
await d.dir(libraryName, [
166+
d.file('pubspec.yaml', '''
167+
name: named_arguments_anywhere
168+
version: 0.0.1
169+
environment:
170+
sdk: '>=2.17.0-0 <3.0.0'
171+
'''),
172+
d.file('analysis_options.yaml', '''
173+
analyzer:
174+
enable-experiment:
175+
- named-arguments-anywhere
176+
'''),
177+
d.dir('lib', [
178+
d.file('lib.dart', '''
179+
library $libraryName;
180+
181+
class C {
182+
const C(int a, int b, {required int c, required int d});
183+
}
184+
185+
const p = C(1, 2, c: 3, d: 4);
186+
187+
const q = C(1, c: 2, 3, d: 4);
188+
189+
const r = C(c: 1, d: 2, 3, 4);
190+
'''),
191+
]),
192+
]).create();
193+
194+
library = (await bootstrapPackageGraph())
195+
.libraries
196+
.firstWhere((l) => l.name == libraryName);
197+
});
198+
199+
test('named parameters in a const invocation value can be specified last',
200+
() async {
201+
var pConst = library.constants.firstWhere((c) => c.name == 'p');
202+
203+
expect(pConst.constantValue,
204+
equals('<a href="$linkPrefix/C/C.html">C</a>(1, 2, c: 3, d: 4)'));
205+
});
206+
207+
test(
208+
'named parameters in a const invocation value can be specified anywhere',
209+
() async {
210+
var qConst = library.constants.firstWhere((c) => c.name == 'q');
211+
212+
expect(qConst.constantValue,
213+
equals('<a href="$linkPrefix/C/C.html">C</a>(1, c: 2, 3, d: 4)'));
214+
});
215+
216+
test('named parameters in a const invocation value can be specified first',
217+
() async {
218+
var rConst = library.constants.firstWhere((c) => c.name == 'r');
219+
220+
expect(rConst.constantValue,
221+
equals('<a href="$linkPrefix/C/C.html">C</a>(c: 1, d: 2, 3, 4)'));
222+
});
223+
}, skip: !namedArgumentsAnywhereAllowed.allows(utils.platformVersion));
224+
}

test/end2end/model_special_cases_test.dart

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -220,53 +220,6 @@ void main() {
220220
expect(referenceLookup(A, 'new'), equals(MatchingLinkResult(null)));
221221
expect(referenceLookup(At, 'new'), equals(MatchingLinkResult(null)));
222222
});
223-
224-
test('constant rendering', () {
225-
TopLevelVariable aFunc,
226-
aFuncParams,
227-
aTearOffDefaultConstructor,
228-
aTearOffNonDefaultConstructor,
229-
aTearOffNonDefaultConstructorInt,
230-
aTearOffDefaultConstructorArgs;
231-
TopLevelVariable aTearOffDefaultConstructorTypedef;
232-
aFunc =
233-
constructorTearoffs.constants.firstWhere((c) => c.name == 'aFunc');
234-
aFuncParams = constructorTearoffs.constants
235-
.firstWhere((c) => c.name == 'aFuncParams');
236-
aTearOffDefaultConstructor = constructorTearoffs.constants
237-
.firstWhere((c) => c.name == 'aTearOffDefaultConstructor');
238-
aTearOffNonDefaultConstructor = constructorTearoffs.constants
239-
.firstWhere((c) => c.name == 'aTearOffNonDefaultConstructor');
240-
aTearOffNonDefaultConstructorInt = constructorTearoffs.constants
241-
.firstWhere((c) => c.name == 'aTearOffNonDefaultConstructorInt');
242-
aTearOffDefaultConstructorArgs = constructorTearoffs.constants
243-
.firstWhere((c) => c.name == 'aTearOffDefaultConstructorArgs');
244-
aTearOffDefaultConstructorTypedef = constructorTearoffs.constants
245-
.firstWhere((c) => c.name == 'aTearOffDefaultConstructorTypedef');
246-
247-
expect(aFunc.constantValue, equals('func'));
248-
expect(aFuncParams.constantValue, equals('funcTypeParams'));
249-
var aFuncWithArgs = constructorTearoffs.constants
250-
.firstWhere((c) => c.name == 'aFuncWithArgs');
251-
expect(aFuncWithArgs.constantValue,
252-
equals('funcTypeParams&lt;String, int&gt;'));
253-
254-
expect(aTearOffDefaultConstructor.constantValue, equals('F.new'));
255-
expect(aTearOffNonDefaultConstructor.constantValue,
256-
equals('F.alternative'));
257-
expect(aTearOffNonDefaultConstructorInt.constantValue,
258-
equals('F&lt;int&gt;.alternative'));
259-
expect(aTearOffDefaultConstructorArgs.constantValue,
260-
equals('F&lt;String&gt;.new'));
261-
262-
expect(aTearOffDefaultConstructorTypedef.constantValue,
263-
equals('Fstring.new'));
264-
var aTearOffDefaultConstructorArgsTypedef =
265-
constructorTearoffs.constants.firstWhere(
266-
(c) => c.name == 'aTearOffDefaultConstructorArgsTypedef');
267-
expect(aTearOffDefaultConstructorArgsTypedef.constantValue,
268-
equals('Ft&lt;String&gt;.new'));
269-
});
270223
}, skip: !_constructorTearoffsAllowed.allows(utils.platformVersion));
271224
});
272225

testing/test_package_experiments/lib/constructor_tearoffs.dart

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -61,20 +61,3 @@ typedef NotAClass = Function;
6161

6262
/// Mixins don't have constructors either, so disallow `M.new`.
6363
mixin M<T> on C {}
64-
65-
void func() {}
66-
void funcTypeParams<T extends String, U extends num>(
67-
T something, U different) {}
68-
69-
const aFunc = func;
70-
const aFuncParams = funcTypeParams;
71-
const aFuncWithArgs = funcTypeParams<String, int>;
72-
73-
const aTearOffDefaultConstructor = F.new;
74-
const aTearOffNonDefaultConstructor = F.alternative;
75-
const aTearOffNonDefaultConstructorInt = F<int>.alternative;
76-
const aTearOffDefaultConstructorArgs = F<String>.new;
77-
78-
const aTearOffDefaultConstructorTypedef = Fstring.new;
79-
80-
const aTearOffDefaultConstructorArgsTypedef = Ft<String>.new;

0 commit comments

Comments
 (0)