From 51580d46f919c1f97d82aeca1ea1086c545c7484 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 26 Jan 2018 00:44:52 +0100 Subject: [PATCH] Add tests for themes --- src/bootstrap/builder.rs | 2 +- src/bootstrap/check.rs | 1 - src/bootstrap/test.rs | 42 ++++++++++++++++++ src/librustdoc/lib.rs | 8 ++-- src/librustdoc/theme.rs | 58 +++++++++++++++++-------- src/tools/rustdoc-themes/test-themes.py | 52 ++++++++++++++++++++++ 6 files changed, 138 insertions(+), 25 deletions(-) create mode 100644 src/tools/rustdoc-themes/test-themes.py diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index bf7b1015a492..6c68ee18506b 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -258,7 +258,7 @@ impl<'a> Builder<'a> { test::HostCompiletest, test::Crate, test::CrateLibrustc, test::Rustdoc, test::Linkcheck, test::Cargotest, test::Cargo, test::Rls, test::Docs, test::ErrorIndex, test::Distcheck, test::Rustfmt, test::Miri, test::Clippy, - test::RustdocJS), + test::RustdocJS, test::RustdocTheme), Kind::Bench => describe!(test::Crate, test::CrateLibrustc), Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook, doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex, doc::Nomicon, diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index e6871764b2c7..ede403491d7f 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -160,4 +160,3 @@ pub fn libtest_stamp(build: &Build, compiler: Compiler, target: Interned pub fn librustc_stamp(build: &Build, compiler: Compiler, target: Interned) -> PathBuf { build.cargo_out(compiler, Mode::Librustc, target).join(".librustc-check.stamp") } - diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index e4c1cdb79fd2..1c6cd066ad99 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -424,6 +424,48 @@ fn path_for_cargo(builder: &Builder, compiler: Compiler) -> OsString { env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect("") } +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct RustdocTheme { + pub compiler: Compiler, + pub host: Interned, +} + +impl Step for RustdocTheme { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("src/tools/rustdoc-themes") + } + + fn make_run(run: RunConfig) { + let compiler = run.builder.compiler(run.builder.top_stage, run.host); + + run.builder.ensure(RustdocTheme { + compiler: compiler, + host: run.builder.build.build, + }); + } + + fn run(self, builder: &Builder) { + let rustdoc = builder.rustdoc(self.compiler.host); + let mut cmd = Command::new(builder.config.python.clone().expect("python not defined")); + cmd.args(&["src/tools/rustdoc-themes/test-themes.py", rustdoc.to_str().unwrap()]); + cmd.env("RUSTC_STAGE", self.compiler.stage.to_string()) + .env("RUSTC_SYSROOT", builder.sysroot(self.compiler)) + .env("RUSTDOC_LIBDIR", builder.sysroot_libdir(self.compiler, self.compiler.host)) + .env("CFG_RELEASE_CHANNEL", &builder.build.config.channel) + .env("RUSTDOC_REAL", builder.rustdoc(self.host)) + .env("RUSTDOC_CRATE_VERSION", builder.build.rust_version()) + .env("RUSTC_BOOTSTRAP", "1"); + if let Some(linker) = builder.build.linker(self.host) { + cmd.env("RUSTC_TARGET_LINKER", linker); + } + builder.run(&mut cmd); + } +} + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct RustdocJS { pub host: Interned, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index c08cff988924..17cf2b7349b2 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -324,13 +324,13 @@ pub fn main_args(args: &[String]) -> isize { let to_check = matches.opt_strs("theme-checker"); if !to_check.is_empty() { - let pathes = theme::load_css_pathes(include_bytes!("html/static/themes/main.css")); + let paths = theme::load_css_paths(include_bytes!("html/static/themes/main.css")); let mut errors = 0; println!("rustdoc: [theme-checker] Starting tests!"); for theme_file in to_check.iter() { print!(" - Checking \"{}\"...", theme_file); - let (success, differences) = theme::test_theme_against(theme_file, &pathes); + let (success, differences) = theme::test_theme_against(theme_file, &paths); if !differences.is_empty() || !success { eprintln!(" FAILED"); errors += 1; @@ -401,7 +401,7 @@ pub fn main_args(args: &[String]) -> isize { let mut themes = Vec::new(); if matches.opt_present("themes") { - let pathes = theme::load_css_pathes(include_bytes!("html/static/themes/main.css")); + let paths = theme::load_css_paths(include_bytes!("html/static/themes/main.css")); for (theme_file, theme_s) in matches.opt_strs("themes") .iter() @@ -410,7 +410,7 @@ pub fn main_args(args: &[String]) -> isize { eprintln!("rustdoc: option --themes arguments must all be files"); return 1; } - let (success, ret) = theme::test_theme_against(&theme_file, &pathes); + let (success, ret) = theme::test_theme_against(&theme_file, &paths); if !success || !ret.is_empty() { eprintln!("rustdoc: invalid theme: \"{}\"", theme_s); eprintln!(" Check what's wrong with the \"theme-checker\" option"); diff --git a/src/librustdoc/theme.rs b/src/librustdoc/theme.rs index fe7538780412..39c9a6e2aa40 100644 --- a/src/librustdoc/theme.rs +++ b/src/librustdoc/theme.rs @@ -170,18 +170,24 @@ fn get_useful_next(events: &[Events], pos: &mut usize) -> Option { fn get_previous_positions(events: &[Events], mut pos: usize) -> Vec { let mut ret = Vec::with_capacity(3); - ret.push(events[pos].get_pos() - 1); + ret.push(events[pos].get_pos()); if pos > 0 { pos -= 1; } loop { - ret.push(events[pos].get_pos()); if pos < 1 || !events[pos].is_comment() { + let x = events[pos].get_pos(); + if *ret.last().unwrap() != x { + ret.push(x); + } else { + ret.push(0); + } break } + ret.push(events[pos].get_pos()); pos -= 1; } - if events[pos].is_comment() { + if ret.len() & 1 != 0 && events[pos].is_comment() { ret.push(0); } ret.iter().rev().cloned().collect() @@ -189,14 +195,22 @@ fn get_previous_positions(events: &[Events], mut pos: usize) -> Vec { fn build_rule(v: &[u8], positions: &[usize]) -> String { positions.chunks(2) - .map(|x| ::std::str::from_utf8(&v[x[0]..x[1]]).unwrap_or("").to_owned()) + .map(|x| ::std::str::from_utf8(&v[x[0]..x[1]]).unwrap_or("")) .collect::() .trim() .replace("\n", " ") + .replace("/", "") + .replace("\t", " ") + .replace("{", "") + .replace("}", "") + .split(" ") + .filter(|s| s.len() > 0) + .collect::>() + .join(" ") } fn inner(v: &[u8], events: &[Events], pos: &mut usize) -> HashSet { - let mut pathes = Vec::with_capacity(50); + let mut paths = Vec::with_capacity(50); while *pos < events.len() { if let Some(Events::OutBlock(_)) = get_useful_next(events, pos) { @@ -204,11 +218,11 @@ fn inner(v: &[u8], events: &[Events], pos: &mut usize) -> HashSet { break } if let Some(Events::InBlock(_)) = get_useful_next(events, pos) { - pathes.push(CssPath::new(build_rule(v, &get_previous_positions(events, *pos)))); + paths.push(CssPath::new(build_rule(v, &get_previous_positions(events, *pos)))); *pos += 1; } while let Some(Events::InBlock(_)) = get_useful_next(events, pos) { - if let Some(ref mut path) = pathes.last_mut() { + if let Some(ref mut path) = paths.last_mut() { for entry in inner(v, events, pos).iter() { path.children.insert(entry.clone()); } @@ -218,10 +232,10 @@ fn inner(v: &[u8], events: &[Events], pos: &mut usize) -> HashSet { *pos += 1; } } - pathes.iter().cloned().collect() + paths.iter().cloned().collect() } -pub fn load_css_pathes(v: &[u8]) -> CssPath { +pub fn load_css_paths(v: &[u8]) -> CssPath { let events = load_css_events(v); let mut pos = 0; @@ -264,9 +278,9 @@ pub fn test_theme_against>(f: &P, against: &CssPath) -> (bool, Ve let mut data = Vec::with_capacity(1000); try_something!(file.read_to_end(&mut data), (false, Vec::new())); - let pathes = load_css_pathes(&data); + let paths = load_css_paths(&data); let mut ret = Vec::new(); - get_differences(against, &pathes, &mut ret); + get_differences(against, &paths, &mut ret); (true, ret) } @@ -317,8 +331,11 @@ rule gh i {} rule j end {} "#; - assert!(get_differences(&load_css_pathes(against.as_bytes()), - &load_css_pathes(text.as_bytes())).is_empty()); + let mut ret = Vec::new(); + get_differences(&load_css_paths(against.as_bytes()), + &load_css_paths(text.as_bytes()), + &mut ret); + assert!(ret.is_empty()); } #[test] @@ -330,8 +347,8 @@ a c // sdf d {} "#; - let pathes = load_css_pathes(text.as_bytes()); - assert!(pathes.children.get("a b c d").is_some()); + let paths = load_css_paths(text.as_bytes()); + assert!(paths.children.get(&CssPath::new("a b c d".to_owned())).is_some()); } #[test] @@ -350,10 +367,13 @@ a { } "#; - let against = load_css_pathes(y.as_bytes()); - let other = load_css_pathes(x.as_bytes()); + let against = load_css_paths(y.as_bytes()); + let other = load_css_paths(x.as_bytes()); - assert!(get_differences(&against, &other).is_empty()); - assert_eq!(get_differences(&other, &against), vec![" Missing \"c\" rule".to_owned()]) + let mut ret = Vec::new(); + get_differences(&against, &other, &mut ret); + assert!(ret.is_empty()); + get_differences(&other, &against, &mut ret); + assert_eq!(ret, vec![" Missing \"c\" rule".to_owned()]); } } diff --git a/src/tools/rustdoc-themes/test-themes.py b/src/tools/rustdoc-themes/test-themes.py new file mode 100644 index 000000000000..27756e3bef6b --- /dev/null +++ b/src/tools/rustdoc-themes/test-themes.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# 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. + +from os import listdir +from os.path import isfile, join +import subprocess +import sys + +FILES_TO_IGNORE = ['main.css'] +THEME_DIR_PATH = "src/librustdoc/html/static/themes" + + +def print_err(msg): + sys.stderr.write('{}\n'.format(msg)) + + +def exec_command(command): + child = subprocess.Popen(command) + stdout, stderr = child.communicate() + return child.returncode + + +def main(argv): + if len(argv) < 1: + print_err("Needs rustdoc binary path") + return 1 + rustdoc_bin = argv[0] + themes = [join(THEME_DIR_PATH, f) for f in listdir(THEME_DIR_PATH) + if isfile(join(THEME_DIR_PATH, f)) and f not in FILES_TO_IGNORE] + if len(themes) < 1: + print_err('No theme found in "{}"...'.format(THEME_DIR_PATH)) + return 1 + args = [rustdoc_bin, '-Z', 'unstable-options', '--theme-checker'] + args.extend(themes) + return exec_command(args) + + +if __name__ != '__main__': + print_err("Needs to be run as main") + sys.exit(1) +else: + sys.exit(main(sys.argv[1:]))