blob: 71dd7a35ee3a40f765431b17fc6ed1fb94bb778d [file] [log] [blame]
// 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.
library dartdoc.comment_reference_test;
import 'package:analyzer/dart/element/element.dart';
import 'package:dartdoc/src/model/comment_referable.dart';
import 'package:dartdoc/src/model/model_object_builder.dart';
import 'package:dartdoc/src/model/nameable.dart';
import 'package:test/test.dart';
const _separator = '.';
abstract class Base extends Nameable with CommentReferable {
@override
ModelObjectBuilder get modelBuilder =>
throw UnimplementedError('not needed for this test');
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);
T lookup<T extends CommentReferable>(String value,
{bool Function(CommentReferable) allowTree,
bool Function(CommentReferable) filter}) =>
referenceBy(value.split(_separator),
allowTree: allowTree, filter: filter);
@override
Element get element => throw UnimplementedError();
@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.firstWhere((c) => c.name == newNameSplit.first,
orElse: () => null);
if (parent == null) {
parent = TopChild(newNameSplit.last, [], this);
children.add(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.firstWhere((c) => c.name == newNameSplit.first,
orElse: () => null);
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(String name, List<GenericChild> children, Base parent,
this.referenceGrandparentOverrides)
: super(name, children, parent);
}
void main() {
group('Basic comment reference lookups', () {
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 allowTree works', () {
referable.add('lib4');
var lib4lib4 = referable.add('lib4.lib4');
var tooDeepSub1 = referable.add('lib4.lib4.sub1');
var sub1 = referable.add('lib4.sub1');
var sub2 = referable.add('lib4.sub2');
expect(sub2.lookup('lib4.lib4'), equals(lib4lib4));
expect(sub2.lookup('lib4.sub1'), equals(tooDeepSub1));
expect(
sub2.lookup('lib4.sub1',
allowTree: ((r) => r is Base && (r.parent is Top))),
equals(sub1));
});
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);
});
});
}