| // Copyright (c) 2021, 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. |
| |
| /// @docImport 'package:dartdoc/src/model/model_element.dart'; |
| library; |
| |
| import 'package:collection/collection.dart'; |
| import 'package:dartdoc/src/model/comment_referable.dart'; |
| import 'package:dartdoc/src/model/nameable.dart'; |
| import 'package:dartdoc/src/model/package_graph.dart'; |
| import 'package:test/test.dart'; |
| |
| const _separator = '.'; |
| |
| abstract class Base with Nameable, CommentReferable { |
| @override |
| PackageGraph get packageGraph => throw UnimplementedError(); |
| |
| List<Base> get children; |
| |
| Base? parent; |
| |
| /// Utility function to quickly build structures similar to [ModelElement] |
| /// hierarchies in dartdoc in tests. |
| /// Returns the added (or already existing) [Base]. |
| Base add(String newName); |
| |
| CommentReferable? lookup<T extends CommentReferable?>( |
| String value, { |
| bool Function(CommentReferable?)? filter, |
| }) { |
| return referenceBy(value.split(_separator), filter: filter ?? (_) => true); |
| } |
| |
| @override |
| Iterable<CommentReferable>? get referenceGrandparentOverrides => null; |
| } |
| |
| class Top extends Base { |
| @override |
| final String name; |
| @override |
| final List<TopChild> children; |
| |
| Top(this.name, this.children); |
| |
| @override |
| Base add(String newName) { |
| Base retval; |
| var newNameSplit = newName.split(_separator).toList(); |
| var parent = children.firstWhereOrNull((c) => c.name == newNameSplit.first); |
| if (parent == null) { |
| parent = TopChild(newNameSplit.last, [], this); |
| children.add(parent); |
| retval = parent; |
| } |
| retval = parent; |
| if (newNameSplit.length > 1) { |
| retval = parent.add(newNameSplit.sublist(1).join(_separator)); |
| } |
| return retval; |
| } |
| |
| @override |
| Map<String, CommentReferable> get referenceChildren => |
| Map.fromEntries(children.map((c) => MapEntry(c.name, c))); |
| |
| @override |
| Iterable<CommentReferable> get referenceParents => []; |
| } |
| |
| abstract class Child extends Base { |
| @override |
| List<Child> get children; |
| |
| @override |
| Base add(String newName) { |
| Base retval; |
| var newNameSplit = newName.split(_separator).toList(); |
| var child = children.firstWhereOrNull((c) => c.name == newNameSplit.first); |
| if (child == null) { |
| child = GenericChild(newNameSplit.last, [], this); |
| children.add(child); |
| } |
| |
| retval = child; |
| if (newNameSplit.length > 1) { |
| retval = child.add(newNameSplit.sublist(1).join(_separator)); |
| } |
| return retval; |
| } |
| } |
| |
| class TopChild extends Child { |
| @override |
| final String name; |
| @override |
| final List<GenericChild> children; |
| final Top _parent; |
| @override |
| Top get parent => _parent; |
| |
| TopChild(this.name, this.children, this._parent); |
| |
| @override |
| Map<String, CommentReferable> get referenceChildren => |
| Map.fromEntries(children.map((c) => MapEntry(c.name, c))); |
| |
| @override |
| Iterable<CommentReferable> get referenceParents => [parent]; |
| } |
| |
| class GenericChild extends Child { |
| @override |
| final String name; |
| @override |
| final List<GenericChild> children; |
| final Base _parent; |
| @override |
| Base get parent => _parent; |
| |
| GenericChild(this.name, this.children, this._parent); |
| |
| @override |
| Map<String, CommentReferable> get referenceChildren => |
| Map.fromEntries(children.map((c) => MapEntry(c.name, c))); |
| |
| @override |
| Iterable<CommentReferable> get referenceParents => [parent]; |
| } |
| |
| class GrandparentOverrider extends GenericChild { |
| @override |
| final Iterable<Base> referenceGrandparentOverrides; |
| |
| GrandparentOverrider(super.name, super.children, super.parent, |
| this.referenceGrandparentOverrides); |
| } |
| |
| void main() { |
| group('Basic comment reference lookups', () { |
| late Top referable; |
| |
| setUp(() { |
| referable = Top('top', []); |
| referable.add('lib1'); |
| referable.add('lib2'); |
| referable.add('lib3'); |
| referable.add('lib1.class1'); |
| referable.add('lib1.class2'); |
| referable.add('lib1.class2.member1'); |
| referable.add('lib2'); |
| referable.add('lib2.class3'); |
| referable.add('lib3.lib3.lib3'); |
| }); |
| |
| test('Check that basic lookups work', () { |
| expect(referable.lookup('lib1')?.name, equals('lib1')); |
| expect(referable.lookup('lib2')?.name, equals('lib2')); |
| expect(referable.lookup('lib1.class2.member1')?.name, equals('member1')); |
| expect(referable.lookup('lib2.class3')?.name, equals('class3')); |
| }); |
| |
| test('Check that filters work', () { |
| expect(referable.lookup('lib3'), isA<TopChild>()); |
| expect(referable.lookup('lib3', filter: (r) => r is GenericChild), |
| isA<GenericChild>()); |
| }); |
| |
| test('Check that grandparent overrides work', () { |
| referable.add('lib4'); |
| var i1 = referable.add('lib4.intermediate1'); |
| var i1target = referable.add('lib4.intermediate1.target'); |
| referable.add('lib4.intermediate2'); |
| var i2target = referable.add('lib4.intermediate2.target'); |
| var i2other = referable.add('lib4.intermediate2.other'); |
| var i2notFromHere = referable.add('lib4.intermediate2.notFromHere'); |
| var overrider = GrandparentOverrider('fromHere', [], i2other, [i1]); |
| i2other.children.add(overrider); |
| expect(i2notFromHere.lookup('target'), i2target); |
| // Ordinarily, since overrider's parent is i2target, we would expect this |
| // to work the same. But it has an override. |
| expect(overrider.lookup('target'), i1target); |
| expect(overrider.lookup('intermediate2.target'), i2target); |
| }); |
| }); |
| } |