blob: 52721945322947abb52dd230bb0290ada7de1281 [file] [log] [blame]
// Copyright (c) 2015, 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.model_test;
import 'dart:io';
import 'package:grinder/grinder.dart' as grinder;
import 'package:path/path.dart' as path;
import 'package:unittest/unittest.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_io.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:dartdoc/src/model.dart';
import 'package:dartdoc/src/model_utils.dart';
void main() {
AnalyzerHelper helper = new AnalyzerHelper();
String dirPath = path.join(Directory.current.path, 'test/fake_package');
Source source = helper.addSource(path.join(dirPath, 'lib/example.dart'));
LibraryElement e = helper.resolve(source);
Package package = new Package([e], dirPath);
var library = package.libraries[0];
var file = new File(path.join(dirPath, 'lib/example.dart'));
var lib2 = new Library(e, package, file.readAsStringSync());
group('Package', () {
var p, p2;
setUp(() {
p = new Package([e], Directory.current.path);
var readmeLoc =
'${Directory.current.path}/test/fake_package/test_readme.md';
p2 = new Package(
[e], Directory.current.path, '1.9.0-dev.3.0', true, readmeLoc);
});
test('name', () {
expect(p.name, 'dartdoc');
});
test('libraries', () {
expect(p.libraries, hasLength(1));
});
test('is documented', () {
expect(p.isDocumented(library), true);
});
test('description', () {
expect(p.description.startsWith('# dartdoc'), true);
});
test('sdk name', () {
expect(p2.name, 'Dart API Reference');
});
test('sdk version', () {
expect(p2.version, '1.9.0-dev.3.0');
});
test('sdk description', () {
expect(true, p2.description
.startsWith('Welcome to the Dart API reference documentation.'));
});
});
group('Library', () {
var sdkLib;
setUp(() {
sdkLib = new Library(
getSdkLibrariesToDocument(helper.sdk, helper.context)[0], package);
});
test('name', () {
expect(library.name, 'ex');
});
test('sdk library name', () {
expect(sdkLib.name, 'dart:async');
});
test('documentation', () {
expect(library.documentation, 'a library');
});
test('has properties', () {
expect(library.hasProperties, true);
});
test('has constants', () {
expect(library.hasConstants, true);
});
test('has exceptions', () {
expect(library.hasExceptions, true);
});
test('has enums', () {
expect(library.hasEnums, false);
});
test('has functions', () {
expect(library.hasFunctions, true);
});
test('has typedefs', () {
expect(library.hasTypedefs, true);
});
test('exported class', () {
expect(library.getClasses().any((c) => c.name == 'Helper'), true);
});
test('exported function', () {
expect(
library.getFunctions().any((f) => f.name == 'helperFunction'), false);
});
});
group('Class', () {
List<Class> classes;
Class Apple, B, Cat, Dog, F;
setUp(() {
classes = library.getClasses();
Apple = classes[0];
B = classes[1];
Cat = classes[2];
Dog = classes[3];
F = classes.firstWhere((c) => c.name == 'F');
});
test('we got the classes we expect', () {
expect(Apple.name, equals('Apple'));
expect(B.name, equals('B'));
expect(Cat.name, equals('Cat'));
expect(Dog.name, equals('Dog'));
});
test('correctly finds classes', () {
expect(classes, hasLength(12));
});
test('docs ', () {
expect(
Apple.resolveReferences(Apple.documentation), 'Sample class String');
});
test('docs refs', () {
expect(B.resolveReferences(B.documentation),
'Extends class <a href=ex/Apple_class.html> Apple</a>');
});
test('abstract', () {
expect(Cat.isAbstract, true);
});
test('supertype', () {
expect(B.hasSupertype, true);
});
test('mixins', () {
expect(Apple.mixins, hasLength(0));
});
test('mixins not private', () {
expect(F.mixins, hasLength(0));
});
test('interfaces', () {
var interfaces = Dog.interfaces;
expect(interfaces, hasLength(2));
expect(interfaces[0].name, 'Cat');
expect(interfaces[1].name, 'E');
});
test('get constructors', () {
expect(Apple.constructors, hasLength(1));
});
test('get static fields', () {
expect(Apple.staticProperties, hasLength(1));
});
test('get constants', () {
expect(Apple.constants, hasLength(1));
});
test('get instance fields', () {
expect(Apple.instanceProperties, hasLength(2));
});
test('get inherited properties', () {
expect(B.inheritedProperties, hasLength(2));
});
test('get methods', () {
expect(Dog.instanceMethods, hasLength(2));
});
test('get operators', () {
expect(Dog.operators, hasLength(1));
expect(Dog.operators[0].name, 'operator ==');
});
test('inherited methods', () {
expect(B.inheritedMethods, hasLength(2));
expect(B.hasInheritedMethods, isTrue);
});
test('inherited methods names', () {
expect(B.inheritedMethods[0].name, 'printMsg');
expect(B.inheritedMethods[1].name, 'isGreaterThan');
});
});
group('Function', () {
ModelFunction f1, f2;
setUp(() {
f1 = library.getFunctions()[0];
f2 = lib2.getFunctions()[0];
});
test('name is function1', () {
expect(f1.name, 'function1');
expect(f2.name, 'function1');
});
test('local element', () {
expect(f1.isLocalElement, true);
});
test('is executable', () {
expect(f1.isExecutable, true);
});
test('is static', () {
expect(f1.isStatic, true);
});
test('handles dynamic parameters correctly', () {
expect(f2.linkedParams(), contains('lastParam'));
});
test('has correct source code', () {
expect(f2.source,
equals('int function1(String s, bool b, lastParam) => 5;'));
});
});
group('Method', () {
var c, m, m2, m3, m4;
setUp(() {
c = library.getClasses()[1];
m = c.instanceMethods[0];
m2 = lib2.getClasses()[1].instanceMethods[0];
m3 = library.getClasses()[0].instanceMethods[0];
m4 = library.getClasses()[1].instanceMethods[1];
});
test('overriden method', () {
expect(m.getOverriddenElement().runtimeType.toString(), 'Method');
});
test('method source', () {
expect(m2.source,
'@override\n void m1() {\n var a = 6;\n var b = a * 9;\n }');
});
test('method documentation', () {
expect(m2.documentation, 'this is a method');
});
test('can have params', () {
expect(m3.canHaveParameters, isTrue);
});
test('has parameters', () {
expect(m3.hasParameters, isFalse);
});
test('return type', () {
expect(m3.modelType.createLinkedReturnTypeName(), 'void');
});
test('parameter is a function', () {
expect(m4.parameters[1].modelType.element.linkedReturnType, 'String');
});
});
group('Field', () {
var c, f1, f2, constField;
setUp(() {
c = library.getClasses()[0];
f1 = c.staticProperties[0]; // n
f2 = c.instanceProperties[0];
constField = c.constants[0]; // string
});
test('is not const', () {
expect(f1.isConst, isFalse);
});
test('is const', () {
expect(constField.isConst, isTrue);
});
test('is final', () {
expect(f1.isFinal, false);
});
test('is static', () {
expect(f2.isStatic, false);
});
});
group('Variable', () {
TopLevelVariable v;
TopLevelVariable v3;
setUp(() {
v = library.getProperties()[0];
v3 = library.getProperties()[1];
});
test('found two properties', () {
expect(library.getProperties(), hasLength(2));
});
test('linked return type is a double', () {
expect(v.linkedReturnType, 'double');
});
test('linked return type is dynamic', () {
expect(v3.linkedReturnType, 'dynamic');
});
});
group('Constant', () {
TopLevelVariable constant;
setUp(() {
constant = library.getConstants()[0];
});
test('found two constants', () {
expect(library.getConstants(), hasLength(2));
});
test('is constant', () {
expect(constant.isConst, isTrue);
});
});
group('Constructor', () {
var c2;
setUp(() {
c2 = lib2.getClasses()[0].constructors[0];
});
test('has source', () {
expect(c2.source, equals('///Constructor\n Apple();'));
});
});
group('Type', () {
var f = library.getClasses()[1].instanceProperties[0];
test('parameterized type', () {
expect(f.modelType.isParameterizedType, true);
});
});
group('Typedef', () {
var t;
setUp(() {
t = library.getTypedefs()[0];
});
test('docs', () {
expect(t.documentation, null);
});
test('linked return type', () {
expect(t.linkedReturnType, 'String');
});
});
group('Parameter', () {
Class c;
Method isGreaterThan, asyncM;
Parameter p1;
setUp(() {
c = library.getClasses()[0]; // A
isGreaterThan = c.instanceMethods[2]; // isGreaterThan
asyncM = library.getClasses()[3].instanceMethods
.firstWhere((m) => m.name == 'foo');
p1 = isGreaterThan.parameters[1]; // {int check:5}
});
test('is optional', () {
expect(p1.isOptional, true);
});
test('default value', () {
expect(p1.defaultValue, '5');
});
test('is named', () {
expect(p1.isOptionalNamed, true);
});
test('linkedName', () {
expect(p1.modelType.linkedName, 'int');
});
test('async return type', () {
expect(asyncM.linkedReturnType, 'Future');
});
});
group('Implementors', () {
Class apple;
Class b;
List<Class> implA, implC;
setUp(() {
apple = library.getClasses()[0];
b = library.getClasses()[1];
implA = apple.implementors;
implC = library.getClasses()[2].implementors;
});
test('the first class is Apple', () {
expect(apple.name, equals('Apple'));
});
test('apple has some implementors', () {
expect(apple.hasImplementors, isTrue);
expect(implA, isNotNull);
expect(implA, hasLength(1));
expect(implA[0].name, equals('B'));
});
test('C has implementors', () {
expect(implC, hasLength(2));
expect(implC[0].name, equals('B'));
expect(implC[1].name, equals('Dog'));
});
test('B does not have implementors', () {
expect(b, isNotNull);
expect(b.name, equals('B'));
expect(b.implementors, hasLength(0));
});
});
group('Errors and exceptions', () {
final List<String> expectedNames = [
'MyError',
'MyException',
'MyErrorImplements',
'MyExceptionImplements'
];
test('library has the exact errors/exceptions we expect', () {
expect(library.getExceptions().map((e) => e.name),
unorderedEquals(expectedNames));
});
});
group('Annotations', () {
Class forAnnotation, dog;
setUp(() {
forAnnotation =
library.getClasses().firstWhere((c) => c.name == 'HasAnnotation');
dog = library.getClasses().firstWhere((c) => c.name == 'Dog');
});
test('is not null', () => expect(forAnnotation, isNotNull));
test('has annotations', () => expect(forAnnotation.hasAnnotations, true));
test('has one annotation',
() => expect(forAnnotation.annotations, hasLength(1)));
test('has the right annotation', () {
expect(forAnnotation.annotations.first, equals(
'<a href="ex/ForAnnotation_class.html">ForAnnotation</a>(\'my value\')'));
});
test('methods has the right annotation', () {
expect(dog.instanceMethods.first.annotations.first, equals('deprecated'));
});
});
}
class AnalyzerHelper {
AnalysisContext context;
DartSdk sdk;
AnalyzerHelper() {
_initAnalyzer();
}
void _initAnalyzer() {
Directory sdkDir = grinder.getSdkDir(['']);
sdk = new DirectoryBasedDartSdk(new JavaFile(sdkDir.path));
List<UriResolver> resolvers = [
new DartUriResolver(sdk),
new FileUriResolver()
];
SourceFactory sourceFactory = new SourceFactory(resolvers);
context = AnalysisEngine.instance.createAnalysisContext();
context.sourceFactory = sourceFactory;
}
Source addSource(String filePath) {
Source source = new FileBasedSource.con1(new JavaFile(filePath));
ChangeSet changeSet = new ChangeSet();
changeSet.addedSource(source);
context.applyChanges(changeSet);
return source;
}
LibraryElement resolve(Source librarySource) =>
context.computeLibraryElement(librarySource);
}