]> git.lizzy.rs Git - rust.git/commitdiff
Introduce expect snapshot testing library into rustc
authorAleksey Kladov <aleksey.kladov@gmail.com>
Fri, 21 Aug 2020 12:03:50 +0000 (14:03 +0200)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Mon, 24 Aug 2020 13:38:42 +0000 (15:38 +0200)
Snapshot testing is a technique for writing maintainable unit tests.
Unlike usual `assert_eq!` tests, snapshot tests allow
to *automatically* upgrade expected values on test failure.
In a sense, snapshot tests are inline-version of our beloved
UI-tests.

Example:

![expect](https://user-images.githubusercontent.com/1711539/90888810-3bcc8180-e3b7-11ea-9626-d06e89e1a0bb.gif)

A particular library we use, `expect_test` provides an `expect!`
macro, which creates a sort of self-updating string literal (by using
`file!` macro). Self-update is triggered by setting `UPDATE_EXPECT`
environmental variable (this info is printed during the test failure).
This library was extracted from rust-analyzer, where we use it for
most of our tests.

There are some other, more popular snapshot testing libraries:

* https://github.com/mitsuhiko/insta
* https://github.com/aaronabramov/k9

The main differences of `expect` are:

* first-class snapshot objects (so, tests can be written as functions,
  rather than as macros)
* focus on inline-snapshots (but file snapshots are also supported)
* restricted feature set (only `assert_eq` and `assert_debug_eq`)
* no extra runtime (ie, no `cargo insta`)

See https://github.com/rust-analyzer/rust-analyzer/pull/5101 for a
an extended comparison.

It is unclear if this testing style will stick with rustc in the long
run. At the moment, rustc is mainly tested via integrated UI tests.
But in the library-ified world, unit-tests will become somewhat more
important (that's why use use `rustc_lexer` library-ified library as
an example in this PR). Given that the cost of removal shouldn't be
too high, it probably makes sense to just see if this flies!

Cargo.lock
src/bootstrap/test.rs
src/librustc_lexer/Cargo.toml
src/librustc_lexer/src/lib.rs
src/librustc_lexer/src/tests.rs
src/tools/tidy/src/deps.rs

index f8fa2971b49d8fced1cebb6e8c0042c6fdba29fa..e058d0b21271900750136c0ff7acd576e7c27b0a 100644 (file)
@@ -997,6 +997,16 @@ dependencies = [
  "yaml-rust 0.4.4",
 ]
 
+[[package]]
+name = "expect-test"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3e383741ea1982866572109d1a8c807bd36aad91fca701489fdca56ef92b3b8"
+dependencies = [
+ "difference",
+ "once_cell",
+]
+
 [[package]]
 name = "failure"
 version = "0.1.8"
@@ -3642,6 +3652,7 @@ dependencies = [
 name = "rustc_lexer"
 version = "0.1.0"
 dependencies = [
+ "expect-test",
  "unicode-xid",
 ]
 
index ac833a55d4c53bbf2224fa0adf7fffba6b76de73..afa72b5d58c14e8744d5d43e10fe015deeba8b83 100644 (file)
@@ -1754,6 +1754,11 @@ fn run(self, builder: &Builder<'_>) {
             cargo.arg("--quiet");
         }
 
+        if builder.config.cmd.bless() {
+            // Bless `expect!` tests.
+            cargo.env("UPDATE_EXPECT", "1");
+        }
+
         if target.contains("emscripten") {
             cargo.env(
                 format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
index 950771f0a692710021dc7e29c18736fdbbe3ea0b..28b56f6fef4b80861b86ccc76619f3bd82be76f4 100644 (file)
@@ -19,3 +19,6 @@ name = "rustc_lexer"
 # Note that this crate purposefully does not depend on other rustc crates
 [dependencies]
 unicode-xid = "0.2.0"
+
+[dev-dependencies]
+expect-test = "0.1"
index 2d80ca5a4de10449f99fbe4772dd42dc0c6ef62b..b7d6194cd77cf956d16ede3087c5b8a0a1ae4517 100644 (file)
@@ -35,6 +35,7 @@
 /// Parsed token.
 /// It doesn't contain information about data that has been parsed,
 /// only the type of the token and its size.
+#[derive(Debug)]
 pub struct Token {
     pub kind: TokenKind,
     pub len: usize,
index b0209ac2899d616fd7e0fab082ea4b2915e5ed1c..a1ea5ceb1f61283a2c5a5722f27bd1d9593552be 100644 (file)
@@ -1,5 +1,7 @@
 use super::*;
 
+use expect_test::{expect, Expect};
+
 fn check_raw_str(s: &str, expected_hashes: u16, expected_err: Option<RawStrError>) {
     let s = &format!("r{}", s);
     let mut cursor = Cursor::new(s);
@@ -120,3 +122,46 @@ fn test_shebang_followed_by_attrib() {
     let input = "#!/bin/rust-scripts\n#![allow_unused(true)]";
     assert_eq!(strip_shebang(input), Some(19));
 }
+
+fn check_lexing(src: &str, expect: Expect) {
+    let actual: String = tokenize(src).map(|token| format!("{:?}\n", token)).collect();
+    expect.assert_eq(&actual)
+}
+
+#[test]
+fn comment_flavors() {
+    check_lexing(
+        r"
+// line
+//// line as well
+/// outer doc line
+//! inner doc line
+/* block */
+/**/
+/*** also block */
+/** outer doc block */
+/*! inner doc block */
+",
+        expect![[r#"
+                Token { kind: Whitespace, len: 1 }
+                Token { kind: LineComment { doc_style: None }, len: 7 }
+                Token { kind: Whitespace, len: 1 }
+                Token { kind: LineComment { doc_style: None }, len: 17 }
+                Token { kind: Whitespace, len: 1 }
+                Token { kind: LineComment { doc_style: Some(Outer) }, len: 18 }
+                Token { kind: Whitespace, len: 1 }
+                Token { kind: LineComment { doc_style: Some(Inner) }, len: 18 }
+                Token { kind: Whitespace, len: 1 }
+                Token { kind: BlockComment { doc_style: None, terminated: true }, len: 11 }
+                Token { kind: Whitespace, len: 1 }
+                Token { kind: BlockComment { doc_style: None, terminated: true }, len: 4 }
+                Token { kind: Whitespace, len: 1 }
+                Token { kind: BlockComment { doc_style: None, terminated: true }, len: 18 }
+                Token { kind: Whitespace, len: 1 }
+                Token { kind: BlockComment { doc_style: Some(Outer), terminated: true }, len: 22 }
+                Token { kind: Whitespace, len: 1 }
+                Token { kind: BlockComment { doc_style: Some(Inner), terminated: true }, len: 22 }
+                Token { kind: Whitespace, len: 1 }
+            "#]],
+    )
+}
index 4f98944e4c8ebb267f458c2b23fdfd8b691e0953..af3fb403703da8c242ef1b492ade360c37b23222 100644 (file)
     "crossbeam-queue",
     "crossbeam-utils",
     "datafrog",
+    "difference",
     "digest",
     "dlmalloc",
     "either",
     "ena",
     "env_logger",
+    "expect-test",
     "fake-simd",
     "filetime",
     "flate2",