From edcbf7e89881f88447de2a0280111a21b6c67226 Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Sat, 8 Aug 2020 00:05:16 -0700 Subject: [PATCH 1/4] Preserve newline following `{@endtemplate}`. Additionally introduce (some of?) the first unit tests. These live in test/unit/ for now. This includes a new dev dependency on mockito. --- lib/src/model/comment_processable.dart | 11 +- lib/src/model/model.dart | 1 + pubspec.yaml | 1 + test/README.md | 10 ++ test/unit/comment_processable_test.dart | 191 ++++++++++++++++++++++++ 5 files changed, 209 insertions(+), 5 deletions(-) create mode 100644 test/README.md create mode 100644 test/unit/comment_processable_test.dart diff --git a/lib/src/model/comment_processable.dart b/lib/src/model/comment_processable.dart index 3c8902c3e1..9d555358de 100644 --- a/lib/src/model/comment_processable.dart +++ b/lib/src/model/comment_processable.dart @@ -11,7 +11,7 @@ import 'package:dartdoc/src/warnings.dart'; import 'package:path/path.dart' as path; final _templatePattern = RegExp( - r'[ ]*{@template\s+(.+?)}([\s\S]+?){@endtemplate}[ ]*\n?', + r'[ ]*{@template\s+(.+?)}([\s\S]+?){@endtemplate}[ ]*(\n?)', multiLine: true); final _htmlPattern = RegExp( r'[ ]*{@inject-html\s*}([\s\S]+?){@end-inject-html}[ ]*\n?', @@ -366,9 +366,6 @@ mixin CommentProcessable on Documentable, Warnable, Locatable, SourceCodeMixin { /// The width and height must be integers specifying the dimensions of the /// video file in pixels. String _injectAnimations(String rawDocs) { - // Make sure we have a set to keep track of used IDs for this href. - package.usedAnimationIdsByHref[href] ??= {}; - String getUniqueId(String base) { var animationIdCount = 1; var id = '$base$animationIdCount'; @@ -382,6 +379,9 @@ mixin CommentProcessable on Documentable, Warnable, Locatable, SourceCodeMixin { } return rawDocs.replaceAllMapped(_basicAnimationPattern, (basicMatch) { + // Make sure we have a set to keep track of used IDs for this href. + package.usedAnimationIdsByHref[href] ??= {}; + var parser = ArgParser(); parser.addOption('id'); var args = _parseArgs(basicMatch[1], parser, 'animation'); @@ -481,8 +481,9 @@ mixin CommentProcessable on Documentable, Warnable, Locatable, SourceCodeMixin { return rawDocs.replaceAllMapped(_templatePattern, (match) { var name = match[1].trim(); var content = match[2].trim(); + var trailingNewline = match[3]; packageGraph.addMacro(name, content); - return '{@macro $name}'; + return '{@macro $name}$trailingNewline'; }); } diff --git a/lib/src/model/model.dart b/lib/src/model/model.dart index c9138b5187..ff2db0553e 100644 --- a/lib/src/model/model.dart +++ b/lib/src/model/model.dart @@ -7,6 +7,7 @@ export 'canonicalization.dart'; export 'categorization.dart'; export 'category.dart'; export 'class.dart'; +export 'comment_processable.dart'; export 'constructor.dart'; export 'container.dart'; export 'container_member.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 37410c083e..26d37c0347 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,6 +40,7 @@ dev_dependencies: grinder: ^0.8.2 io: ^0.3.0 http: ^0.12.0 + mockito: ^4.1.1 pedantic: ^1.9.0 test: ^1.3.0 diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000000..9381b83e89 --- /dev/null +++ b/test/README.md @@ -0,0 +1,10 @@ +# Tests + +Most of dartdoc's tests are large end-to-end tests which read real files in +real packages, in the `testing/` directory. Unit tests exist in `test/unit/`. + +Many of the end-to-end test cases should be rewritten as unit tests. + +At some point, the distinction should flip, such that unit tests are generally +located in `test/`, and end-to-end tests are found in a specific directory, or +in files whose names signify the distinction. diff --git a/test/unit/comment_processable_test.dart b/test/unit/comment_processable_test.dart new file mode 100644 index 0000000000..c230734350 --- /dev/null +++ b/test/unit/comment_processable_test.dart @@ -0,0 +1,191 @@ +import 'dart:io' show Directory; + +import 'package:dartdoc/src/dartdoc_options.dart'; +import 'package:dartdoc/src/model/model.dart'; +import 'package:dartdoc/src/package_meta.dart'; +import 'package:dartdoc/src/warnings.dart'; +import 'package:mockito/mockito.dart'; +import 'package:test/test.dart'; + +void main() { + _Processor processor; + setUp(() { + processor = _Processor(_FakeDartdocOptionContext()); + processor.href = '/project/a.dart'; + }); + + test('removes triple slashes', () async { + var doc = await processor.processComment(''' +/// Text. +/// More text. +'''); + expect(doc, equals(''' +Text. +More text.''')); + }); + + test('removes space after triple slashes', () async { + var doc = await processor.processComment(''' +/// Text. +/// More text. +'''); + // TODO(srawlins): Actually, the three spaces before 'More' is perhaps not + // the best fit. Should it only be two, to match the indent from the first + // line's "Text"? + expect(doc, equals(''' +Text. + More text.''')); + }); + + test('leaves blank lines', () async { + var doc = await processor.processComment(''' +/// Text. +/// +/// More text. +'''); + expect(doc, equals(''' +Text. + +More text.''')); + }); + + test('processes @template', () async { + var doc = await processor.processComment(''' +/// Text. +/// +/// {@template abc} +/// Template text. +/// {@endtemplate} +/// +/// End text. +'''); + expect(doc, equals(''' +Text. + +{@macro abc} + +End text.''')); + verify(processor.packageGraph.addMacro('abc', 'Template text.')).called(1); + }); + + test('processes leading @template', () async { + var doc = await processor.processComment(''' +/// {@template abc} +/// Template text. +/// {@endtemplate} +/// +/// End text. +'''); + expect(doc, equals(''' +{@macro abc} + +End text.''')); + verify(processor.packageGraph.addMacro('abc', 'Template text.')).called(1); + }); + + test('processes trailing @template', () async { + var doc = await processor.processComment(''' +/// Text. +/// +/// {@template abc} +/// Template text. +/// {@endtemplate} +'''); + expect(doc, equals(''' +Text. + +{@macro abc}''')); + verify(processor.packageGraph.addMacro('abc', 'Template text.')).called(1); + }); + + test('processes @template w/o blank line following', () async { + var doc = await processor.processComment(''' +/// Text. +/// +/// {@template abc} +/// Template text. +/// {@endtemplate} +/// End text. +'''); + expect(doc, equals(''' +Text. + +{@macro abc} +End text.''')); + verify(processor.packageGraph.addMacro('abc', 'Template text.')).called(1); + }); + + test('allows whitespace around @template name', () async { + var doc = await processor.processComment(''' +/// {@template abc } +/// Template text. +/// {@endtemplate} +'''); + expect(doc, equals(''' +{@macro abc}''')); + verify(processor.packageGraph.addMacro('abc', 'Template text.')).called(1); + }); + + // TODO(srawlins): More unit tests: @video, @youtube, @animation, + // @inject-html, @tool. +} + +/// In order to mix in [CommentProcessable], we must first implement +/// the super-class constraints. +abstract class __Processor extends Fake + implements Documentable, Warnable, Locatable, SourceCodeMixin {} + +/// A simple comment processor. +class _Processor extends __Processor with CommentProcessable { + @override + final _FakeDartdocOptionContext config; + + @override + final _FakePackage package; + + @override + final _MockPackageGraph packageGraph; + + @override + String href; + + _Processor(this.config) + : package = _FakePackage(), + packageGraph = _MockPackageGraph() { + throwOnMissingStub(packageGraph); + when(packageGraph.addMacro(any, any)).thenReturn(null); + } +} + +class _FakeDirectory extends Fake implements Directory { + @override + final String path; + + _FakeDirectory() : path = '/project'; +} + +class _FakePackage extends Fake implements Package { + @override + final PackageMeta packageMeta; + + _FakePackage() : packageMeta = _FakePackageMeta(); +} + +class _FakePackageMeta extends Fake implements PackageMeta { + @override + final Directory dir; + + _FakePackageMeta() : dir = _FakeDirectory(); +} + +class _FakeDartdocOptionContext extends Fake implements DartdocOptionContext { + @override + final bool allowTools; + + @override + final bool injectHtml; + + _FakeDartdocOptionContext({this.allowTools = false, this.injectHtml = false}); +} + +class _MockPackageGraph extends Mock implements PackageGraph {} From 05c789aff898d3bb247aaf90cc129360674c43b3 Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Sat, 8 Aug 2020 06:46:45 -0700 Subject: [PATCH 2/4] fix test; debugging in flutter dartdoc --- test/model_test.dart | 2 +- test/src/utils.dart | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/test/model_test.dart b/test/model_test.dart index 90baabe686..8d28201bb3 100644 --- a/test/model_test.dart +++ b/test/model_test.dart @@ -719,7 +719,7 @@ void main() { test("renders a macro within the same comment where it's defined", () { expect(withMacro.documentation, - equals('Macro method\n\nFoo macro content\nMore docs')); + equals('Macro method\n\nFoo macro content\n\nMore docs')); }); test("renders a macro in another method, not the same where it's defined", diff --git a/test/src/utils.dart b/test/src/utils.dart index 2099295825..5d48d055be 100644 --- a/test/src/utils.dart +++ b/test/src/utils.dart @@ -384,8 +384,12 @@ class SubprocessLauncher { var exitCode = await process.exitCode; if (exitCode != 0) { - throw ProcessException(executable, arguments, - 'SubprocessLauncher got non-zero exitCode: $exitCode', exitCode); + throw ProcessException( + executable, + arguments, + 'SubprocessLauncher got non-zero exitCode: $exitCode\n\n' + 'stdout: ${process.stdout}\n\nstderr: ${process.stderr}', + exitCode); } return jsonObjects; } From 87ea181469f908d9426ca62f89fd91b0fe4b5d76 Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Sat, 8 Aug 2020 20:57:00 -0700 Subject: [PATCH 3/4] small changes --- test/unit/comment_processable_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/comment_processable_test.dart b/test/unit/comment_processable_test.dart index c230734350..db7dd1255c 100644 --- a/test/unit/comment_processable_test.dart +++ b/test/unit/comment_processable_test.dart @@ -126,7 +126,7 @@ End text.''')); verify(processor.packageGraph.addMacro('abc', 'Template text.')).called(1); }); - // TODO(srawlins): More unit tests: @video, @youtube, @animation, + // TODO(srawlins): More unit tests: @example, @youtube, @animation, // @inject-html, @tool. } @@ -135,7 +135,7 @@ End text.''')); abstract class __Processor extends Fake implements Documentable, Warnable, Locatable, SourceCodeMixin {} -/// A simple comment processor. +/// A simple comment processor for testing [CommentProcessable]. class _Processor extends __Processor with CommentProcessable { @override final _FakeDartdocOptionContext config; From 64bf47ed532f7ce5403807c15c16e451b659e7f2 Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Mon, 10 Aug 2020 20:59:51 -0700 Subject: [PATCH 4/4] Copyright --- test/unit/comment_processable_test.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/unit/comment_processable_test.dart b/test/unit/comment_processable_test.dart index db7dd1255c..de4b607ade 100644 --- a/test/unit/comment_processable_test.dart +++ b/test/unit/comment_processable_test.dart @@ -1,3 +1,7 @@ +// 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 'dart:io' show Directory; import 'package:dartdoc/src/dartdoc_options.dart';