test262_harness/
lib.rs

1use serde::{Deserialize, Serialize};
2use std::path::{Path, PathBuf};
3use walkdir::WalkDir;
4
5mod error;
6pub use error::Error;
7
8/// The test harness
9pub struct Harness {
10    test_paths: Vec<PathBuf>,
11    idx: usize,
12}
13
14impl Harness {
15    /// Provide the root path for the
16    /// test directory from the test262 repository
17    pub fn new<P: AsRef<Path>>(test_root: P) -> Result<Self, Error> {
18        let test_paths = WalkDir::new(test_root)
19            .min_depth(1)
20            .into_iter()
21            .filter_map(|e| {
22                let entry = match e {
23                    Err(e) => return Some(Err(e)),
24                    Ok(e) => e,
25                };
26                let path = entry.path();
27                if path.is_dir() {
28                    None
29                } else {
30                    let ext = path.extension()?;
31                    if ext == "js" {
32                        let file_name = path.file_name()?;
33                        let file_name = file_name.to_str()?;
34                        if file_name.ends_with("_FIXTURE.js") {
35                            None
36                        } else {
37                            Some(Ok(path.to_path_buf()))
38                        }
39                    } else {
40                        None
41                    }
42                }
43            })
44            .collect::<Result<Vec<PathBuf>, walkdir::Error>>()?;
45        Ok(Self { test_paths, idx: 0 })
46    }
47
48    fn create_test_from(&self, p: &PathBuf) -> Result<Test, Error> {
49        let contents = std::fs::read_to_string(p)?;
50        let (yaml_start, yaml_end) = Self::find_yaml(&contents, p)?;
51        let yaml = contents[yaml_start..yaml_end].replace("\r", "\n");
52        let desc = serde_yaml::from_str(&yaml)?;
53        Ok(Test {
54            desc,
55            path: p.clone(),
56            source: contents,
57        })
58    }
59
60    fn find_yaml(content: &str, path: &PathBuf) -> Result<(usize, usize), Error> {
61        let start = content
62            .find("/*---")
63            .ok_or_else(|| Error::DescriptionInvalid(path.clone()))?;
64        let end = content
65            .find("---*/")
66            .ok_or_else(|| Error::DescriptionInvalid(path.clone()))?;
67        Ok((start + 5, end))
68    }
69}
70
71impl Iterator for Harness {
72    type Item = Result<Test, Error>;
73    fn next(&mut self) -> Option<Self::Item> {
74        if self.idx >= self.test_paths.len() {
75            None
76        } else {
77            let p = self.test_paths.get(self.idx)?;
78            self.idx += 1;
79            Some(self.create_test_from(p))
80        }
81    }
82}
83
84/// A single entry in the
85/// test suite
86pub struct Test {
87    /// The full js text including the
88    /// license and metadata comments
89    pub source: String,
90    /// The full file path that this test
91    /// can be found
92    pub path: PathBuf,
93    /// The parsed metadata from the
94    /// file
95    pub desc: Description,
96}
97
98/// The parsed metadata from the
99/// file
100#[derive(Debug, Deserialize, Clone, Serialize, PartialEq)]
101pub struct Description {
102    /// One possible id
103    pub id: Option<String>,
104    /// One possible id
105    pub esid: Option<String>,
106    /// One possible id
107    pub es5id: Option<String>,
108    /// One possible id
109    pub es6id: Option<String>,
110    /// A longer description of
111    /// what the test is trying
112    /// to evaluate
113    pub info: Option<String>,
114    /// A short description of
115    /// what the test is trying
116    /// to evaluate
117    pub description: Option<String>,
118    /// Will be `Some` if this
119    /// test should fail
120    pub negative: Option<Negative>,
121    /// If this test relies on an
122    /// files in the /harness
123    /// directory they will
124    /// be included here
125    #[serde(default)]
126    pub includes: Vec<String>,
127    /// If this test needs
128    /// to be executed in
129    /// a specific way
130    /// i.e. as a module or
131    /// strict mode only
132    #[serde(default)]
133    pub flags: Vec<Flag>,
134    /// Any locales that
135    /// should be respected
136    #[serde(default)]
137    pub locale: Vec<String>,
138    /// If this test relies on any
139    /// features
140    #[serde(default)]
141    pub features: Vec<String>,
142}
143
144/// If a test is expected to
145/// fail, this describes
146/// how it should fail
147#[derive(Debug, Deserialize, Clone, Serialize, PartialEq)]
148pub struct Negative {
149    /// When should this test fail
150    pub phase: Phase,
151    /// The name of the expected
152    /// exception
153    #[serde(alias = "type")]
154    pub kind: Option<String>,
155}
156
157/// Phase for negative tests
158#[derive(Debug, Deserialize, Clone, Copy, Serialize, PartialEq)]
159#[serde(rename_all = "camelCase")]
160pub enum Phase {
161    /// During the parsing step
162    Parse,
163    /// After parsing but before
164    /// evaluation
165    Early,
166    /// During module resolution
167    Resolution,
168    /// During evaluation
169    Runtime,
170}
171
172#[derive(Debug, Deserialize, PartialEq, Clone, Copy, Serialize)]
173#[serde(rename_all = "camelCase")]
174pub enum Flag {
175    /// This test should only be run in strict mode
176    OnlyStrict,
177    /// This test should not be run in strict mode
178    NoStrict,
179    /// This test should only be run as a module
180    Module,
181    /// This test should be run as is, in non-strict mode
182    Raw,
183    /// This test will be asynchronous,
184    /// use doneprintHandle.js
185    Async,
186    /// This test was procedurally generated
187    Generated,
188    /// the [[CanBlock]] record must be false
189    #[serde(alias = "CanBlockIsFalse")]
190    CanBlockIsFalse,
191    /// the [[CanBlock]] record must be true
192    #[serde(alias = "CanBlockIsTrue")]
193    CanBlockIsTrue,
194    /// This test may pass in more than
195    /// one way depending on implementation
196    #[serde(alias = "non-deterministic")]
197    NonDeterministic,
198}