1 mod progress;
2 
3 use self::progress::Progress;
4 use anyhow::Result;
5 use flate2::read::GzDecoder;
6 use std::fs;
7 use std::path::Path;
8 use tar::Archive;
9 use walkdir::DirEntry;
10 
11 const REVISION: &str = "50171c310cd15e1b2d3723766ce64e2e4d6696fc";
12 
13 #[rustfmt::skip]
14 static EXCLUDE: &[&str] = &[
15     // TODO: anonymous structs/unions
16     // type A = struct { field: u8 };
17     // https://github.com/dtolnay/syn/issues/1049
18     "src/test/pretty/anonymous-types.rs",
19 
20     // TODO: impl ~const T {}
21     // https://github.com/dtolnay/syn/issues/1051
22     "src/test/ui/rfc-2632-const-trait-impl/syntax.rs",
23 
24     // TODO: ~const in where-clause
25     // https://github.com/dtolnay/syn/issues/1051
26     "src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-run.rs",
27     "src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs",
28 
29     // Compile-fail expr parameter in const generic position: f::<1 + 2>()
30     "src/test/ui/const-generics/early/closing-args-token.rs",
31     "src/test/ui/const-generics/early/const-expression-parameter.rs",
32 
33     // Deprecated anonymous parameter syntax in traits
34     "src/test/ui/issues/issue-13105.rs",
35     "src/test/ui/issues/issue-13775.rs",
36     "src/test/ui/issues/issue-34074.rs",
37     "src/test/ui/proc-macro/trait-fn-args-2015.rs",
38     "src/tools/rustfmt/tests/source/trait.rs",
39     "src/tools/rustfmt/tests/target/trait.rs",
40 
41     // Excessive nesting
42     "src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs",
43 
44     // Testing rustfmt on invalid syntax
45     "src/tools/rustfmt/tests/coverage/target/comments.rs",
46     "src/tools/rustfmt/tests/parser/issue-4126/invalid.rs",
47     "src/tools/rustfmt/tests/parser/issue_4418.rs",
48     "src/tools/rustfmt/tests/parser/unclosed-delims/issue_4466.rs",
49     "src/tools/rustfmt/tests/source/configs/disable_all_formatting/true.rs",
50     "src/tools/rustfmt/tests/source/configs/spaces_around_ranges/false.rs",
51     "src/tools/rustfmt/tests/source/configs/spaces_around_ranges/true.rs",
52     "src/tools/rustfmt/tests/source/type.rs",
53     "src/tools/rustfmt/tests/target/configs/spaces_around_ranges/false.rs",
54     "src/tools/rustfmt/tests/target/configs/spaces_around_ranges/true.rs",
55     "src/tools/rustfmt/tests/target/type.rs",
56 
57     // Not actually test cases
58     "src/test/rustdoc-ui/test-compile-fail2.rs",
59     "src/test/rustdoc-ui/test-compile-fail3.rs",
60     "src/test/ui/include-single-expr-helper.rs",
61     "src/test/ui/include-single-expr-helper-1.rs",
62     "src/test/ui/json-bom-plus-crlf-multifile-aux.rs",
63     "src/test/ui/lint/expansion-time-include.rs",
64     "src/test/ui/macros/auxiliary/macro-comma-support.rs",
65     "src/test/ui/macros/auxiliary/macro-include-items-expr.rs",
66     "src/test/ui/parser/auxiliary/issue-21146-inc.rs",
67 ];
68 
base_dir_filter(entry: &DirEntry) -> bool69 pub fn base_dir_filter(entry: &DirEntry) -> bool {
70     let path = entry.path();
71     if path.is_dir() {
72         return true; // otherwise walkdir does not visit the files
73     }
74     if path.extension().map(|e| e != "rs").unwrap_or(true) {
75         return false;
76     }
77 
78     let mut path_string = path.to_string_lossy();
79     if cfg!(windows) {
80         path_string = path_string.replace('\\', "/").into();
81     }
82     let path = if let Some(path) = path_string.strip_prefix("tests/rust/") {
83         path
84     } else {
85         panic!("unexpected path in Rust dist: {}", path_string);
86     };
87 
88     if path.starts_with("src/test/compile-fail") || path.starts_with("src/test/rustfix") {
89         return false;
90     }
91 
92     if path.starts_with("src/test/ui") {
93         let stderr_path = entry.path().with_extension("stderr");
94         if stderr_path.exists() {
95             // Expected to fail in some way
96             return false;
97         }
98     }
99 
100     !EXCLUDE.contains(&path)
101 }
102 
103 #[allow(dead_code)]
edition(path: &Path) -> &'static str104 pub fn edition(path: &Path) -> &'static str {
105     if path.ends_with("dyn-2015-no-warnings-without-lints.rs") {
106         "2015"
107     } else {
108         "2018"
109     }
110 }
111 
clone_rust()112 pub fn clone_rust() {
113     let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
114         Err(_) => true,
115         Ok(contents) => contents.trim() != REVISION,
116     };
117     if needs_clone {
118         download_and_unpack().unwrap();
119     }
120     let mut missing = String::new();
121     let test_src = Path::new("tests/rust");
122     for exclude in EXCLUDE {
123         if !test_src.join(exclude).exists() {
124             missing += "\ntests/rust/";
125             missing += exclude;
126         }
127     }
128     if !missing.is_empty() {
129         panic!("excluded test file does not exist:{}\n", missing);
130     }
131 }
132 
download_and_unpack() -> Result<()>133 fn download_and_unpack() -> Result<()> {
134     let url = format!(
135         "https://github.com/rust-lang/rust/archive/{}.tar.gz",
136         REVISION
137     );
138     let response = reqwest::blocking::get(&url)?.error_for_status()?;
139     let progress = Progress::new(response);
140     let decoder = GzDecoder::new(progress);
141     let mut archive = Archive::new(decoder);
142     let prefix = format!("rust-{}", REVISION);
143 
144     let tests_rust = Path::new("tests/rust");
145     if tests_rust.exists() {
146         fs::remove_dir_all(tests_rust)?;
147     }
148 
149     for entry in archive.entries()? {
150         let mut entry = entry?;
151         let path = entry.path()?;
152         if path == Path::new("pax_global_header") {
153             continue;
154         }
155         let relative = path.strip_prefix(&prefix)?;
156         let out = tests_rust.join(relative);
157         entry.unpack(&out)?;
158     }
159 
160     fs::write("tests/rust/COMMIT", REVISION)?;
161     Ok(())
162 }
163