7 个版本

0.1.6 2023年10月6日
0.1.5 2023年2月10日

408解析器实现 中排名

Download history 7/week @ 2024-04-22 34/week @ 2024-04-29 26/week @ 2024-05-06 39/week @ 2024-05-13 25/week @ 2024-05-20 31/week @ 2024-05-27 13/week @ 2024-06-03 13/week @ 2024-06-10 15/week @ 2024-06-17 15/week @ 2024-06-24 8/week @ 2024-07-08 20/week @ 2024-07-15 44/week @ 2024-07-29 16/week @ 2024-08-05

每月下载量 82
4 crates 中使用

MITGPL-3.0-only

59KB
1.5K SLoC

****# pest-test

pest解析器的测试框架(类似于tree-sitter测试)。

测试用例

一个测试用例是一个包含三个部分文本文件

  • 测试名称必须位于文件的 第一行。它可以包含任何字符,除了换行符。
  • 源代码块由任意连续的三个或更多非空白字符界定。相同的字符序列必须在代码块前后出现,并且该序列不得出现在代码块内部。
  • 代码块前后必须有一个行分隔符。最外层的行分隔符将被移除;任何剩余的行分隔符将被保留。这意味着如果您的解析器对首尾空格敏感,您必须确保在代码块前后放置正确数量的空行。
  • 期望的输出语法树,以S表达式的形式编写。可选地,终端节点后面可以跟其期望的字符串值。期望的字符串值可以包含转义字符 - 在与实际值比较之前,它们将被取消转义。

以下是一个示例测试。请注意,代码块分隔符正好由7个等号组成。在这种情况下,解析器忽略了隐式空白,因此代码前后空行的数量是任意的。

My Test

=======

fn x() int {
  return 1;
}

=======

(source_file
  (function_definition
    (identifier: "x")
    (parameter_list)
    (primitive_type: "int")
    (block
      (return_statement 
        (number: "1")
      )
    )
  )
)

属性

期望输出S表达式中的节点可以用形式为#[name(args)]的属性进行注释。当前已识别的属性包括

  • skip:对于某些语法,存在多级嵌套,这只是为了应对PEG解析器的限制,例如具有左递归的数学表达式。为了简化涉及此类语法的测试用例,可以使用skip属性来忽略实际解析树中指定级别的嵌套。
    (expression
      #[skip(depth = 3)]
      (sum
        (number: 1)
        (number: 2)
      )
    )
    

用法

测试框架的主要接口是pest_test::PestTester。默认情况下,假定测试位于您crate的tests/pest目录中,并且具有.txt文件扩展名。下面的示例展示了如何使用lazy_static宏创建一个单独的PestTester实例,然后使用它评估任意数量的测试。

#[cfg(test)]
mod tests {
  use mycrate::parser::{MyParser, Rule};
  use lazy_static::lazy_static;
  use pest_test::{Error, PestTester};

  lazy_static! {
    static ref TESTER: PestTester<Rule, MyParser> = 
      PestTester::from_defaults(Rule::root_rule);
  }

  // Loads test from `tests/pest/mytest.txt` and evaluates it. Returns an `Err<pest_test::Error>`
  // if there was an error evaluating the test, or if the expected and actual values do not match.
  fn test_my_parser -> Result<(), Error> {
    (*TESTER).evaluate_strict("mytest")
  }
}

如果您将pest-test-gen添加为开发依赖项,则可以使用pest_tests属性宏为您所有的测试用例生成测试。

// Generate tests for all test cases in tests/pest/foo/ and all subdirectories. Since
// `lazy_static = true`, a single `PestTester` is created and used by all tests; otherwise a new
// `PestTester` would be created for each test.
#[pest_tests(
  mycrate::parser::MyParser,
  mycrate::parser::Rule,
  "root_rule",
  subdir = "foo",
  recursive = true,
  lazy_static = true,
)]
#[cfg(test)]
mod foo_tests {}

要禁用diff输出的着色,请在运行cargo时使用CARGO_TERM_COLOR=never

请注意,只有当测试模块的代码发生变化时,测试模块才会重新编译。因此,如果您在tests/pest中添加或重命名测试用例而没有更改测试模块,则测试模块可能不会更新以包括新/重命名的测试用例,因此您可能需要删除target文件夹以强制重新编译测试。

详细信息

测试文件使用pest进行解析。源代码使用您的pest语法进行解析,然后生成的树将被彻底迭代以构建一个嵌套数据结构,然后将其与从预期输出构建的相同结构进行匹配。如果不匹配,则将树以行内差异的形式打印出来。

依赖关系

~3–13MB
~102K SLoC