2018-12-30 05:57:27 +03:00
|
|
|
#![feature(test)]
|
|
|
|
|
|
|
|
extern crate test;
|
|
|
|
|
2019-02-24 08:12:04 +03:00
|
|
|
use pretty_assertions::assert_eq;
|
2019-12-02 11:10:06 +03:00
|
|
|
use serde_json;
|
2018-12-30 05:57:27 +03:00
|
|
|
use std::{
|
|
|
|
env,
|
|
|
|
fs::File,
|
|
|
|
io::{self, Read},
|
|
|
|
path::Path,
|
|
|
|
};
|
2020-08-03 19:33:23 +03:00
|
|
|
use swc_common::{errors::Handler, sync::Lrc, SourceMap};
|
2019-12-10 18:02:39 +03:00
|
|
|
use swc_ecma_ast::*;
|
2020-07-31 12:49:07 +03:00
|
|
|
use swc_ecma_parser::{lexer::Lexer, PResult, Parser, StringInput};
|
2020-07-23 20:18:22 +03:00
|
|
|
use swc_ecma_visit::{Fold, FoldWith};
|
2019-10-23 14:19:49 +03:00
|
|
|
use test::{
|
|
|
|
test_main, DynTestFn, Options, ShouldPanic::No, TestDesc, TestDescAndFn, TestName, TestType,
|
|
|
|
};
|
2019-02-12 09:30:11 +03:00
|
|
|
use testing::{run_test, StdErr};
|
2018-12-30 05:57:27 +03:00
|
|
|
use walkdir::WalkDir;
|
|
|
|
|
|
|
|
fn add_test<F: FnOnce() + Send + 'static>(
|
|
|
|
tests: &mut Vec<TestDescAndFn>,
|
|
|
|
name: String,
|
|
|
|
ignore: bool,
|
|
|
|
f: F,
|
|
|
|
) {
|
|
|
|
tests.push(TestDescAndFn {
|
|
|
|
desc: TestDesc {
|
2019-10-23 14:19:49 +03:00
|
|
|
test_type: TestType::UnitTest,
|
2018-12-30 05:57:27 +03:00
|
|
|
name: TestName::DynTestName(name),
|
|
|
|
ignore,
|
|
|
|
should_panic: No,
|
|
|
|
allow_fail: false,
|
|
|
|
},
|
2020-07-23 20:18:22 +03:00
|
|
|
testfn: DynTestFn(Box::new(f)),
|
2018-12-30 05:57:27 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn error_tests(tests: &mut Vec<TestDescAndFn>) -> Result<(), io::Error> {
|
|
|
|
let root = {
|
|
|
|
let mut root = Path::new(env!("CARGO_MANIFEST_DIR")).to_path_buf();
|
|
|
|
root.push("tests");
|
|
|
|
root.push("jsx");
|
|
|
|
root.push("errors");
|
|
|
|
root
|
|
|
|
};
|
|
|
|
|
|
|
|
eprintln!("Loading tests from {}", root.display());
|
|
|
|
|
|
|
|
let dir = root;
|
|
|
|
|
|
|
|
for entry in WalkDir::new(&dir).into_iter() {
|
|
|
|
let entry = entry?;
|
|
|
|
if entry.file_type().is_dir() || !entry.file_name().to_string_lossy().ends_with(".js") {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let file_name = entry
|
|
|
|
.path()
|
|
|
|
.strip_prefix(&dir)
|
|
|
|
.expect("failed to strip prefix")
|
|
|
|
.to_str()
|
|
|
|
.unwrap()
|
|
|
|
.to_string();
|
|
|
|
|
|
|
|
let input = {
|
|
|
|
let mut buf = String::new();
|
|
|
|
File::open(entry.path())?.read_to_string(&mut buf)?;
|
|
|
|
buf
|
|
|
|
};
|
|
|
|
|
|
|
|
let ignore = false;
|
|
|
|
|
|
|
|
let dir = dir.clone();
|
|
|
|
let name = format!("jsx::error::{}", file_name);
|
|
|
|
add_test(tests, name, ignore, move || {
|
|
|
|
eprintln!(
|
|
|
|
"\n\n========== Running error reporting test {}\nSource:\n{}\n",
|
|
|
|
file_name, input
|
|
|
|
);
|
|
|
|
|
|
|
|
let path = dir.join(&file_name);
|
2019-02-12 09:30:11 +03:00
|
|
|
let err = run_test(false, |cm, handler| {
|
|
|
|
if false {
|
|
|
|
// Type annotation
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse source
|
2020-07-23 20:18:22 +03:00
|
|
|
let _ = parse_module(cm, handler, &path);
|
|
|
|
if !handler.has_errors() {
|
|
|
|
panic!("should emit error, but parsed without error")
|
|
|
|
}
|
2019-02-12 09:30:11 +03:00
|
|
|
|
2019-11-17 07:21:53 +03:00
|
|
|
Err(())
|
2019-02-12 09:30:11 +03:00
|
|
|
})
|
|
|
|
.expect_err("should fail, but parsed as");
|
2018-12-30 05:57:27 +03:00
|
|
|
|
|
|
|
if err
|
|
|
|
.compare_to_file(format!("{}.stderr", path.display()))
|
|
|
|
.is_err()
|
|
|
|
{
|
|
|
|
panic!()
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn reference_tests(tests: &mut Vec<TestDescAndFn>) -> Result<(), io::Error> {
|
|
|
|
let root = {
|
|
|
|
let mut root = Path::new(env!("CARGO_MANIFEST_DIR")).to_path_buf();
|
|
|
|
root.push("tests");
|
|
|
|
root.push("jsx");
|
|
|
|
root.push("basic");
|
|
|
|
root
|
|
|
|
};
|
|
|
|
|
|
|
|
eprintln!("Loading tests from {}", root.display());
|
|
|
|
|
|
|
|
let dir = root;
|
|
|
|
|
|
|
|
for entry in WalkDir::new(&dir).into_iter() {
|
|
|
|
let entry = entry?;
|
|
|
|
if entry.file_type().is_dir() || !entry.file_name().to_string_lossy().ends_with(".js") {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let file_name = entry
|
|
|
|
.path()
|
|
|
|
.strip_prefix(&dir)
|
|
|
|
.expect("failed to strip prefix")
|
|
|
|
.to_str()
|
|
|
|
.unwrap()
|
|
|
|
.to_string();
|
|
|
|
|
|
|
|
let input = {
|
|
|
|
let mut buf = String::new();
|
|
|
|
File::open(entry.path())?.read_to_string(&mut buf)?;
|
|
|
|
buf
|
|
|
|
};
|
|
|
|
|
|
|
|
let ignore = false;
|
|
|
|
|
|
|
|
let dir = dir.clone();
|
|
|
|
let name = format!("jsx::reference::{}", file_name);
|
|
|
|
add_test(tests, name, ignore, move || {
|
2019-02-12 09:30:11 +03:00
|
|
|
run_test(false, |cm, handler| {
|
2019-12-13 09:21:25 +03:00
|
|
|
eprintln!(
|
|
|
|
"\n\n========== Running reference test {}\nSource:\n{}\n",
|
|
|
|
file_name, input
|
|
|
|
);
|
|
|
|
|
|
|
|
let path = dir.join(&file_name);
|
|
|
|
// Parse source
|
|
|
|
let module = parse_module(cm.clone(), handler, &path)?.fold_with(&mut Normalizer);
|
|
|
|
let json = serde_json::to_string_pretty(&module)
|
|
|
|
.expect("failed to serialize module as json");
|
|
|
|
if StdErr::from(json.clone())
|
|
|
|
.compare_to_file(format!("{}.json", path.display()))
|
|
|
|
.is_err()
|
|
|
|
{
|
|
|
|
panic!()
|
|
|
|
}
|
|
|
|
|
|
|
|
let deser = serde_json::from_str::<Module>(&json)
|
|
|
|
.unwrap_or_else(|err| {
|
|
|
|
panic!(
|
|
|
|
"failed to deserialize json back to module: {}\n{}",
|
|
|
|
err, json
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.fold_with(&mut Normalizer);
|
|
|
|
assert_eq!(module, deser, "JSON:\n{}", json);
|
|
|
|
|
|
|
|
Ok(())
|
2019-02-12 09:30:11 +03:00
|
|
|
})
|
|
|
|
.unwrap();
|
2018-12-30 05:57:27 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-08-03 19:33:23 +03:00
|
|
|
fn parse_module<'a>(cm: Lrc<SourceMap>, handler: &Handler, file_name: &Path) -> Result<Module, ()> {
|
2019-02-12 09:30:11 +03:00
|
|
|
with_parser(cm, handler, file_name, |p| p.parse_module())
|
2018-12-30 05:57:27 +03:00
|
|
|
}
|
|
|
|
|
2019-02-12 09:30:11 +03:00
|
|
|
fn with_parser<F, Ret>(
|
2020-08-03 19:33:23 +03:00
|
|
|
cm: Lrc<SourceMap>,
|
2019-02-12 09:30:11 +03:00
|
|
|
handler: &Handler,
|
|
|
|
file_name: &Path,
|
|
|
|
f: F,
|
|
|
|
) -> Result<Ret, ()>
|
2018-12-30 05:57:27 +03:00
|
|
|
where
|
2020-07-31 12:49:07 +03:00
|
|
|
F: FnOnce(&mut Parser<Lexer<StringInput<'_>>>) -> PResult<Ret>,
|
2018-12-30 05:57:27 +03:00
|
|
|
{
|
2019-02-12 09:30:11 +03:00
|
|
|
let fm = cm
|
|
|
|
.load_file(file_name)
|
|
|
|
.unwrap_or_else(|e| panic!("failed to load {}: {}", file_name.display(), e));
|
|
|
|
|
2020-07-25 14:26:04 +03:00
|
|
|
let mut p = Parser::new(
|
2019-02-12 09:30:11 +03:00
|
|
|
::swc_ecma_parser::Syntax::Es(::swc_ecma_parser::EsConfig {
|
|
|
|
jsx: true,
|
|
|
|
..Default::default()
|
|
|
|
}),
|
|
|
|
(&*fm).into(),
|
|
|
|
None,
|
2020-07-25 14:26:04 +03:00
|
|
|
);
|
|
|
|
|
|
|
|
let res = f(&mut p).map_err(|e| e.into_diagnostic(handler).emit());
|
|
|
|
|
|
|
|
for e in p.take_errors() {
|
|
|
|
e.into_diagnostic(&handler).emit();
|
|
|
|
}
|
2018-12-30 05:57:27 +03:00
|
|
|
|
2019-02-12 09:30:11 +03:00
|
|
|
res
|
2018-12-30 05:57:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn references() {
|
|
|
|
let args: Vec<_> = env::args().collect();
|
|
|
|
let mut tests = Vec::new();
|
|
|
|
reference_tests(&mut tests).unwrap();
|
2019-10-02 07:53:56 +03:00
|
|
|
test_main(&args, tests, Some(Options::new()));
|
2018-12-30 05:57:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn error() {
|
|
|
|
let args: Vec<_> = env::args().collect();
|
|
|
|
let mut tests = Vec::new();
|
|
|
|
error_tests(&mut tests).unwrap();
|
2019-10-02 07:53:56 +03:00
|
|
|
test_main(&args, tests, Some(Options::new()));
|
2018-12-30 05:57:27 +03:00
|
|
|
}
|
2019-02-24 08:12:04 +03:00
|
|
|
|
|
|
|
struct Normalizer;
|
|
|
|
|
2020-07-23 20:18:22 +03:00
|
|
|
impl Fold for Normalizer {
|
|
|
|
fn fold_pat(&mut self, mut node: Pat) -> Pat {
|
|
|
|
node = node.fold_children_with(self);
|
2020-07-01 10:31:55 +03:00
|
|
|
|
2020-07-23 20:18:22 +03:00
|
|
|
if let Pat::Expr(expr) = node {
|
|
|
|
match *expr {
|
|
|
|
Expr::Ident(i) => return Pat::Ident(i),
|
|
|
|
_ => {
|
|
|
|
node = Pat::Expr(expr);
|
|
|
|
}
|
|
|
|
}
|
2020-07-01 10:31:55 +03:00
|
|
|
}
|
2020-07-23 20:18:22 +03:00
|
|
|
|
|
|
|
node
|
2020-07-01 10:31:55 +03:00
|
|
|
}
|
|
|
|
|
2020-07-23 20:18:22 +03:00
|
|
|
fn fold_pat_or_expr(&mut self, node: PatOrExpr) -> PatOrExpr {
|
|
|
|
let node = node.fold_children_with(self);
|
2019-02-24 08:12:04 +03:00
|
|
|
|
|
|
|
match node {
|
2020-07-23 20:18:22 +03:00
|
|
|
PatOrExpr::Pat(pat) => match *pat {
|
|
|
|
Pat::Expr(expr) => PatOrExpr::Expr(expr),
|
|
|
|
_ => PatOrExpr::Pat(pat),
|
|
|
|
},
|
2019-02-24 08:12:04 +03:00
|
|
|
_ => node,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|