Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate some linkedName tests for types to be unit tests. #4007

Merged
merged 1 commit into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions test/dartdoc_test_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,12 @@ abstract class DartdocTestBase {

String get linkPrefix => '$placeholder$libraryName';

String get dartAsyncUrlPrefix =>
'https://api.dart.dev/stable/3.2.0/dart-async';

String get dartSdkUrlPrefix => 'https://api.dart.dev/stable/3.2.0';
String get dartAsyncUrlPrefix => '$dartSdkUrlPrefix/dart-async';

String get dartCoreUrlPrefix => '$dartSdkUrlPrefix/dart-core';

String get dartSdkUrlPrefix => 'https://api.dart.dev/stable/3.2.0';

String get sdkConstraint => '>=3.7.0 <4.0.0';

/// A mapping of pub dependency names to the paths.
Expand Down
104 changes: 1 addition & 103 deletions test/end2end/model_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1890,7 +1890,7 @@ void main() async {
});

test('correctly finds all the classes', () {
expect(classes, hasLength(37));
expect(classes, hasLength(34));
});

test('abstract', () {
Expand Down Expand Up @@ -3085,108 +3085,6 @@ String? topLevelFunction(int param1, bool param2, Cool coolBeans,
});
});

group('Type expansion', () {
late final Class TemplatedInterface, ClassWithUnusualProperties;

setUpAll(() {
TemplatedInterface = exLibrary.classes.named('TemplatedInterface');
ClassWithUnusualProperties =
fakeLibrary.classes.named('ClassWithUnusualProperties');
});

test('setter that takes a function is correctly displayed', () {
var explicitSetter = ClassWithUnusualProperties.instanceFields
.singleWhere((f) => f.name == 'explicitSetter');
// TODO(jcollins-g): really, these shouldn't be called "parameters" in
// the span class.
expect(
explicitSetter.modelType.linkedName,
matches(RegExp(
r'dynamic Function<span class="signature">\(<span class="parameter" id="(f-)?param-bar"><span class="type-annotation">int</span> <span class="parameter-name">bar</span>, </span><span class="parameter" id="(f-)?param-baz"><span class="type-annotation"><a href="%%__HTMLBASE_dartdoc_internal__%%fake/Cool-class.html">Cool</a></span> <span class="parameter-name">baz</span>, </span><span class="parameter" id="(f-)?param-macTruck"><span class="type-annotation">List<span class="signature">&lt;<wbr><span class="type-parameter">int</span>&gt;</span></span> <span class="parameter-name">macTruck</span></span>\)</span>')));
});

test('parameterized type from inherited field is correctly displayed', () {
var aInheritedField = TemplatedInterface.inheritedFields
.singleWhere((f) => f.name == 'aInheritedField');
expect(
aInheritedField.modelType.linkedName,
'<a href="${htmlBasePlaceholder}ex/AnotherParameterizedClass-class.html">AnotherParameterizedClass</a>'
'<span class="signature">&lt;<wbr><span class="type-parameter">List<span class="signature">&lt;<wbr><span class="type-parameter">int</span>&gt;</span></span>&gt;</span>?');
});

test(
'parameterized type for return value from inherited explicit getter is correctly displayed',
() {
Accessor aInheritedGetter = TemplatedInterface.inheritedFields
.singleWhere((f) => f.name == 'aInheritedGetter')
.getter!;
expect(aInheritedGetter.modelType.returnType.linkedName,
'<a href="${htmlBasePlaceholder}ex/AnotherParameterizedClass-class.html">AnotherParameterizedClass</a><span class="signature">&lt;<wbr><span class="type-parameter">List<span class="signature">&lt;<wbr><span class="type-parameter">int</span>&gt;</span></span>&gt;</span>');
});

test(
'parameterized type for return value from inherited explicit setter is correctly displayed',
() {
Accessor aInheritedSetter = TemplatedInterface.inheritedFields
.singleWhere((f) => f.name == 'aInheritedSetter')
.setter!;
expect(aInheritedSetter.parameters.first.modelType.linkedName,
'<a href="${htmlBasePlaceholder}ex/AnotherParameterizedClass-class.html">AnotherParameterizedClass</a><span class="signature">&lt;<wbr><span class="type-parameter">List<span class="signature">&lt;<wbr><span class="type-parameter">int</span>&gt;</span></span>&gt;</span>');
expect(aInheritedSetter.enclosingCombo.modelType.linkedName,
'<a href="%%__HTMLBASE_dartdoc_internal__%%ex/AnotherParameterizedClass-class.html">AnotherParameterizedClass</a><span class="signature">&lt;<wbr><span class="type-parameter">List<span class="signature">&lt;<wbr><span class="type-parameter">int</span>&gt;</span></span>&gt;</span>');
});

test(
'parameterized type for return value from method is correctly displayed',
() {
var aMethodInterface = TemplatedInterface.instanceMethods
.singleWhere((m) => m.name == 'aMethodInterface');
expect(aMethodInterface.modelType.returnType.linkedName,
'<a href="${htmlBasePlaceholder}ex/AnotherParameterizedClass-class.html">AnotherParameterizedClass</a><span class="signature">&lt;<wbr><span class="type-parameter">List<span class="signature">&lt;<wbr><span class="type-parameter">int</span>&gt;</span></span>&gt;</span>');
});

test(
'parameterized type for return value from inherited method is correctly displayed',
() {
var aInheritedMethod = TemplatedInterface.instanceMethods
.singleWhere((m) => m.name == 'aInheritedMethod');
expect(aInheritedMethod.modelType.returnType.linkedName,
'<a href="${htmlBasePlaceholder}ex/AnotherParameterizedClass-class.html">AnotherParameterizedClass</a><span class="signature">&lt;<wbr><span class="type-parameter">List<span class="signature">&lt;<wbr><span class="type-parameter">int</span>&gt;</span></span>&gt;</span>');
});

test(
'parameterized type for return value containing a parameterized typedef is correctly displayed',
() {
var aTypedefReturningMethodInterface = TemplatedInterface.instanceMethods
.singleWhere((m) => m.name == 'aTypedefReturningMethodInterface');
expect(aTypedefReturningMethodInterface.modelType.returnType.linkedName,
'<a href="${htmlBasePlaceholder}ex/ParameterizedTypedef.html">ParameterizedTypedef</a><span class="signature">&lt;<wbr><span class="type-parameter">List<span class="signature">&lt;<wbr><span class="type-parameter">String</span>&gt;</span></span>&gt;</span>');
});

test(
'parameterized type for return value containing a parameterized typedef from inherited method is correctly displayed',
() {
var aInheritedTypedefReturningMethod = TemplatedInterface.instanceMethods
.singleWhere((m) => m.name == 'aInheritedTypedefReturningMethod');
expect(aInheritedTypedefReturningMethod.modelType.returnType.linkedName,
'<a href="${htmlBasePlaceholder}ex/ParameterizedTypedef.html">ParameterizedTypedef</a><span class="signature">&lt;<wbr><span class="type-parameter">List<span class="signature">&lt;<wbr><span class="type-parameter">int</span>&gt;</span></span>&gt;</span>');
});

test('parameterized types for inherited operator is correctly displayed',
() {
var aInheritedAdditionOperator = TemplatedInterface.inheritedOperators
.singleWhere((m) => m.name == 'operator +');
expect(aInheritedAdditionOperator.modelType.returnType.linkedName,
'<a href="${htmlBasePlaceholder}ex/ParameterizedClass-class.html">ParameterizedClass</a><span class="signature">&lt;<wbr><span class="type-parameter">List<span class="signature">&lt;<wbr><span class="type-parameter">int</span>&gt;</span></span>&gt;</span>');
expect(
ParameterRendererHtml()
.renderLinkedParams(aInheritedAdditionOperator.parameters),
'<span class="parameter" id="+-param-other"><span class="type-annotation"><a href="${htmlBasePlaceholder}ex/ParameterizedClass-class.html">ParameterizedClass</a><span class="signature">&lt;<wbr><span class="type-parameter">List<span class="signature">&lt;<wbr><span class="type-parameter">int</span>&gt;</span></span>&gt;</span></span> <span class="parameter-name">other</span></span>');
});

test('', () {});
});

