blob: 568b72fbb38cafea4b9f1792207aef6ae262df89 [file] [log] [blame]
// Copyright (c) 2020, 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:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:dartdoc/src/dartdoc_options.dart';
import 'package:dartdoc/src/model/documentable.dart';
import 'package:dartdoc/src/package_config_provider.dart';
import 'package:dartdoc/src/package_meta.dart';
import 'package:dartdoc/src/special_elements.dart';
import 'package:test/test.dart';
import 'src/utils.dart' as utils;
void main() {
MemoryResourceProvider resourceProvider;
PackageMetaProvider packageMetaProvider;
FakePackageConfigProvider packageConfigProvider;
DartdocOptionSet optionSet;
Folder sdkFolder;
Folder projectRoot;
String projectPath;
var packageName = 'my_package';
void writeToJoinedPath(List<String> pathSegments, String content) {
var file = pathSegments.removeAt(pathSegments.length - 1);
var directory = projectRoot;
for (var d in pathSegments) {
directory = directory.getChildAssumingFolder(d);
}
directory.getChildAssumingFile(file).writeAsStringSync(content);
}
setUp(() async {
packageMetaProvider = utils.testPackageMetaProvider;
resourceProvider = packageMetaProvider.resourceProvider;
sdkFolder = packageMetaProvider.defaultSdkDir;
optionSet = await DartdocOptionSet.fromOptionGenerators(
'dartdoc', [createDartdocOptions], packageMetaProvider);
packageConfigProvider = utils.getTestPackageConfigProvider(sdkFolder.path);
});
tearDown(() {
projectRoot = null;
projectPath = null;
clearPackageMetaCache();
});
group('typical package', () {
setUp(() {
optionSet.parseArguments([]);
projectRoot = utils.writePackage(
packageName, resourceProvider, packageConfigProvider);
projectPath = projectRoot.path;
projectRoot
.getChildAssumingFolder('lib')
.getChildAssumingFile('a.dart')
.writeAsStringSync('''
/// Documentation comment.
int x;
''');
});
test('with no deps has 2 local packages, including SDK', () async {
var packageGraph = await utils.bootBasicPackage(
projectPath, packageMetaProvider, packageConfigProvider,
additionalArguments: [
'--auto-include-dependencies',
'--no-link-to-remote'
]);
var localPackages = packageGraph.localPackages;
expect(localPackages, hasLength(2));
expect(localPackages[0].name, equals(packageName));
expect(localPackages[1].name, equals('Dart'));
});
test('with no deps has 1 local package, excluding SDK', () async {
var packageGraph = await utils.bootBasicPackage(
projectPath, packageMetaProvider, packageConfigProvider,
additionalArguments: ['--no-link-to-remote']);
var localPackages = packageGraph.localPackages;
expect(localPackages, hasLength(1));
expect(localPackages[0].name, equals(packageName));
});
test('has proper name and kind', () async {
var packageGraph = await utils.bootBasicPackage(
projectPath, packageMetaProvider, packageConfigProvider);
var package = packageGraph.defaultPackage;
expect(package.name, equals('my_package'));
expect(package.kind, equals('package'));
});
test('has public libraries', () async {
var packageGraph = await utils.bootBasicPackage(
projectPath, packageMetaProvider, packageConfigProvider);
expect(packageGraph.localPublicLibraries, hasLength(1));
});
test('has private libraries', () async {
var packageGraph = await utils.bootBasicPackage(
projectPath, packageMetaProvider, packageConfigProvider);
var interceptorsLib = packageGraph.libraries
.firstWhere((lib) => lib.name == 'dart:_interceptors');
expect(interceptorsLib.isPublic, isFalse);
});
test('has a homepage', () async {
var packageGraph = await utils.bootBasicPackage(
projectPath, packageMetaProvider, packageConfigProvider);
expect(packageGraph.defaultPackage.hasHomepage, isTrue);
expect(packageGraph.defaultPackage.homepage,
equals('https://github.com/dart-lang'));
});
test('has a public library', () async {
var packageGraph = await utils.bootBasicPackage(
projectPath, packageMetaProvider, packageConfigProvider);
var library = packageGraph.libraries.firstWhere((lib) => lib.name == 'a');
expect(library.isDocumented, true);
});
test('has anonymous libraries', () async {
writeToJoinedPath(['lib', 'b.dart'], '''
/// Documentation comment.
int x;
''');
var packageGraph = await utils.bootBasicPackage(
projectPath, packageMetaProvider, packageConfigProvider);
expect(
packageGraph.libraries.where((lib) => lib.name == 'b'), hasLength(1));
});
test('has documentation via Markdown README', () async {
writeToJoinedPath(['README.md'], 'Readme text.');
var packageGraph = await utils.bootBasicPackage(
projectPath, packageMetaProvider, packageConfigProvider);
expect(packageGraph.defaultPackage.hasDocumentationFile, true);
expect(packageGraph.defaultPackage.hasDocumentation, true);
});
test('has documentation via text README', () async {
writeToJoinedPath(['README'], 'Readme text.');
var packageGraph = await utils.bootBasicPackage(
projectPath, packageMetaProvider, packageConfigProvider);
expect(packageGraph.defaultPackage.hasDocumentationFile, true);
expect(packageGraph.defaultPackage.hasDocumentation, true);
});
test('has documentation content', () async {
writeToJoinedPath(['README.md'], 'Readme text.');
var packageGraph = await utils.bootBasicPackage(
projectPath, packageMetaProvider, packageConfigProvider);
expect(packageGraph.defaultPackage.documentation, equals('Readme text.'));
});
test('has documentation content rendered as HTML', () async {
writeToJoinedPath(['README.md'], 'Readme text.');
var packageGraph = await utils.bootBasicPackage(
projectPath, packageMetaProvider, packageConfigProvider);
expect(packageGraph.defaultPackage.documentationAsHtml,
equals('<p>Readme text.</p>'));
});
});
test('documents single explicitly included library', () async {
optionSet.parseArguments([]);
projectRoot = utils.writePackage(
packageName, resourceProvider, packageConfigProvider);
projectPath = projectRoot.path;
writeToJoinedPath(['lib', 'foo.dart'], '''
/// Documentation comment.
library foo;
''');
writeToJoinedPath(['lib', 'bar.dart'], '''
/// Documentation comment.
library bar;
''');
var packageGraph = await utils.bootBasicPackage(
projectPath, packageMetaProvider, packageConfigProvider,
additionalArguments: ['--include', 'foo']);
expect(packageGraph.localPublicLibraries, hasLength(1));
expect(packageGraph.localPublicLibraries.single.name, equals('foo'));
});
test('documents multiple explicitly included libraries', () async {
optionSet.parseArguments(['--include', 'foo', '--include', 'bar']);
projectRoot = utils.writePackage(
packageName, resourceProvider, packageConfigProvider);
projectPath = projectRoot.path;
writeToJoinedPath(['lib', 'foo.dart'], '''
/// Documentation comment.
library foo;
''');
writeToJoinedPath(['lib', 'bar.dart'], '''
/// Documentation comment.
library bar;
''');
writeToJoinedPath(['lib', 'baz.dart'], '''
/// Documentation comment.
library baz;
''');
var packageGraph = await utils.bootBasicPackage(
projectPath, packageMetaProvider, packageConfigProvider,
additionalArguments: ['--include', 'foo', '--include', 'bar']);
var documentedLibraries = packageGraph.localPublicLibraries;
expect(documentedLibraries, hasLength(2));
expect(documentedLibraries.map((e) => e.name), containsAll(['foo', 'bar']));
expect(documentedLibraries.map((e) => e.name), contains('bar'));
});
test('excludes single explicitly excluded library', () async {
optionSet.parseArguments([]);
projectRoot = utils.writePackage(
packageName, resourceProvider, packageConfigProvider);
projectPath = projectRoot.path;
writeToJoinedPath(['lib', 'foo.dart'], '''
/// Documentation comment.
library foo;
''');
writeToJoinedPath(['lib', 'bar.dart'], '''
/// Documentation comment.
library bar;
''');
var packageGraph = await utils.bootBasicPackage(
projectPath, packageMetaProvider, packageConfigProvider,
additionalArguments: ['--exclude', 'foo']);
expect(packageGraph.localPublicLibraries, hasLength(1));
expect(packageGraph.localPublicLibraries.single.name, equals('bar'));
});
group('using --link-to-remote', () {
Folder packageOneRoot;
Folder packageTwoRoot;
setUp(() {
optionSet.parseArguments(['--link-to-remote']);
packageOneRoot =
utils.writePackage('one', resourceProvider, packageConfigProvider);
packageOneRoot
.getChildAssumingFolder('lib')
.getChildAssumingFile('one.dart')
.writeAsStringSync('''
/// Documentation comment.
library one;
class One {}
''');
packageOneRoot.getChildAssumingFolder('bin').create();
packageOneRoot
.getChildAssumingFolder('bin')
.getChildAssumingFile('script.dart')
.writeAsStringSync('''
/// Documentation comment.
library script;
class Script {}
''');
packageTwoRoot =
utils.writePackage('two', resourceProvider, packageConfigProvider);
packageConfigProvider.addPackageToConfigFor(
packageTwoRoot.path, 'one', Uri.file('${packageOneRoot.path}/'));
packageTwoRoot
.getChildAssumingFolder('lib')
.getChildAssumingFile('two.dart')
.writeAsStringSync('''
/// Documentation comment.
library two;
import 'package:one/one.dart';
class Two extends One {}
''');
});
test('includes remote elements when linkTo -> url is specified', () async {
packageOneRoot
.getChildAssumingFile('dartdoc_options.yaml')
.writeAsStringSync('''
dartdoc:
linkTo:
url: 'https://mypub.topdomain/%n%/%v%'
''');
var packageGraph = await utils.bootBasicPackage(
packageTwoRoot.path, packageMetaProvider, packageConfigProvider,
additionalArguments: ['--link-to-remote']);
expect(packageGraph.packages, hasLength(3));
var packageOne =
packageGraph.packages.singleWhere((p) => p.name == 'one');
// TODO(srawlins): Why is there more than one?
var libraryOne =
packageOne.allLibraries.lastWhere((l) => l.name == 'one');
var classOne = libraryOne.allClasses.firstWhere((c) => c.name == 'One');
expect(packageOne.documentedWhere, equals(DocumentLocation.remote));
expect(classOne.href,
equals('https://mypub.topdomain/one/0.0.1/one/One-class.html'));
});
test('does not include remote elements when linkTo -> url is not specified',
() async {
var packageGraph = await utils.bootBasicPackage(
packageTwoRoot.path, packageMetaProvider, packageConfigProvider,
additionalArguments: ['--link-to-remote']);
expect(packageGraph.packages, hasLength(3));
var packageOne =
packageGraph.packages.singleWhere((p) => p.name == 'one');
expect(packageOne.documentedWhere, equals(DocumentLocation.missing));
});
test('includes external remote elements when includeExternal is specified',
() async {
packageOneRoot
.getChildAssumingFile('dartdoc_options.yaml')
.writeAsStringSync('''
dartdoc:
includeExternal:
- bin/script.dart
linkTo:
url: 'https://mypub.topdomain/%n%/%v%'
''');
var packageGraph = await utils.bootBasicPackage(
packageTwoRoot.path, packageMetaProvider, packageConfigProvider,
additionalArguments: ['--link-to-remote']);
expect(packageGraph.packages, hasLength(3));
var packageOne =
packageGraph.packages.singleWhere((p) => p.name == 'one');
expect(packageOne.documentedWhere, equals(DocumentLocation.remote));
// TODO(srawlins): Why is there more than one?
var libraryScript =
packageOne.allLibraries.singleWhere((l) => l.name == 'script');
var classScript =
libraryScript.allClasses.singleWhere((c) => c.name == 'Script');
expect(classScript.href,
equals('https://mypub.topdomain/one/0.0.1/script/Script-class.html'));
});
});
group('SDK package', () {
setUp(() {
optionSet.parseArguments([]);
});
test('has proper name and kind', () async {
var packageGraph = await utils.bootBasicPackage(
sdkFolder.path, packageMetaProvider, packageConfigProvider,
additionalArguments: [
'--input',
packageMetaProvider.defaultSdkDir.path,
]);
var sdkPackage = packageGraph.defaultPackage;
expect(sdkPackage.name, equals('Dart'));
expect(sdkPackage.kind, equals('SDK'));
});
test('has a homepage', () async {
var packageGraph = await utils.bootBasicPackage(
sdkFolder.path, packageMetaProvider, packageConfigProvider,
additionalArguments: [
'--input',
packageMetaProvider.defaultSdkDir.path,
]);
var sdkPackage = packageGraph.defaultPackage;
expect(sdkPackage.hasHomepage, isTrue);
expect(sdkPackage.homepage, equals('https://github.com/dart-lang/sdk'));
});
test('has a version', () async {
var packageGraph = await utils.bootBasicPackage(
sdkFolder.path, packageMetaProvider, packageConfigProvider,
additionalArguments: [
'--input',
packageMetaProvider.defaultSdkDir.path,
]);
var sdkPackage = packageGraph.defaultPackage;
expect(sdkPackage.version, isNotNull);
});
test('has a description', () async {
var packageGraph = await utils.bootBasicPackage(
sdkFolder.path, packageMetaProvider, packageConfigProvider,
additionalArguments: [
'--input',
packageMetaProvider.defaultSdkDir.path,
]);
var sdkPackage = packageGraph.defaultPackage;
expect(sdkPackage.documentation, startsWith('Welcome'));
});
test('Pragma is hidden in docs', () async {
var packageGraph = await utils.bootBasicPackage(
sdkFolder.path, packageMetaProvider, packageConfigProvider,
additionalArguments: [
'--input',
packageMetaProvider.defaultSdkDir.path,
]);
var pragmaModelElement = packageGraph.specialClasses[SpecialClass.pragma];
expect(pragmaModelElement.name, equals('pragma'));
});
});
group('using default options', () {
setUp(() {
optionSet.parseArguments([]);
});
test('package with no version has a default version', () async {
projectRoot = utils.writePackage(
packageName, resourceProvider, packageConfigProvider,
pubspecContent: '''
name: $packageName
''');
projectPath = projectRoot.path;
var packageGraph = await utils.bootBasicPackage(
projectPath, packageMetaProvider, packageConfigProvider);
expect(packageGraph.defaultPackage.version, equals('0.0.0-unknown'));
});
test('package with no doc comments has no docs', () async {
projectRoot = utils.writePackage(
packageName, resourceProvider, packageConfigProvider);
projectPath = projectRoot.path;
writeToJoinedPath(['lib', 'a.dart'], '''
// No documentation comment.
int x;
''');
var packageGraph = await utils.bootBasicPackage(
projectPath, packageMetaProvider, packageConfigProvider);
expect(packageGraph.defaultPackage.hasDocumentation, isFalse);
expect(packageGraph.defaultPackage.hasDocumentationFile, isFalse);
expect(packageGraph.defaultPackage.documentationFile, isNull);
expect(packageGraph.defaultPackage.documentation, isNull);
});
test('package with no homepage in the pubspec has no homepage', () async {
projectRoot = utils.writePackage(
packageName, resourceProvider, packageConfigProvider,
pubspecContent: '''
name: $packageName
version: 0.0.1
''');
projectPath = projectRoot.path;
writeToJoinedPath(['lib', 'a.dart'], '''
/// Documentation comment.
int x;
''');
var packageGraph = await utils.bootBasicPackage(
projectPath, packageMetaProvider, packageConfigProvider);
expect(packageGraph.defaultPackage.hasHomepage, isFalse);
});
test('package with no doc comments has no categories', () async {
projectRoot = utils.writePackage(
packageName, resourceProvider, packageConfigProvider);
projectPath = projectRoot.path;
writeToJoinedPath(['lib', 'a.dart'], '''
// No documentation comment.
int x;
''');
var packageGraph = await utils.bootBasicPackage(
projectPath, packageMetaProvider, packageConfigProvider);
expect(packageGraph.localPackages.first.hasCategories, isFalse);
expect(packageGraph.localPackages.first.categories, isEmpty);
});
});
}