| // 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/model/indexable.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() { |
| late MemoryResourceProvider resourceProvider; |
| late PackageMetaProvider packageMetaProvider; |
| late FakePackageConfigProvider packageConfigProvider; |
| late DartdocOptionSet optionSet; |
| late Folder sdkFolder; |
| |
| late Folder projectRoot; |
| late 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 as MemoryResourceProvider; |
| sdkFolder = packageMetaProvider.defaultSdkDir; |
| |
| optionSet = DartdocOptionRoot.fromOptionGenerators( |
| 'dartdoc', [createDartdocOptions], packageMetaProvider); |
| packageConfigProvider = utils.getTestPackageConfigProvider(sdkFolder.path); |
| }); |
| |
| tearDown(clearPackageMetaCache); |
| |
| group('tests', () { |
| 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(Kind.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.named('dart:_internal'); |
| |
| 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.named('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.packageMeta.getReadmeContents(), |
| isNotNull); |
| 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.packageMeta.getReadmeContents(), |
| isNotNull); |
| 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', () { |
| late Folder packageOneRoot; |
| late 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.named('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.named('script'); |
| var classScript = libraryScript.allClasses.named('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(Kind.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.packageMeta.getReadmeContents(), |
| 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); |
| }); |
| }); |
| }, onPlatform: {'windows': Skip('Test does not work on Windows (#2446)')}); |
| } |