|  | // Copyright 2020 The Fuchsia Authors. 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'; | 
|  |  | 
|  | import 'package:doc_checker/errors.dart'; | 
|  | import 'package:doc_checker/link_checker.dart'; | 
|  |  | 
|  | import 'package:path/path.dart' as path; | 
|  | import 'package:test/test.dart'; | 
|  |  | 
|  | void main() { | 
|  | LinkChecker checker; | 
|  | final String docsDir = '${Directory.systemTemp.path}/docs'; | 
|  | final String srcDir = '${Directory.systemTemp.path}/src'; | 
|  | const String docsProject = 'fuchsia'; | 
|  |  | 
|  | setUp(() async { | 
|  | checker = LinkChecker(Directory.systemTemp.path, docsDir, docsProject) | 
|  | ..checkLocalLinksOnly = true; | 
|  | }); | 
|  |  | 
|  | tearDown(() async { | 
|  | Directory docsDirectory = Directory(docsDir); | 
|  | Directory srcDirectory = Directory(srcDir); | 
|  | if (docsDirectory.existsSync()) { | 
|  | await docsDirectory.delete(recursive: true); | 
|  | } | 
|  | if (srcDirectory.existsSync()) { | 
|  | await srcDirectory.delete(recursive: true); | 
|  | } | 
|  | }); | 
|  |  | 
|  | group('doc_checker link_checker tests', () { | 
|  | test('invalid uri', () async { | 
|  | const String invalid = 'h!:\\some_crazy//String'; | 
|  |  | 
|  | List<String> links = [invalid]; | 
|  |  | 
|  | List<DocContext> docList = [ | 
|  | DocContext(docsDir, 'some_label', null, links) | 
|  | ]; | 
|  |  | 
|  | bool sawError = await checker.check(docList, [], null); | 
|  | expect(sawError, isTrue); | 
|  | expect(checker.errors, hasLength(1)); | 
|  |  | 
|  | Error error = checker.errors.first; | 
|  | expect(error.type, equals(ErrorType.invalidUri)); | 
|  | }); | 
|  |  | 
|  | test('non_http_link', () async { | 
|  | // check that non http, non-file schemes are ignored. | 
|  | const String maillink = 'mailto://fuchsia@fuchsia.dev'; | 
|  |  | 
|  | // check that an explicit file scheme is checked. | 
|  | String filelink = 'file:///tmp/docs/does-not-exist.md'; | 
|  |  | 
|  | List<String> links = [maillink, filelink]; | 
|  |  | 
|  | List<DocContext> docList = [DocContext(docsDir, 'nothing', null, links)]; | 
|  |  | 
|  | bool sawError = await checker.check(docList, [], null); | 
|  | // mailto should be ignored, no error. | 
|  | // filelink should be broken link error. | 
|  | expect(sawError, isTrue); | 
|  |  | 
|  | expect(checker.errors, hasLength(1)); | 
|  | Error error = checker.errors.first; | 
|  | expect(error.type, equals(ErrorType.brokenLink)); | 
|  | }); | 
|  |  | 
|  | test('link_to_code', () async { | 
|  | const String codelink = | 
|  | 'https://fuchsia.googlesource.com/fuchsia/+/HEAD/src/testing/BUILD.gn'; | 
|  |  | 
|  | List<String> links = [codelink]; | 
|  |  | 
|  | List<DocContext> docList = [DocContext(docsDir, 'BUILD.gn', null, links)]; | 
|  |  | 
|  | bool sawError = await checker.check(docList, [], null); | 
|  | expect(sawError, isTrue); | 
|  |  | 
|  | expect(checker.errors, hasLength(1)); | 
|  | Error error = checker.errors.first; | 
|  | expect(error.type, equals(ErrorType.convertHttpToPath)); | 
|  | }); | 
|  | test('link_to_project', () async { | 
|  | const String codelink = | 
|  | 'https://fuchsia.googlesource.com/topaz/+/HEAD/tools/doc_checker/'; | 
|  |  | 
|  | List<String> links = [codelink]; | 
|  |  | 
|  | List<DocContext> docList = [ | 
|  | DocContext(docsDir, 'doc_checker', null, links) | 
|  | ]; | 
|  |  | 
|  | bool sawError = await checker.check(docList, [], null); | 
|  | expect(sawError, isFalse); | 
|  | }); | 
|  |  | 
|  | test('link_to_unrelated project', () async { | 
|  | const String codelink = 'https://fuchsia.googlesource.com/peridot/'; | 
|  |  | 
|  | List<String> links = [codelink]; | 
|  |  | 
|  | List<DocContext> docList = [DocContext(docsDir, 'peridot', null, links)]; | 
|  |  | 
|  | bool sawError = await checker.check(docList, [], null); | 
|  | expect(sawError, isTrue); | 
|  |  | 
|  | expect(checker.errors, hasLength(1)); | 
|  | Error error = checker.errors.first; | 
|  | expect(error.type, equals(ErrorType.obsoleteProject)); | 
|  | }); | 
|  |  | 
|  | test('link_to_devsite', () async { | 
|  | const String codelink = | 
|  | 'https://fuchsia.dev/fuchsia-src/development/monitor/fidlcat'; | 
|  |  | 
|  | // These are exceptions to the rule. | 
|  | // Links to the home page are OK | 
|  | const String rootlink = 'https://fuchsia.dev'; | 
|  | // Links to the reference section are OK. | 
|  | const String referencelink = 'https://fuchsia.dev/reference/something'; | 
|  |  | 
|  | // navbar.md can link to anywhere | 
|  | const navbar = 'navbar.md'; | 
|  |  | 
|  | List<String> links = [codelink, rootlink, referencelink]; | 
|  |  | 
|  | List<DocContext> docList = [ | 
|  | DocContext(docsDir, 'randompage', null, links), | 
|  | DocContext(docsDir, navbar, null, links) | 
|  | ]; | 
|  |  | 
|  | bool sawError = await checker.check(docList, [], null); | 
|  | expect(sawError, isTrue); | 
|  |  | 
|  | expect(checker.errors, hasLength(1)); | 
|  | Error error = checker.errors.first; | 
|  | expect(error.type, equals(ErrorType.convertHttpToPath)); | 
|  | }); | 
|  | test('link_to_external sites', () async { | 
|  | const String codelink = 'https://github.com/google/fonts'; | 
|  | const String codelinkWithAnchor = | 
|  | 'https://github.com/google/fonts#licensing'; | 
|  |  | 
|  | List<String> links = [codelink, codelinkWithAnchor]; | 
|  |  | 
|  | List<DocContext> docList = [ | 
|  | DocContext(docsDir, 'randompage', null, links) | 
|  | ]; | 
|  |  | 
|  | bool sawError = await checker.check(docList, [], null); | 
|  | expect(sawError, isFalse); | 
|  | }); | 
|  | test('relative file link', () async { | 
|  | List<String> links = [ | 
|  | '/docs/page1.md', | 
|  | 'page1.md#topic', | 
|  | 'relative/page2.md', | 
|  | 'missing_page.md', | 
|  | '/src/project/main.cc', | 
|  | '#Heading2' | 
|  | ]; | 
|  |  | 
|  | List<DocContext> docList = [ | 
|  | DocContext(docsDir, 'randompage', null, links) | 
|  | ]; | 
|  |  | 
|  | File('$docsDir/page1.md') | 
|  | ..createSync(recursive: true) | 
|  | ..writeAsStringSync('# Page 1\nSome text\n\n ##Topic\n\nTopic info\n'); | 
|  |  | 
|  | File('$docsDir/relative/page2.md') | 
|  | ..createSync(recursive: true) | 
|  | ..writeAsStringSync('# Page 1'); | 
|  |  | 
|  | File('$srcDir/project/main.cc') | 
|  | ..createSync(recursive: true) | 
|  | ..writeAsStringSync('print "hello world";\n'); | 
|  |  | 
|  | bool sawError = await checker.check(docList, [], null); | 
|  | expect(sawError, isTrue); | 
|  |  | 
|  | expect(checker.errors, hasLength(1)); | 
|  | Error error = checker.errors.first; | 
|  | expect(error.type, equals(ErrorType.brokenLink)); | 
|  | }); | 
|  |  | 
|  | test('relative paths', () async { | 
|  | String pageLabel = '//docs/somewhere/index.md'; | 
|  | List<String> links = [ | 
|  | '../page1.md', | 
|  | '../../src/project/main.cc', | 
|  | '/one/two/three/../../../../../../' | 
|  | ]; | 
|  |  | 
|  | File('$docsDir/page1.md') | 
|  | ..createSync(recursive: true) | 
|  | ..writeAsStringSync('# Page 1\nSome text\n\n ##Topic\n\nTopic info\n'); | 
|  |  | 
|  | File('$srcDir/project/main.cc') | 
|  | ..createSync(recursive: true) | 
|  | ..writeAsStringSync('print "hello world";\n'); | 
|  |  | 
|  | List<DocContext> docList = [ | 
|  | DocContext(path.join(docsDir, 'somewhere'), pageLabel, null, links) | 
|  | ]; | 
|  |  | 
|  | bool sawError = await checker.check(docList, [], null); | 
|  | expect(sawError, isTrue); | 
|  |  | 
|  | expect(checker.errors, hasLength(2)); | 
|  | Error error = checker.errors.first; | 
|  | expect(error.type, equals(ErrorType.invalidRelativePath)); | 
|  | error = checker.errors.last; | 
|  | expect(error.type, equals(ErrorType.invalidRelativePath)); | 
|  | }); | 
|  |  | 
|  | test('uri to docs', () async { | 
|  | List<String> links = [ | 
|  | // This should be an error, use /docs/... | 
|  | 'https://fuchsia.googlesource.com/fuchsia/+/HEAD/docs/README.md', | 
|  | // This should be OK, since it goes to owners | 
|  | 'https://fuchsia.googlesource.com/fuchsia/+/HEAD/docs/some/path/OWNERS' | 
|  | ]; | 
|  |  | 
|  | String pageLabel = '//docs/somewhere/index.md'; | 
|  | List<DocContext> docList = [ | 
|  | DocContext(path.join(docsDir, 'somewhere'), pageLabel, null, links) | 
|  | ]; | 
|  |  | 
|  | bool sawError = await checker.check(docList, [], null); | 
|  | expect(sawError, isTrue); | 
|  |  | 
|  | expect(checker.errors, hasLength(1)); | 
|  | for (Error error in checker.errors) { | 
|  | expect(error.type, equals(ErrorType.convertHttpToPath)); | 
|  | } | 
|  | }); | 
|  |  | 
|  | test('link to directory', () async { | 
|  | String pageLabel = '//docs/somewhere/index.md'; | 
|  | List<String> links = [ | 
|  | // This is OK - since there is /docs/README.md | 
|  | '/docs/', | 
|  | // This is OK - there is a README.md | 
|  | '/docs/folder', | 
|  | // This is OK - it is to a directory that is not under /docs/ | 
|  | '/src/project', | 
|  | // This is an error - there is not a README.md file. | 
|  | '/docs/noreadme_folder/' | 
|  | ]; | 
|  |  | 
|  | File('$docsDir/README.md') | 
|  | ..createSync(recursive: true) | 
|  | ..writeAsStringSync('# Readme file\n'); | 
|  |  | 
|  | File('$docsDir/folder/README.md') | 
|  | ..createSync(recursive: true) | 
|  | ..writeAsStringSync('# index file in a directory.\n'); | 
|  |  | 
|  | File('$docsDir/noreadme_folder/anypage.md') | 
|  | ..createSync(recursive: true) | 
|  | ..writeAsStringSync('# No readme here.\n'); | 
|  |  | 
|  | File('$srcDir/project/main.cc') | 
|  | ..createSync(recursive: true) | 
|  | ..writeAsStringSync('print "hello world";\n'); | 
|  |  | 
|  | List<DocContext> docList = [ | 
|  | DocContext(path.join(docsDir, 'somewhere'), pageLabel, null, links) | 
|  | ]; | 
|  |  | 
|  | bool sawError = await checker.check(docList, [], null); | 
|  | expect(sawError, isTrue); | 
|  |  | 
|  | expect(checker.errors, hasLength(1)); | 
|  | for (Error error in checker.errors) { | 
|  | expect(error.type, equals(ErrorType.invalidLinkToDirectory)); | 
|  | } | 
|  | }); | 
|  | }); | 
|  | } |