diff --git a/.gitignore b/.gitignore index 9ffaa82e1c8b5..2a9084d1d9f49 100644 --- a/.gitignore +++ b/.gitignore @@ -109,3 +109,5 @@ version.texi no_llvm_build +**node_modules/ +**doc-ui/.lock diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index dc0b0aaf0bb3c..cf83fae4d75ba 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -421,6 +421,7 @@ impl<'a> Builder<'a> { test::Clippy, test::RustdocJS, test::RustdocTheme, + test::DocUI, // Run bootstrap close to the end as it's unlikely to fail test::Bootstrap, // Run run-make last, since these won't pass without make on Windows diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index c86010379f495..8cbee8833765c 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -584,6 +584,70 @@ impl Step for RustdocJS { } } +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct DocUI { + pub host: Interned, + pub target: Interned, +} + +impl Step for DocUI { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("src/test/doc-ui") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(DocUI { + host: run.host, + target: run.target, + }); + } + + fn run(self, builder: &Builder) { + if let Some(ref nodejs) = builder.config.nodejs { + let mut found_puppeteer = false; + // Check if puppeteer is installed locally. + if let Ok(output) = Command::new("npm") + .args(&["ls", "puppeteer", "puppeteer-core"]) + .current_dir("src/tools/doc-ui") + .output() { + found_puppeteer = String::from_utf8_lossy(&output.stdout).contains("puppeteer"); + } + if !found_puppeteer { + // Check if puppeteer is installed "globally". + if let Ok(output) = Command::new("npm") + .args(&["ls", "-g", "puppeteer", "puppeteer-core"]) + .output() { + found_puppeteer = String::from_utf8_lossy(&output.stdout).contains("puppeteer"); + } + } + if !found_puppeteer { + let mut command = Command::new(nodejs); + command.args(&["src/tools/doc-ui/script.js", + &*self.host, + &builder.top_stage.to_string()]); + builder.ensure(::doc::Std { + target: self.target, + stage: builder.top_stage, + }); + builder.run(&mut command); + } else { + builder.info(&format!( + "No puppeteer found (maybe try installing it with `npm install puppeteer`?), \ + skipping \"src/test/doc-ui\" tests" + )); + } + } else { + builder.info(&format!( + "No nodejs found, skipping \"src/test/doc-ui\" tests" + )); + } + } +} + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct RustdocUi { pub host: Interned, diff --git a/src/test/doc-ui/images/struct-syntax.png b/src/test/doc-ui/images/struct-syntax.png new file mode 100644 index 0000000000000..a7c59f5cc9e7f Binary files /dev/null and b/src/test/doc-ui/images/struct-syntax.png differ diff --git a/src/test/doc-ui/lib/lib.rs b/src/test/doc-ui/lib/lib.rs new file mode 100644 index 0000000000000..653de7eec0236 --- /dev/null +++ b/src/test/doc-ui/lib/lib.rs @@ -0,0 +1,14 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub struct Foo { + pub damn: u32, + pub foo: Option, +} diff --git a/src/test/doc-ui/struct-syntax.js b/src/test/doc-ui/struct-syntax.js new file mode 100644 index 0000000000000..10b89194a6b5b --- /dev/null +++ b/src/test/doc-ui/struct-syntax.js @@ -0,0 +1,13 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +var TEST = { + "path": "struct.Foo.html", +}; diff --git a/src/tools/doc-ui/package-lock.json b/src/tools/doc-ui/package-lock.json new file mode 100644 index 0000000000000..a7c543c3666f6 --- /dev/null +++ b/src/tools/doc-ui/package-lock.json @@ -0,0 +1,305 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "es6-promise": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", + "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==" + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "^4.0.3" + } + }, + "extract-zip": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz", + "integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=", + "requires": { + "concat-stream": "1.6.2", + "debug": "2.6.9", + "mkdirp": "0.5.1", + "yauzl": "2.4.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "fd-slicer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "requires": { + "pend": "~1.2.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "https-proxy-agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "requires": { + "agent-base": "^4.1.0", + "debug": "^3.1.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "mime": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.3.1.tgz", + "integrity": "sha512-OEUllcVoydBHGN1z84yfQDimn58pZNNNXgZlHXSboxMlFvgI6MXSWpWKpFRra7H1HxpVhHTkrghfRW49k6yjeg==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, + "png-js": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/png-js/-/png-js-0.1.1.tgz", + "integrity": "sha1-HMfCEjA6yr50Jj7DrHgAlYAkLZM=" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + }, + "progress": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", + "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=" + }, + "proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=" + }, + "puppeteer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.7.0.tgz", + "integrity": "sha512-f+1DxKHPqce6CXUBz2eVO2WcATeVeQSOPG9GYaGObEZDCiCEUwG+gogjMsrvn7he2wHTqNVb5p6RUrwmr8XFBA==", + "requires": { + "debug": "^3.1.0", + "extract-zip": "^1.6.6", + "https-proxy-agent": "^2.2.1", + "mime": "^2.0.3", + "progress": "^2.0.0", + "proxy-from-env": "^1.0.0", + "rimraf": "^2.6.1", + "ws": "^5.1.1" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "requires": { + "glob": "^7.0.5" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "requires": { + "async-limiter": "~1.0.0" + } + }, + "yauzl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", + "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", + "requires": { + "fd-slicer": "~1.0.1" + } + } + } +} diff --git a/src/tools/doc-ui/script.js b/src/tools/doc-ui/script.js new file mode 100644 index 0000000000000..e4f3ce23a4c0b --- /dev/null +++ b/src/tools/doc-ui/script.js @@ -0,0 +1,142 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const puppeteer = require('puppeteer'); +const fs = require('fs'); +const execFileSync = require('child_process').execFileSync; +const PNG = require('png-js'); + +const TEST_FOLDER = 'src/test/doc-ui/'; + + +function loadContent(content) { + var Module = module.constructor; + var m = new Module(); + m._compile(content, "tmp.js"); + return m.exports; +} + +function readFile(filePath) { + return fs.readFileSync(filePath, 'utf8'); +} + +function comparePixels(img1, img2) { + return img1.equals(img2); +} + +function main(argv) { + /*if (argv.length !== 4) { + console.error("Expected 2 arguments, received " + (argv.length - 2) + ":"); + console.error(" - first argument : toolchain to check as argument (for example " + + "'x86_64-apple-darwin')"); + console.error(" - second argument: browser path (chrome or chromium)"); + process.exitCode = 1; // exiting + }*/ + var toolchain = argv[2]; + var stage = argv[3]; + + if (stage != "0" && stage != "1" && stage != "2") { + console.error("second argument (stage) should be either '0', '1' or '2'"); + process.exitCode = 1; // exiting + } + + var browserPath = undefined; + + if (argv.length > 4) { + browserPath = argv[4]; + try { + fs.accessSync(browserPath, fs.constants.X_OK); + } catch (err) { + console.error('"' + browserPath + '" is not executable! Aborting.'); + process.exitCode = 2; // exiting + } + } + + var outPath = "build/" + toolchain + "/stage" + stage; + execFileSync(outPath + "/bin/rustdoc", + ["src/test/doc-ui/lib/lib.rs", "-o", outPath + "/doc-ui"], {}, + function(error, stdout, stderr) { + if (error) { + console.error(error); + process.exitCode = 1; // exiting + } + }); + + var imageFolder = outPath + "/doc-ui/images/"; + fs.mkdir(imageFolder, function() {}); + + console.log("=> Starting doc-ui tests..."); + + var loaded = []; + var failures = 0; + var output = []; + fs.readdirSync(TEST_FOLDER).forEach(function(file) { + var fullPath = TEST_FOLDER + file; + if (file.endsWith(".js") && fs.lstatSync(fullPath).isFile()) { + var content = readFile(fullPath) + 'exports.TEST = TEST;'; + loaded.push([file, loadContent(content).TEST]); + } + }); + + puppeteer.launch({executablePath: browserPath}).then(async browser => { + var docPath = 'file://' + process.cwd() + '/' + outPath + '/doc-ui/lib/'; + for (var i = 0; i < loaded.length; ++i) { + process.stdout.write(loaded[i][0] + "... "); + try { + if (!('path' in loaded[i][1])) { + failures += 1; + console.log('FAILED (missing "path" key from test file)'); + continue; + } + if (typeof loaded[i][1]['path'] !== "string" || loaded[i][1]['path'].length < 1) { + failures += 1; + console.log('FAILED (invalid "path" key from test file)'); + continue; + } + const page = await browser.newPage(); + await page.goto(docPath + loaded[i][1]['path']); + await page.waitFor(5000); + var newImage = imageFolder + loaded[i][0].replace(".js", ".png"); + await page.screenshot({ + path: newImage, + fullPage: true, + }); + var originalImage = TEST_FOLDER + "images/" + loaded[i][0].replace(".js", ".png"); + if (fs.existsSync(originalImage) === false) { + console.log('ignored ("' + originalImage + '" not found)'); + continue; + } + if (comparePixels(PNG.load(newImage).imgData, + PNG.load(originalImage).imgData) === false) { + failures += 1; + console.log('FAILED (images "' + newImage + '" and "' + originalImage + + '" are different)'); + continue; + } + } catch (err) { + failures += 1; + console.log("FAILED"); + output.push(loaded[i][0] + " output:\n" + err + '\n'); + continue; + } + console.log("ok"); + } + if (failures > 0) { + console.log("\n=== ERROR OUTPUT ===\n"); + console.log(output.join("\n")); + } + await browser.close(); + console.log("<= doc-ui tests done: " + (loaded.length - failures) + " succeeded, " + + failures + " failed"); + process.exitCode = failures; // exiting + }); +} + +main(process.argv); diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index c8ce4cf8bb5be..f693570c90805 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -216,7 +216,8 @@ function lookForEntry(entry, data) { function main(argv) { if (argv.length !== 3) { - console.error("Expected toolchain to check as argument (for example 'x86_64-apple-darwin'"); + console.error("Expected toolchain to check as argument (for example " + + "'x86_64-apple-darwin')"); return 1; } var toolchain = argv[2];