Monday, November 5, 2012

Adding to the Dart SDK Test Suite

‹prev | My Chain | next›

While updating my Hipster MVC library, I found that the old style of dartdoc documentation no longer worked. The dartdoc tool is part of the Dart SDK. It parses source code as Markdown, producing very pretty documentation.

The problem is that documentation marked with triple slashes was not formatted correctly. The following commented Dart code is not producing properly formatted documentation:
/// Testing
///     var testing = 'this is source code';
get foo => 'bar';
The most obvious problem is that code samples, introduced by four spaces, are not being formatted as code samples.

After a bit of investigation, I found that the cause is the CommentMap class improperly stripping newlines from triple-slashed comments. Given the above multi-line comment, the CommentMap class was passing a single line to the markdown parser:
Testing     var testing = 'this is source code';
Since it was a single line, markdown was not seeing the indented code line.

Anyhow, given the above precondition, I think that I want the following test for my dartdoc code fix:
main() {
  test('triple slashed comments retain newlines', () {
    Commentmap cm = new CommentMap();
    var comment = cm.find(new FakeSourceLocation());
    expect(comment, equals("Testing\n    var testing = 'this is source code';"));
  });
}
In other words, I very much want that newline character in the expect() statement.

In order for that test to work, I am going to need a bit more setup in dart/sdk/lib/_internal/dartdoc/test/comment_map_test.dart. I start with the license, which appears in all of the tests, the name of the library, and some imports:
// Copyright (c) 2012, 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.

/// Unit tests for comment map.
library commentMapTests;

import 'dart:uri';

import '../lib/mirrors.dart';
import '../../compiler/implementation/scanner/scannerlib.dart' as dart2js;
The imports are taken from the other libraries in the dartdoc test suite, though I do apply some process of elimination to figure out which ones really need to be included.

Next, I need to import the unittest library. Again, I copy the import from other dartdoc tests, comment and all:
// TODO(rnystrom): Better path to unittest.
import '../../../../../pkg/unittest/lib/unittest.dart';
Before submitting a patch back to the Dart maintainers I need to modify that path as I found yesterday.

Finally, I need to pull in the CommentMap class. It is "part" of the dartdoc library (as opposed to a separate library that needs to be imported). So I need to pull it into my test with the part keyword:
// TODO(rnystrom): Use "package:" URL (#4968).
part '../lib/src/dartdoc/comment_map.dart';
Once more, I copy comments from similar statements to (hopefully) increase the likelihood that my patch will be accepted.

The last thing that I need to do is define the FakeSourceLocation class that will be used by the CommentMap. Reading through the CommentMap code, the source location object needs to define the sourceUri, offset, and sourceText properties. For this fake/test class, I define them as:
class FakeSourceLocation implements SourceLocation {
  Uri get sourceUri => new Uri('file:///tmp/test.dart');
  int get offset => 57;
  String get sourceText => """
/// Testing
///     var testing = 'this is source code';
get foo => 'bar';
""";
}
The sourceUri and sourceText are pretty straight-forward. The offset is the number of characters from the start of the string under the source code. In this case, there are 57 characters of comments before the foo getter is reached.

With that, I have my failing test:
➜  dart-sdk git:(master) ✗ ./dart/tools/testing/bin/linux/dart \
  ./dart/sdk/lib/_internal/dartdoc/test/comment_map_test.dart
unittest-suite-wait-for-done
FAIL: triple slashed comments retain newlines
  Expected: 'Testing\n    var testing = 'this is source code';'
       but: was 'Testing    var testing = 'this is source code';'.
  
  #0      DefaultFailureHandler.fail (file:///home/chris/repos/dart-sdk/dart/pkg/unittest/lib/src/expect.dart:86:5)
  #1      DefaultFailureHandler.failMatch (file:///home/chris/repos/dart-sdk/dart/pkg/unittest/lib/src/expect.dart:90:9)
  #2      expect (file:///home/chris/repos/dart-sdk/dart/pkg/unittest/lib/src/expect.dart:55:29)
  #3      main. (file:///home/chris/repos/dart-sdk/dart/sdk/lib/_internal/dartdoc/test/comment_map_test.dart:33:11)
  #4      TestCase.run (file:///home/chris/repos/dart-sdk/dart/pkg/unittest/lib/src/test_case.dart:83:11)
  #5      _nextBatch._nextBatch. (file:///home/chris/repos/dart-sdk/dart/pkg/unittest/lib/unittest.dart:803:19)
  #6      guardAsync (file:///home/chris/repos/dart-sdk/dart/pkg/unittest/lib/unittest.dart:762:19)
  

0 PASSED, 1 FAILED, 0 ERRORS
As expected, my test fails because the mapped comment no longer includes the newline. Without that newline, subsequent markdown processing will not produce the desired, pretty output.

Happily, the fix is easy. I just need to re-add a newline character when building up the triple-slashed comments in CommentMap:
  _parseComments(Source source) {
    // ...
    while (token.kind != dart2js.EOF_TOKEN) {
      if (token.kind == dart2js.COMMENT_TOKEN) {
        // ...
        } else if (text.startsWith('///')) {
          var line = text.substring(3);
          // Allow a leading space.
          if (line.startsWith(' ')) line = line.substring(1);
          if (lastComment == null) {
            lastComment = line;
          } else {
            lastComment = "$lastComment\n$line";
          }
        }
      } else if (token.kind == dart2js.HASH_TOKEN) {
      // ...
    }
  }
With the assembled comments for triple-slashes again including a newline, I have a passing test:
➜  dart-sdk git:(master) ✗ ./dart/tools/testing/bin/linux/dart \
  ./dart/sdk/lib/_internal/dartdoc/test/comment_map_test.dart
unittest-suite-wait-for-done
PASS: triple slashed comments retain newlines

All 1 tests passed.
unittest-suite-success
With that, I feel more confident in submitting a fix. Tomorrow.


Day #561

No comments:

Post a Comment