Skip to content

Commit 6d5e133

Browse files
authored
Simplify LibraryContainer hierarchy and tests (#4121)
This one is a bit of a story; I could break it up if that would help the review, but here goes: 1. I saw that LibraryContainer, an `abstract mixin class`, was (a) _mixed into_ Category, and (b) _extended_ by Package. Weird. So I tried to make it a _base_ class, a proper superclass of those two. Well that showed me the two test classes: TestLibraryContainer and TestLibraryContainerSdk. 2. What do those two test classes do? They existed for a mere 2 test cases in `model_test.dart`. These test cases just test the `compareTo` logic in LibraryContainer, but it is not terribly obvious how they test them. The TestLibraryContainer seemed very generic, and odd, with its own ContainerOrder list. In practice, Categories are always ordered by the `--category-order` option, and Packages are always ordered by the `--package-order` option. There's no need to test some generic ordering system. 3. So, I was able to tear down those test classes and their two test cases, and rewrite them in a more real-world test `group` in `packages_test.dart`. 4. This also allows `isSdk` and `enclosingName` to be simple, final fields on LibraryContainer, and `enclosingName` can be private. And then `containerOrder` only needs to stay public in order to override. 5. This refactoring did require some fixes in the `writePackage` test function: (a) it was writing a `.packages` file, and (b) it was writing hard-coded package names into a package config file. We fix this by passing in a list of dependency names.
1 parent 6d1aa6f commit 6d5e133

File tree

7 files changed

+115
-163
lines changed

7 files changed

+115
-163
lines changed

lib/src/model/category.dart

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,12 @@ import 'package:dartdoc/src/model/model.dart';
1111
import 'package:dartdoc/src/warnings.dart';
1212

1313
/// A subcategory of a package, containing elements tagged with `{@category}`.
14-
class Category
14+
final class Category extends LibraryContainer
1515
with
1616
Nameable,
1717
Warnable,
1818
CommentReferable,
1919
MarkdownFileDocumentation,
20-
LibraryContainer,
2120
TopLevelContainer
2221
implements Documentable {
2322
/// The package in which this category is contained.
@@ -64,7 +63,8 @@ class Category
6463
Category(this._name, this.package, this.config)
6564
: _categoryDefinition =
6665
config.categories.categoryDefinitions[_name.orDefault] ??
67-
CategoryDefinition(_name, null, null);
66+
CategoryDefinition(_name, null, null),
67+
super(isSdk: false, enclosingName: package.name);
6868

6969
Iterable<ExternalItem> get externalItems => _categoryDefinition.externalItems;
7070

@@ -88,9 +88,6 @@ class Category
8888
@override
8989
List<String> get containerOrder => config.categoryOrder;
9090

91-
@override
92-
String get enclosingName => package.name;
93-
9491
@override
9592
PackageGraph get packageGraph => package.packageGraph;
9693

lib/src/model/library_container.dart

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
import 'package:collection/collection.dart';
66
import 'package:dartdoc/src/model/model.dart';
77
import 'package:dartdoc/src/model_utils.dart' as model_utils;
8+
import 'package:meta/meta.dart';
89

910
/// A set of libraries, initialized after construction by accessing [libraries].
1011
///
1112
/// Do not cache return values of any methods or members excepting [libraries]
1213
/// and [name] before finishing initialization of a [LibraryContainer].
13-
abstract mixin class LibraryContainer
14+
abstract base class LibraryContainer
1415
implements Nameable, Comparable<LibraryContainer>, Documentable {
1516
final List<Library> libraries = [];
1617

@@ -19,31 +20,40 @@ abstract mixin class LibraryContainer
1920

2021
bool get hasPublicLibraries => libraries.any((e) => e.isPublic);
2122

23+
LibraryContainer({required this.isSdk, required String enclosingName})
24+
: _enclosingName = enclosingName;
25+
2226
/// The name of the container or object that this LibraryContainer is a part
23-
/// of. Used for sorting in [containerOrder].
24-
String get enclosingName;
27+
/// of.
28+
///
29+
/// Used for sorting in [containerOrder].
30+
final String _enclosingName;
2531

2632
/// Order by which this container should be sorted.
33+
@visibleForOverriding
2734
List<String> get containerOrder;
2835

29-
/// Sorting key. [containerOrder] should contain these.
36+
/// Sorting key.
37+
///
38+
/// [containerOrder] should contain these.
3039
String get sortKey => name;
3140

32-
/// Does this container represent the SDK? This can be false for containers
33-
/// that only represent a part of the SDK.
34-
bool get isSdk => false;
41+
/// Whether this container represents the Dart SDK.
42+
///
43+
/// This can be false for containers that only represent a part of the SDK.
44+
final bool isSdk;
3545

3646
/// Returns:
3747
/// * -1 if this container is listed in [containerOrder].
38-
/// * 0 if this container is named the same as the [enclosingName].
48+
/// * 0 if this container is named the same as the [_enclosingName].
3949
/// * 1 if this container represents the SDK.
40-
/// * 2 if this group has a name that contains the name [enclosingName].
50+
/// * 2 if this group has a name that contains the name [_enclosingName].
4151
/// * 3 otherwise.
4252
int get _group {
4353
if (containerOrder.contains(sortKey)) return -1;
44-
if (equalsIgnoreAsciiCase(sortKey, enclosingName)) return 0;
54+
if (equalsIgnoreAsciiCase(sortKey, _enclosingName)) return 0;
4555
if (isSdk) return 1;
46-
if (sortKey.toLowerCase().contains(enclosingName.toLowerCase())) return 2;
56+
if (sortKey.toLowerCase().contains(_enclosingName.toLowerCase())) return 2;
4757
return 3;
4858
}
4959

lib/src/model/package.dart

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const String htmlBasePlaceholder = r'%%__HTMLBASE_dartdoc_internal__%%';
2929

3030
/// A [LibraryContainer] that contains [Library] objects related to a particular
3131
/// package.
32-
class Package extends LibraryContainer
32+
final class Package extends LibraryContainer
3333
with Nameable, Warnable, CommentReferable {
3434
@override
3535
final String name;
@@ -70,7 +70,10 @@ class Package extends LibraryContainer
7070
packageGraph.config,
7171
packageGraph.resourceProvider.getFolder(packagePath),
7272
packageGraph.resourceProvider,
73-
);
73+
),
74+
super(
75+
isSdk: packageMeta.isSdk,
76+
enclosingName: packageGraph.defaultPackageName);
7477

7578
@override
7679
bool get isCanonical => true;
@@ -183,9 +186,6 @@ class Package extends LibraryContainer
183186
return DocumentLocation.missing;
184187
}();
185188

186-
@override
187-
String get enclosingName => packageGraph.defaultPackageName;
188-
189189
String get filePath => 'index.html';
190190

191191
@override
@@ -364,9 +364,6 @@ class Package extends LibraryContainer
364364
packageGraph.localPackages.isNotEmpty &&
365365
identical(packageGraph.localPackages.first, this);
366366

367-
@override
368-
bool get isSdk => packageMeta.isSdk;
369-
370367
final String packagePath;
371368

372369
String get version => packageMeta.version;

lib/src/package_config_provider.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ class FakePackageConfigProvider implements PackageConfigProvider {
2525
/// A mapping of package config search locations to configured packages.
2626
final _packageConfigData = <String, List<package_config.Package>>{};
2727

28+
/// Adds the package named [name] at [root] to the package config for
29+
/// [location].
2830
void addPackageToConfigFor(String location, String name, Uri root) {
2931
_packageConfigData
3032
.putIfAbsent(location, () => [])

test/end2end/model_test.dart

Lines changed: 0 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import 'package:analyzer/dart/element/type.dart';
99
import 'package:analyzer/source/line_info.dart';
1010
import 'package:async/async.dart';
1111
import 'package:collection/src/iterable_extensions.dart';
12-
import 'package:dartdoc/src/dartdoc_options.dart';
1312
import 'package:dartdoc/src/element_type.dart';
1413
import 'package:dartdoc/src/matching_link_result.dart';
1514
import 'package:dartdoc/src/model/attribute.dart';
@@ -36,66 +35,6 @@ Future<PackageGraph> get testPackageGraph async =>
3635
excludeLibraries: ['css', 'code_in_comments'],
3736
additionalArguments: ['--no-link-to-remote']));
3837

39-
/// For testing sort behavior.
40-
class TestLibraryContainer extends LibraryContainer with Nameable {
41-
@override
42-
final List<String> containerOrder;
43-
@override
44-
String enclosingName;
45-
@override
46-
final String name;
47-
48-
@override
49-
bool get isSdk => false;
50-
@override
51-
PackageGraph get packageGraph => throw UnimplementedError();
52-
53-
@override
54-
Package get package => throw UnimplementedError();
55-
56-
TestLibraryContainer(
57-
this.name, this.containerOrder, LibraryContainer? enclosingContainer)
58-
: enclosingName = enclosingContainer?.name ?? '';
59-
60-
@override
61-
DartdocOptionContext get config => throw UnimplementedError();
62-
63-
@override
64-
String? get documentation => throw UnimplementedError();
65-
66-
@override
67-
String get documentationAsHtml => throw UnimplementedError();
68-
69-
@override
70-
bool get hasDocumentation => throw UnimplementedError();
71-
72-
@override
73-
String? get href => throw UnimplementedError();
74-
75-
@override
76-
bool get isDocumented => throw UnimplementedError();
77-
78-
@override
79-
Kind get kind => throw UnimplementedError();
80-
81-
@override
82-
String get oneLineDoc => throw UnimplementedError();
83-
84-
@override
85-
String? get aboveSidebarPath => null;
86-
87-
@override
88-
String? get belowSidebarPath => null;
89-
}
90-
91-
class TestLibraryContainerSdk extends TestLibraryContainer {
92-
TestLibraryContainerSdk(super.name, super.containerOrder,
93-
LibraryContainer super.enclosingContainer);
94-
95-
@override
96-
bool get isSdk => true;
97-
}
98-
9938
void main() async {
10039
final packageGraph = await testPackageGraph;
10140
late final Library exLibrary;
@@ -737,64 +676,6 @@ void main() async {
737676
expect(category.redirectFilePath, 'topics/Superb-topic.html');
738677
});
739678

740-
group('LibraryContainer', () {
741-
late final TestLibraryContainer topLevel;
742-
var sortOrderBasic = ['theFirst', 'second', 'fruit'];
743-
var containerNames = [
744-
'moo',
745-
'woot',
746-
'theFirst',
747-
'topLevel Things',
748-
'toplevel',
749-
'fruit'
750-
];
751-
752-
setUpAll(() {
753-
topLevel = TestLibraryContainer('topLevel', [], null);
754-
});
755-
756-
test('multiple containers with specified sort order', () {
757-
var containers = <LibraryContainer>[];
758-
for (var i = 0; i < containerNames.length; i++) {
759-
var name = containerNames[i];
760-
containers.add(TestLibraryContainer(name, sortOrderBasic, topLevel));
761-
}
762-
containers.add(TestLibraryContainerSdk('SDK', sortOrderBasic, topLevel));
763-
containers.sort();
764-
expect(
765-
containers.map((c) => c.name),
766-
orderedEquals([
767-
'theFirst',
768-
'fruit',
769-
'toplevel',
770-
'SDK',
771-
'topLevel Things',
772-
'moo',
773-
'woot'
774-
]));
775-
});
776-
777-
test('multiple containers, no specified sort order', () {
778-
var containers = <LibraryContainer>[];
779-
for (var name in containerNames) {
780-
containers.add(TestLibraryContainer(name, [], topLevel));
781-
}
782-
containers.add(TestLibraryContainerSdk('SDK', [], topLevel));
783-
containers.sort();
784-
expect(
785-
containers.map((c) => c.name),
786-
orderedEquals([
787-
'toplevel',
788-
'SDK',
789-
'topLevel Things',
790-
'fruit',
791-
'moo',
792-
'theFirst',
793-
'woot'
794-
]));
795-
});
796-
});
797-
798679
group('Library', () {
799680
late final Library anonLib,
800681
isDeprecated,

test/packages_test.dart

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,9 @@ library script;
277277
class Script {}
278278
''');
279279

280-
packageTwoRoot =
281-
utils.writePackage('two', resourceProvider, packageConfigProvider);
280+
packageTwoRoot = utils.writePackage(
281+
'two', resourceProvider, packageConfigProvider,
282+
dependencies: ['one']);
282283
packageConfigProvider.addPackageToConfigFor(
283284
packageTwoRoot.path, 'one', Uri.file('${packageOneRoot.path}/'));
284285
packageTwoRoot
@@ -456,6 +457,64 @@ int x;
456457
expect(packageGraph.localPackages.first.categories, isEmpty);
457458
});
458459
});
460+
461+
group('ordering', () {
462+
late Folder defaultRoot;
463+
464+
Folder bootBasicPackages(List<String> names) {
465+
var defaultPackageRoot = utils.writePackage(
466+
'default', resourceProvider, packageConfigProvider,
467+
dependencies: names);
468+
469+
for (var name in names) {
470+
var root =
471+
utils.writePackage(name, resourceProvider, packageConfigProvider);
472+
root
473+
.getChildAssumingFolder('lib')
474+
.getChildAssumingFile('$name.dart')
475+
.writeAsStringSync('var a = 1;');
476+
packageConfigProvider.addPackageToConfigFor(
477+
defaultPackageRoot.path, name, Uri.file('${root.path}/'));
478+
defaultPackageRoot
479+
.getChildAssumingFolder('lib')
480+
.getChildAssumingFile('$name.dart')
481+
.writeAsStringSync('''
482+
import 'package:$name/$name.dart';
483+
var b = a;
484+
''');
485+
}
486+
487+
return defaultPackageRoot;
488+
}
489+
490+
test('default package precedes SDK which precedes dependencies',
491+
() async {
492+
defaultRoot = bootBasicPackages(['bbb', 'aaa']);
493+
var packageGraph = await utils.bootBasicPackage(
494+
defaultRoot.path, packageMetaProvider, packageConfigProvider,
495+
additionalArguments: [
496+
'--auto-include-dependencies',
497+
]);
498+
499+
var sortedPackages = [...packageGraph.localPackages]..sort();
500+
expect(sortedPackages.map((c) => c.name),
501+
orderedEquals(['default', 'Dart', 'aaa', 'bbb']));
502+
});
503+
504+
test('packages named in --package-order option come first', () async {
505+
defaultRoot = bootBasicPackages(['aaa', 'bbb', 'ccc']);
506+
var packageGraph = await utils.bootBasicPackage(
507+
defaultRoot.path, packageMetaProvider, packageConfigProvider,
508+
additionalArguments: [
509+
'--auto-include-dependencies',
510+
'--package-order=bbb,aaa',
511+
]);
512+
513+
var sortedPackages = [...packageGraph.localPackages]..sort();
514+
expect(sortedPackages.map((c) => c.name),
515+
orderedEquals(['bbb', 'aaa', 'default', 'Dart', 'ccc']));
516+
});
517+
});
459518
});
460519
}
461520

0 commit comments

Comments
 (0)