Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: Cleanup code for tsc test suite #785

Merged
merged 18 commits into from Mar 4, 2023
2 changes: 1 addition & 1 deletion crates/stc_ts_file_analyzer/examples/file.rs
Expand Up @@ -29,7 +29,7 @@ fn profile_file(file_name: &Path) {
println!("{}", filename);
let want_error = true;

for case in parse_conformance_test(file_name) {
for case in parse_conformance_test(file_name).unwrap() {
testing::Tester::new()
.print_errors(|cm, handler| -> Result<(), _> {
let handler = Arc::new(handler);
Expand Down
4 changes: 2 additions & 2 deletions crates/stc_ts_file_analyzer/tests/base.rs
Expand Up @@ -276,7 +276,7 @@ fn run_test(file_name: PathBuf, want_error: bool) -> Option<NormalizedOutput> {
let filename = file_name.display().to_string();
println!("{}", filename);

for case in parse_conformance_test(&file_name) {
for case in parse_conformance_test(&file_name).unwrap() {
let result = testing::Tester::new()
.print_errors(|cm, handler| -> Result<(), _> {
let handler = Arc::new(handler);
Expand Down Expand Up @@ -404,7 +404,7 @@ fn pass(file_name: PathBuf) {

#[fixture("tests/pass-only/**/*.ts")]
fn pass_only(input: PathBuf) {
for case in parse_conformance_test(&input) {
for case in parse_conformance_test(&input).unwrap() {
testing::run_test2(false, |cm, handler| {
let fm = cm.load_file(&input).unwrap();

Expand Down
10 changes: 7 additions & 3 deletions crates/stc_ts_testing/src/conformance.rs
Expand Up @@ -10,6 +10,7 @@ use std::{
sync::Arc,
};

use anyhow::{anyhow, Result};
use once_cell::sync::Lazy;
use regex::Regex;
use rustc_hash::FxHashSet;
Expand All @@ -21,6 +22,8 @@ use swc_ecma_ast::{EsVersion, Program};
use swc_ecma_parser::{Parser, Syntax, TsConfig};

pub struct TestSpec {
/// Typescript conformance test remove lines starting with @-directives, and
/// it changes the line of errors.
pub err_shift_n: usize,
pub libs: Vec<Lib>,
pub rule: Rule,
Expand Down Expand Up @@ -72,7 +75,7 @@ fn parse_sub_files(source: &str) -> Vec<(String, String)> {
}

#[allow(clippy::explicit_write)]
pub fn parse_conformance_test(file_name: &Path) -> Vec<TestSpec> {
pub fn parse_conformance_test(file_name: &Path) -> Result<Vec<TestSpec>> {
let mut err_shift_n = 0;
let mut first_stmt_line = 0;

Expand Down Expand Up @@ -247,7 +250,8 @@ pub fn parse_conformance_test(file_name: &Path) -> Vec<TestSpec> {
rule.strict_function_types = strict;
} else if s.to_ascii_lowercase().starts_with("filename") {
} else if s.to_ascii_lowercase().starts_with("allowjs") || s.to_ascii_lowercase().starts_with("checkjs") {
panic!("allowJs and checkJs are not supported yet. See https://github.com/dudykr/stc/issues/702")
// panic!("allowJs and checkJs are not supported yet. See https://github.com/dudykr/stc/issues/702")
return Err(());
} else {
writeln!(stderr(), "Comment is not handled: {}", s).unwrap();
}
Expand Down Expand Up @@ -332,7 +336,7 @@ pub fn parse_conformance_test(file_name: &Path) -> Vec<TestSpec> {
lib_files,
}])
})
.unwrap()
.map_err(|err| anyhow!("Failed to parse test case: {}", err))
}

fn parse_directive_values<T>(s: &str, parser: &dyn Fn(&str) -> T) -> Vec<(String, T)> {
Expand Down
84 changes: 8 additions & 76 deletions crates/stc_ts_testing/src/tsc.rs
@@ -1,24 +1,23 @@
//! Support for official typescript tests.

use std::{fs::read_to_string, path::Path, sync::Arc};

use anyhow::{bail, Context, Error};
use serde::{Deserialize, Serialize};
use swc_common::{comments::Comments, errors::Handler, input::SourceFileInput, FileName, SourceMap};
use swc_ecma_ast::*;
use swc_ecma_parser::{lexer::Lexer, Parser, Syntax, TsConfig};

/// Error from `tsc`.
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct TscError {
pub file: String,
#[serde(default)]
pub file: Option<String>,
pub line: usize,
pub col: usize,
pub code: usize,
// pub msg: String,
}

impl TscError {
pub fn ts_error_code(&self) -> String {
format!("TS{}", self.code)
}

pub fn parse_all(output: &str) -> Vec<Self> {
let mut errors = vec![];

Expand All @@ -39,7 +38,7 @@ impl TscError {
};
let item = item.strip_suffix("\u{001b}[0m").expect("expected colored output");

error.file = item.to_string();
error.file = Some(item.to_string());
}
1 => {
let item = item
Expand Down Expand Up @@ -80,70 +79,3 @@ impl TscError {
errors
}
}

/// Simple typescript test case.
///
/// Expects typescript
#[derive(Debug)]
pub struct TsTestCase {
pub program: Program,
pub type_data: Vec<TypeInfo>,
}

#[derive(Debug)]
pub struct TypeInfo {
pub expr: String,
pub ty: String,
}

impl TsTestCase {
pub fn parse(cm: &Arc<SourceMap>, handler: &Handler, file_name: &Path, comments: Option<&dyn Comments>) -> Result<Self, Error> {
let s = read_to_string(file_name).with_context(|| format!("failed to parse typescript test file at `{}`", file_name.display()))?;
let mut code = String::new();
let mut type_data = vec![];

for line in s.lines().skip(1) {
if line.starts_with('>') {
let idx = line.find(" : ");
let idx = match idx {
Some(idx) => idx,
None => {
bail!("failed to find the separator of expression and type from `{}`", line)
}
};

let expr = line[1..idx].to_string();
let ty = line[idx + 3..].to_string();

type_data.push(TypeInfo { expr, ty });
} else {
code.push_str(line);
code.push('\n');
}
}

let fm = cm.new_source_file(FileName::Real(file_name.to_path_buf()), code);

let lexer = Lexer::new(
Syntax::Typescript(TsConfig {
tsx: file_name.to_string_lossy().contains("tsx"),
..Default::default()
}),
EsVersion::latest(),
SourceFileInput::from(&*fm),
comments,
);

let mut parser = Parser::new_from(lexer);
let program = parser.parse_program();
let program = match program {
Ok(program) => program,
Err(err) => {
err.into_diagnostic(handler).emit();
bail!("failed to parse typescript test case")
}
};

Ok(Self { program, type_data })
}
}
Expand Up @@ -2,16 +2,16 @@
"required_errors": {},
"required_error_lines": {},
"extra_errors": {
"TS0": 1,
"TS2307": 2
"TS2307": 2,
"TS0": 1
},
"extra_error_lines": {
"TS0": [
1
],
"TS2307": [
1,
1
],
"TS0": [
1
]
}
}
@@ -1,13 +1,13 @@
{
"required_errors": {
"TS18007": 1,
"TS2695": 1
"TS2695": 1,
"TS18007": 1
},
"required_error_lines": {
"TS18007": [
"TS2695": [
14
],
"TS2695": [
"TS18007": [
14
]
},
Expand Down
Expand Up @@ -2,15 +2,15 @@
"required_errors": {},
"required_error_lines": {},
"extra_errors": {
"TS2304": 2,
"TS2307": 1
"TS2307": 1,
"TS2304": 2
},
"extra_error_lines": {
"TS2304": [
3,
"TS2307": [
3
],
"TS2307": [
"TS2304": [
3,
3
]
}
Expand Down