提交 51580d46 编写于 作者: G Guillaume Gomez

Add tests for themes

上级 63ee1cd8
......@@ -258,7 +258,7 @@ fn get_step_descriptions(kind: Kind) -> Vec<StepDescription> {
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,
......
......@@ -160,4 +160,3 @@ pub fn libtest_stamp(build: &Build, compiler: Compiler, target: Interned<String>
pub fn librustc_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf {
build.cargo_out(compiler, Mode::Librustc, target).join(".librustc-check.stamp")
}
......@@ -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<String>,
}
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<String>,
......
......@@ -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");
......
......@@ -170,18 +170,24 @@ fn get_useful_next(events: &[Events], pos: &mut usize) -> Option<Events> {
fn get_previous_positions(events: &[Events], mut pos: usize) -> Vec<usize> {
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<usize> {
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::<String>()
.trim()
.replace("\n", " ")
.replace("/", "")
.replace("\t", " ")
.replace("{", "")
.replace("}", "")
.split(" ")
.filter(|s| s.len() > 0)
.collect::<Vec<&str>>()
.join(" ")
}
fn inner(v: &[u8], events: &[Events], pos: &mut usize) -> HashSet<CssPath> {
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<CssPath> {
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<CssPath> {
*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<P: AsRef<Path>>(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 @@ fn test_comments_in_rules() {
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 @@ fn test_text() {
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 @@ fn test_comparison() {
}
"#;
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()]);
}
}
#!/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 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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:]))
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册