1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 //! Various utility functions used in tests.
16
17 // This file is included directly into integration tests in the
18 // `tests/` directory. These tests are compiled without access to the
19 // rest of the `pdl` crate. To make this work, avoid `use crate::`
20 // statements below.
21
22 use googletest::prelude::{assert_that, eq};
23 use std::fs;
24 use std::path::Path;
25
26 /// Format Rust code in `input`.
format_rust(input: &str) -> String27 pub fn format_rust(input: &str) -> String {
28 let syntax_tree = syn::parse_file(input).expect("Could not parse {input:#?} as Rust code");
29 let formatted = prettyplease::unparse(&syntax_tree);
30 format!("#![rustfmt::skip]\n{formatted}")
31 }
32
33 /// Compare a string with a snapshot file.
34 ///
35 /// The `snapshot_path` is relative to the current working directory
36 /// of the test binary. This depends on how you execute the tests:
37 ///
38 /// * When using `atest`: The current working directory is a random
39 /// temporary directory. You need to ensure that the snapshot file
40 /// is installed into this directory. You do this by adding the
41 /// snapshot to the `data` attribute of your test rule
42 ///
43 /// * When using Cargo: The current working directory is set to
44 /// `CARGO_MANIFEST_DIR`, which is where the `Cargo.toml` file is
45 /// found.
46 ///
47 /// If you run the test with Cargo and the `UPDATE_SNAPSHOTS`
48 /// environment variable is set, then the `actual_content` will be
49 /// written to `snapshot_path`. Otherwise the content is compared and
50 /// a panic is triggered if they differ.
51 #[track_caller]
assert_snapshot_eq<P: AsRef<Path>>(snapshot_path: P, actual_content: &str)52 pub fn assert_snapshot_eq<P: AsRef<Path>>(snapshot_path: P, actual_content: &str) {
53 let update_snapshots = std::env::var("UPDATE_SNAPSHOTS").is_ok();
54 let snapshot = snapshot_path.as_ref();
55 let snapshot_content = match fs::read(snapshot) {
56 Ok(content) => content,
57 Err(_) if update_snapshots => Vec::new(),
58 Err(err) => panic!("Could not read snapshot from {}: {}", snapshot.display(), err),
59 };
60 let snapshot_content = String::from_utf8(snapshot_content).expect("Snapshot was not UTF-8");
61
62 // Normal comparison if UPDATE_SNAPSHOTS is unset.
63 if !update_snapshots {
64 assert_that!(actual_content, eq(&snapshot_content));
65 }
66
67 // Bail out if we are not using Cargo.
68 if std::env::var("CARGO_MANIFEST_DIR").is_err() {
69 panic!("Please unset UPDATE_SNAPSHOTS if you are not using Cargo");
70 }
71
72 if actual_content != snapshot_content {
73 eprintln!(
74 "Updating snapshot {}: {} -> {} bytes",
75 snapshot.display(),
76 snapshot_content.len(),
77 actual_content.len()
78 );
79 fs::write(&snapshot_path, actual_content).unwrap_or_else(|err| {
80 panic!("Could not write snapshot to {}: {}", snapshot.display(), err)
81 });
82 }
83 }
84