group('Method', () {
late final Class classB,
klass,
Expand Down
1 change: 0 additions & 1 deletion test/parameters_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ void f(int _) {}
void test_formalParameter_generic_method() async {
var library = await bootPackageWithLibrary('''
class C {
C() {}
int one(int Function<T>(T)? f) {
return 1;
}
Expand Down
225 changes: 225 additions & 0 deletions test/types_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:dartdoc/src/model/model.dart';
import 'package:dartdoc/src/render/parameter_renderer.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';

import 'dartdoc_test_base.dart';
import 'src/utils.dart';

void main() {
defineReflectiveSuite(() {
defineReflectiveTests(TypesTest);
});
}

@reflectiveTest
class TypesTest extends DartdocTestBase {
@override
String get libraryName => 'types';

void test_setter_functionTypedParameter() async {
var library = await bootPackageWithLibrary('''
class C {
set f(p(int a, List<int> b)) {}
}
''');
var f = library.field('C', 'f');
expect(f.modelType.linkedName, matchesCompressed('''
dynamic Function
<span class="signature">\\(
<span class="parameter" id="p-param-a">
<span class="type-annotation">
<a href="$dartCoreUrlPrefix/int-class.html">int</a>
</span>
<span class="parameter-name">a</span>,
</span>
<span class="parameter" id="p-param-b">
<span class="type-annotation">
<a href="$dartCoreUrlPrefix/List-class.html">List</a>
<span class="signature">&lt;<wbr>
<span class="type-parameter">
<a href="$dartCoreUrlPrefix/int-class.html">int</a>
</span>&gt;
</span>
</span>
<span class="parameter-name">b</span>
</span>\\)
</span>
'''));
}

void test_field_substitutedTypes() async {
var library = await bootPackageWithLibrary('''
class C<T> {
List<T>? f;
}
class D extends C<int> {}
''');
var f = library.field('D', 'f');
expect(f.modelType.linkedName, matchesCompressed('''
<a href="$dartCoreUrlPrefix/List-class.html">List</a>
<span class="signature">&lt;<wbr>
<span class="type-parameter">
<a href="$dartCoreUrlPrefix/int-class.html">int</a>
</span>&gt;
</span>
'''));
}

void test_getter_substitutedTypes() async {
var library = await bootPackageWithLibrary('''
class C<T> {
List<T> get f => [];
}
class D extends C<int> {}
''');
var f = library.field('D', 'f').getter!;
expect(f.modelType.returnType.linkedName, matchesCompressed('''
<a href="$dartCoreUrlPrefix/List-class.html">List</a>
<span class="signature">&lt;<wbr>
<span class="type-parameter">
<a href="$dartCoreUrlPrefix/int-class.html">int</a>
</span>&gt;
</span>
'''));
}

void test_setterParameter_substitutedTypes() async {
var library = await bootPackageWithLibrary('''
class C<T> {
set f(List<T> p) {}
}
class D extends C<int> {}
''');
var f = library.field('D', 'f').setter!;
expect(f.parameters.first.modelType.linkedName, matchesCompressed('''
<a href="$dartCoreUrlPrefix/List-class.html">List</a>
<span class="signature">&lt;<wbr>
<span class="type-parameter">
<a href="$dartCoreUrlPrefix/int-class.html">int</a>
</span>&gt;
</span>
'''));
}

void test_methodReturnType() async {
var library = await bootPackageWithLibrary('''
abstract class C {
List<int> m();
}
''');
var m = library.method('C', 'm');
expect(m.modelType.returnType.linkedName, matchesCompressed('''
<a href="$dartCoreUrlPrefix/List-class.html">List</a>
<span class="signature">&lt;<wbr>
<span class="type-parameter">
<a href="$dartCoreUrlPrefix/int-class.html">int</a>
</span>&gt;
</span>
'''));
}

void test_methodReturnType_substitutedTypes() async {
var library = await bootPackageWithLibrary('''
abstract class C<T> {
List<T> m();
}
class D extends C<int> {}
''');
var m = library.method('D', 'm');
expect(m.modelType.returnType.linkedName, matchesCompressed('''
<a href="$dartCoreUrlPrefix/List-class.html">List</a>
<span class="signature">&lt;<wbr>
<span class="type-parameter">
<a href="$dartCoreUrlPrefix/int-class.html">int</a>
</span>&gt;
</span>
'''));
}

void test_methodReturnType_parameterizedTypedef() async {
var library = await bootPackageWithLibrary('''
typedef String TD<T>(T p);
abstract class C {
TD<int> m();
}
''');
var m = library.method('C', 'm');
expect(m.modelType.returnType.linkedName, matchesCompressed('''
<a href="${htmlBasePlaceholder}types/TD.html">TD</a>
<span class="signature">&lt;<wbr>
<span class="type-parameter">
<a href="$dartCoreUrlPrefix/int-class.html">int</a>
</span>&gt;
</span>
'''));
}

void test_methodReturnType_substitutedTypes_parameterizedTypedef() async {
var library = await bootPackageWithLibrary('''
typedef String TD<T>(T p);
abstract class C<T> {
TD<T> m();
}
class D extends C<int> {}
''');
var m = library.method('D', 'm');
expect(m.modelType.returnType.linkedName, matchesCompressed('''
<a href="${htmlBasePlaceholder}types/TD.html">TD</a>
<span class="signature">&lt;<wbr>
<span class="type-parameter">
<a href="$dartCoreUrlPrefix/int-class.html">int</a>
</span>&gt;
</span>
'''));
}

void test_operatorTypes_substitutedTypes() async {
var library = await bootPackageWithLibrary('''
abstract class C<T> {
List<T> operator +(List<T> p);
}
class D extends C<int> {}
''');
var plus = library.operator('D', 'operator +');
expect(plus.modelType.returnType.linkedName, matchesCompressed('''
<a href="$dartCoreUrlPrefix/List-class.html">List</a>
<span class="signature">&lt;<wbr>
<span class="type-parameter">
<a href="$dartCoreUrlPrefix/int-class.html">int</a>
</span>&gt;
</span>
'''));
var renderedParameter =
ParameterRendererHtml().renderLinkedParams(plus.parameters);
expect(renderedParameter, matchesCompressed('''
<a href="$dartCoreUrlPrefix/List-class.html">List</a>
<span class="signature">&lt;<wbr>
<span class="type-parameter">
<a href="$dartCoreUrlPrefix/int-class.html">int</a>
</span>&gt;
</span>
'''));
}
}

extension on Library {
Field field(String className, String methodName) => classes
.firstWhere((c) => c.name == className)
.instanceFields
.firstWhere((field) => field.name == methodName);

Method method(String className, String methodName) => classes
.firstWhere((clas) => clas.name == className)
.instanceMethods
.firstWhere((method) => method.name == methodName);

Operator operator(String className, String methodName) => classes
.firstWhere((clas) => clas.name == className)
.instanceOperators
.firstWhere((method) => method.name == methodName);
}
20 changes: 0 additions & 20 deletions testing/test_package/lib/example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,26 +88,6 @@ typedef String processMessage<T>(String msg);

typedef String ParameterizedTypedef<T>(T msg, int foo);

/// Support class to test inheritance + type expansion from implements clause.
abstract class ParameterizedClass<T> {
AnotherParameterizedClass<T> aInheritedMethod(int foo);
ParameterizedTypedef<T> aInheritedTypedefReturningMethod();
AnotherParameterizedClass<T>? aInheritedField;
AnotherParameterizedClass<T> get aInheritedGetter;
ParameterizedClass<T> operator +(ParameterizedClass<T> other);
set aInheritedSetter(AnotherParameterizedClass<T> thingToSet);
}

class AnotherParameterizedClass<B> {}

/// Class for testing expansion of type from implements clause.
abstract class TemplatedInterface<A> implements ParameterizedClass<List<int>> {
AnotherParameterizedClass<List<int>> aMethodInterface(A value);
ParameterizedTypedef<List<String>> aTypedefReturningMethodInterface();
AnotherParameterizedClass<Stream<List<int>>>? aField;
set aSetter(AnotherParameterizedClass<List<bool>> thingToSet);
}

class TemplatedClass<X> {
int aMethod(X input) {
return 5;
Expand Down
Loading