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

add snapshot testing #39

Merged
merged 1 commit into from
Jun 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 127 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ structopt = "0.2"
failure = "0.1"
rnix = "0.11"
rowan = "0.15.11"

[dev-dependencies]
insta = "1.29.0"
7 changes: 6 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@
};

devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [ cargo clippy rustfmt ];
buildInputs = with pkgs; [
cargo
cargo-insta
clippy
rustfmt
];
};
});
}
36 changes: 21 additions & 15 deletions src/commonmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
use failure::Error;
use std::iter::repeat;

use std::io::Write;

/// Represent a single function argument name and its (optional)
/// doc-string.
#[derive(Debug)]
Expand All @@ -38,18 +40,21 @@ pub enum Argument {
Pattern(Vec<SingleArg>),
}

fn print_indented(indent: usize, text: &str) {
fn print_indented<W: Write>(writer: &mut W, indent: usize, text: &str) -> Result<(), Error> {
let prefix = repeat(' ').take(indent).collect::<String>();
print!(
writeln!(
writer,
"{}",
text.replace("\r\n", "\n")
.replace("\n", &format!("\n{prefix}"))
);
)?;

Ok(())
}

impl Argument {
/// Write CommonMark structure for a single function argument.
fn write_argument(self, indent: usize) -> Result<(), Error> {
fn write_argument<W: Write>(self, writer: &mut W, indent: usize) -> Result<(), Error> {
match self {
// Write a flat argument entry.
Argument::Flat(arg) => {
Expand All @@ -58,15 +63,15 @@ impl Argument {
arg.name,
arg.doc.unwrap_or("Function argument".into()).trim()
);
print_indented(indent, &arg_text);
print_indented(writer, indent, &arg_text)?;
}

// Write a pattern argument entry and its individual
// parameters as a nested structure.
Argument::Pattern(pattern_args) => {
print_indented(indent, "structured function argument\n\n: ");
print_indented(writer, indent, "structured function argument\n\n: ")?;
for pattern_arg in pattern_args {
Argument::Flat(pattern_arg).write_argument(indent + 2)?;
Argument::Flat(pattern_arg).write_argument(writer, indent + 2)?;
}
}
}
Expand Down Expand Up @@ -101,31 +106,31 @@ pub struct ManualEntry {

impl ManualEntry {
/// Write a single CommonMark entry for a documented Nix function.
pub fn write_section(self) -> Result<(), Error> {
pub fn write_section<W: Write>(self, writer: &mut W) -> Result<(), Error> {
let title = format!("lib.{}.{}", self.category, self.name);
let ident = format!(
"lib.{}.{}",
self.category,
self.name.replace('\'', "-prime")
);

println!("## `{}` {{#function-library-{}}}\n", title, ident);
writeln!(writer, "## `{}` {{#function-library-{}}}\n", title, ident)?;

// <subtitle> (type signature)
if let Some(t) = &self.fn_type {
println!("`{}`\n", t);
writeln!(writer, "`{}`\n", t)?;
}

// Primary doc string
// TODO: Split paragraphs?
for paragraph in &self.description {
println!("{}\n", paragraph);
writeln!(writer, "{}\n", paragraph)?;
}

// Function argument names
if !self.args.is_empty() {
for arg in self.args {
arg.write_argument(0)?;
arg.write_argument(writer, 0)?;
}
}

Expand All @@ -134,11 +139,12 @@ impl ManualEntry {
// TODO: In grhmc's version there are multiple (named)
// examples, how can this be achieved automatically?
if let Some(example) = &self.example {
println!(
writeln!(
writer,
"### {} usage example {{#function-library-example-{}}}\n",
title, ident
);
println!("```nix{}```\n", example);
)?;
writeln!(writer, "```nix{}```\n", example)?;
}

// TODO: add source links
Expand Down
63 changes: 50 additions & 13 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ use rnix::{
use rowan::{ast::AstNode, WalkEvent};
use std::fs;

use std::io;
use std::io::Write;

use std::path::PathBuf;
use structopt::StructOpt;

Expand Down Expand Up @@ -239,13 +242,8 @@ fn collect_entry_information(entry: AttrpathValue) -> Option<DocItem> {
}
}

fn main() {
let opts = Options::from_args();
let src = fs::read_to_string(&opts.file).unwrap();
let nix = rnix::Root::parse(&src).ok().expect("failed to parse input");

let entries: Vec<_> = nix
.syntax()
fn collect_entries(root: rnix::Root, category: &str) -> Vec<ManualEntry> {
root.syntax()
.preorder()
.filter_map(|ev| match ev {
WalkEvent::Enter(n) => Some(n),
Expand All @@ -256,21 +254,60 @@ fn main() {
.filter_map(AttrpathValue::cast)
.filter_map(collect_entry_information)
.map(|d| ManualEntry {
category: opts.category.clone(),
category: category.to_string(),
name: d.name,
description: d.comment.doc.split("\n\n").map(|s| s.to_string()).collect(),
fn_type: d.comment.doc_type,
example: d.comment.example,
args: d.args,
})
.collect();
.collect()
}

fn main() {
let mut output = io::stdout();
let opts = Options::from_args();
let src = fs::read_to_string(&opts.file).unwrap();
let nix = rnix::Root::parse(&src).ok().expect("failed to parse input");

println!(
// TODO: move this to commonmark.rs
writeln!(
output,
"# {} {{#sec-functions-library-{}}}\n",
&opts.description, opts.category
);
)
.expect("Failed to write header");

for entry in collect_entries(nix, &opts.category) {
entry
.write_section(&mut output)
.expect("Failed to write section")
}
}

for entry in entries {
entry.write_section().expect("Failed to write section")
#[test]
fn test_main() {
let mut output = Vec::new();
let src = fs::read_to_string("test/strings.nix").unwrap();
let nix = rnix::Root::parse(&src).ok().expect("failed to parse input");
let desc = "string manipulation functions";
let category = "strings";

// TODO: move this to commonmark.rs
writeln!(
output,
"# {} {{#sec-functions-library-{}}}\n",
desc, category
)
.expect("Failed to write header");

for entry in collect_entries(nix, category) {
entry
.write_section(&mut output)
.expect("Failed to write section")
}

let output = String::from_utf8(output).expect("not utf8");

insta::assert_snapshot!(output);
}
Loading