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

feature: debug_string_snapshot to test pretty printers #707

Open
honungsburk opened this issue Jan 8, 2025 · 4 comments
Open

feature: debug_string_snapshot to test pretty printers #707

honungsburk opened this issue Jan 8, 2025 · 4 comments

Comments

@honungsburk
Copy link

I'm writing a DSL and would like to use insta to snapshot test my pretty printer and my diagnostics messages. Is it already possible somehow and I've just missed it or would debug_string_snapshot make a nice addition to the library?

@honungsburk honungsburk changed the title debug_string_snapshot to test pretty printers feature: debug_string_snapshot to test pretty printers Jan 8, 2025
@max-sixty
Copy link
Collaborator

Could you give an example? Would assert_debug_snapshot work?

@honungsburk
Copy link
Author

For example, you could have a typescript pretty printer that takes this as input

function  greet(name:string){console.log("Hello, "+name);}const name="Alice";greet(name);

and outputs this:

function greet(name: string): void {
  console.log("Hello, " + name);
}

const name = "Alice";
greet(name);

Then it would be nice to see that the formatting stays the same as you are refactoring.

I think assert_debug_snapshot would work if I created a wrapper struct for String and implemented such that it does not escape newline characters.

However, I have used similar libraries to insta in other languages and they only expected to be given some arbitrary string. I was surprised that this was not directly supported.

@max-sixty
Copy link
Collaborator

Can you give a rust code example?

@honungsburk
Copy link
Author

honungsburk commented Jan 9, 2025

I got it working using debug.

The idea is that I want to quickly iterate on the quality of my error messages and it is a pain to run my CLI too all the time (and I want to catch regressions) so I dump a bunch of code for my custom DSL into a directory and then have it check each file individually for errors.

input file:

@doc "hello"
@doc "world"
collection Person {
    name: string
}

output file:

---
source: packages/cli/tests/diagnostics_report_test.rs
assertion_line: 40
expression: PrintString(report_string)
snapshot_kind: text
---
[E0013] Error: Decorator '@doc' is already defined.
   ╭─[/Users/frankhampusweslien/git/frank/graphite-lang/packages/cli/tests/diagnostics_report_input/duplicate_decorator.gr:1:1]
   │
 1 │ @doc "hello"
   │ ──┬─  
   │   ╰─── error here
───╯
[E0013] Error: Decorator '@doc' is already defined.
   ╭─[/Users/frankhampusweslien/git/frank/graphite-lang/packages/cli/tests/diagnostics_report_input/duplicate_decorator.gr:2:1]
   │
 2 │ @doc "world"
   │ ──┬─  
   │   ╰─── error here
───╯

testing code:

use ariadne::FileCache;
use graphite_cli::diagnostics_report;
use graphite_core::pipeline;
use std::path::PathBuf;

struct PrintString(String);

impl std::fmt::Debug for PrintString {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.0)
    }
}

/// Regression tests for diagnostics report. Run `cargo test` to check that all the tests pass.
#[test]
fn test_parser_regression() {
    let test_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("tests")
        .join("diagnostics_report_input");

    let mut failures = Vec::new();

    for entry in std::fs::read_dir(test_dir).unwrap() {
        let entry = entry.unwrap();
        let file_name = entry.file_name().to_str().unwrap().to_string();
        let result = std::panic::catch_unwind(|| {
            let file_path = entry.path();

            let diagnostics = pipeline::check(file_path);

            // Build and render the diagnostic report

            let mut buffer = Vec::new();
            for diagnostic in diagnostics {
                let report = diagnostics_report::build(&diagnostic);
                report.write(FileCache::default(), &mut buffer).unwrap();
            }
            let report_string = String::from_utf8(strip_ansi_escapes::strip(&buffer)).unwrap();
            // Assert the snapshot
            insta::assert_debug_snapshot!(file_name.clone(), PrintString(report_string));
        });

        if result.is_err() {
            failures.push(file_name.to_string());
        }
    }

    if !failures.is_empty() {
        panic!("Diagnostic report tests failed for files: {:?}", failures);
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants