Skip to content

Commit

Permalink
add ci testing for markdown toml fences
Browse files Browse the repository at this point in the history
  • Loading branch information
Emilgardis committed Apr 6, 2022
1 parent 4a858e5 commit 05b4a3b
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: test
args: --locked
args: --locked --all-targets --workspace
timeout-minutes: 5

generate-matrix:
Expand Down
59 changes: 58 additions & 1 deletion Cargo.lock

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

6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ atty = "0.2"
color-eyre = "0.6"
eyre = "0.6"
home = "0.5"
lazy_static = "1"
rustc_version = "0.4"
toml = "0.5"
which = { version = "4", default_features = false }
Expand All @@ -33,3 +32,8 @@ dunce = "1"

[profile.release]
lto = true

[dev-dependencies]
regex = "1"
once_cell = "1"
walkdir = "2"
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,15 +226,15 @@ non-standard targets (i.e. something not reported by rustc/rustup). However,
you can use the `build.xargo` or `target.{{TARGET}}.xargo` field in
`Cross.toml` to force the use of `xargo`:

``` toml
```toml
# all the targets will use `xargo`
[build]
xargo = true
```

Or,

``` toml
```toml
# only this target will use `xargo`
[target.aarch64-unknown-linux-gnu]
xargo = true
Expand Down
2 changes: 1 addition & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ mod tests {
use std::matches;

fn toml(content: &str) -> Result<crate::CrossToml> {
Ok(CrossToml::from_str(content).wrap_err("couldn't parse toml")?)
Ok(CrossToml::parse(content).wrap_err("couldn't parse toml")?.0)
}

#[test]
Expand Down
16 changes: 8 additions & 8 deletions src/cross_toml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use crate::errors::*;
use crate::{Target, TargetList};
use serde::Deserialize;
use std::collections::HashMap;
use std::collections::{BTreeSet, HashMap};

/// Environment configuration
#[derive(Debug, Deserialize, PartialEq, Default)]
Expand Down Expand Up @@ -45,10 +45,10 @@ pub struct CrossToml {

impl CrossToml {
/// Parses the [`CrossToml`] from a string
pub fn from_str(toml_str: &str) -> Result<Self> {
pub fn parse(toml_str: &str) -> Result<(Self, BTreeSet<String>)> {
let tomld = &mut toml::Deserializer::new(toml_str);

let mut unused = std::collections::BTreeSet::new();
let mut unused = BTreeSet::new();

let cfg = serde_ignored::deserialize(tomld, |path| {
unused.insert(path.to_string());
Expand All @@ -57,11 +57,11 @@ impl CrossToml {
if !unused.is_empty() {
eprintln!(
"Warning: found unused key(s) in Cross configuration:\n > {}",
unused.into_iter().collect::<Vec<_>>().join(", ")
unused.clone().into_iter().collect::<Vec<_>>().join(", ")
);
}

Ok(cfg)
Ok((cfg, unused))
}

/// Returns the `target.{}.image` part of `Cross.toml`
Expand Down Expand Up @@ -128,7 +128,7 @@ mod tests {
targets: HashMap::new(),
build: CrossBuildConfig::default(),
};
let parsed_cfg = CrossToml::from_str("")?;
let (parsed_cfg, _) = CrossToml::parse("")?;

assert_eq!(parsed_cfg, cfg);

Expand Down Expand Up @@ -157,7 +157,7 @@ mod tests {
volumes = ["VOL1_ARG", "VOL2_ARG"]
passthrough = ["VAR1", "VAR2"]
"#;
let parsed_cfg = CrossToml::from_str(test_str)?;
let (parsed_cfg, _) = CrossToml::parse(test_str)?;

assert_eq!(parsed_cfg, cfg);

Expand Down Expand Up @@ -195,7 +195,7 @@ mod tests {
xargo = false
image = "test-image"
"#;
let parsed_cfg = CrossToml::from_str(test_str)?;
let (parsed_cfg, _) = CrossToml::parse(test_str)?;

assert_eq!(parsed_cfg, cfg);

Expand Down
5 changes: 4 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#![deny(missing_debug_implementations, rust_2018_idioms)]

#[cfg(test)]
mod tests;

mod cargo;
mod cli;
mod config;
Expand Down Expand Up @@ -405,7 +408,7 @@ fn toml(root: &Root) -> Result<Option<CrossToml>> {
let content = file::read(&path)
.wrap_err_with(|| format!("could not read file `{}`", path.display()))?;

let config = CrossToml::from_str(&content)
let (config, _) = CrossToml::parse(&content)
.wrap_err_with(|| format!("failed to parse file `{}` as TOML", path.display()))?;

Ok(Some(config))
Expand Down
53 changes: 53 additions & 0 deletions src/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
mod toml;

use std::{
ffi::OsStr,
path::{Path, PathBuf},
};

use once_cell::sync::OnceCell;
use serde::Deserialize;

static WORKSPACE: OnceCell<PathBuf> = OnceCell::new();

/// Returns the cargo workspace for the manifest
pub fn get_cargo_workspace() -> &'static Path {
let manifest_dir = env!("CARGO_MANIFEST_DIR");
WORKSPACE.get_or_init(|| {
#[derive(Deserialize)]
struct Manifest {
workspace_root: PathBuf,
}
let output = std::process::Command::new(
std::env::var("CARGO")
.ok()
.unwrap_or_else(|| "cargo".to_string()),
)
.arg("metadata")
.arg("--format-version=1")
.arg("--no-deps")
.current_dir(manifest_dir)
.output()
.unwrap();
let manifest: Manifest = serde_json::from_slice(&output.stdout).unwrap();
manifest.workspace_root
})
}

pub fn walk_dir<'a>(
root: &'_ Path,
skip: &'a [impl AsRef<OsStr>],
) -> impl Iterator<Item = Result<walkdir::DirEntry, walkdir::Error>> + 'a {
walkdir::WalkDir::new(root).into_iter().filter_entry(|e| {
if skip
.iter()
.map(|s| -> &std::ffi::OsStr { s.as_ref() })
.any(|dir| e.file_name() == dir)
{
return false;
} else if e.file_type().is_dir() {
return true;
}
e.path().extension() == Some("md".as_ref())
})
}
63 changes: 63 additions & 0 deletions src/tests/toml.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use std::io::Read;

use once_cell::sync::Lazy;
use regex::{Regex, RegexBuilder};

static TOML_REGEX: Lazy<Regex> = Lazy::new(|| {
RegexBuilder::new(r#"```toml\n(.*?)```"#)
.multi_line(true)
.dot_matches_new_line(true)
.build()
.unwrap()
});

#[test]
fn toml_check() -> Result<(), Box<dyn std::error::Error>> {
let workspace_root = super::get_cargo_workspace();
let walk = super::walk_dir(
workspace_root,
&[
"target",
".git",
"src",
"CODE_OF_CONDUCT.md",
"CHANGELOG.md",
],
);

for dir_entry in walk {
let dir_entry = dir_entry?;
if dir_entry.file_type().is_dir() {
continue;
}
eprintln!("File: {:?}", dir_entry.path().display());
let mut file = std::fs::File::open(dir_entry.path()).unwrap();
let mut contents = String::new();
file.read_to_string(&mut contents).unwrap();
for matches in TOML_REGEX.captures_iter(&contents) {
let fence = matches.get(1).unwrap();
eprintln!(
"testing snippet at: {}:{:?}",
dir_entry.path().display(),
text_line_no(&contents, fence.range().start),
);
assert!(crate::cross_toml::CrossToml::parse(fence.as_str())?
.1
.is_empty());
}
}
Ok(())
}

pub fn text_line_no(text: &str, index: usize) -> usize {
let mut line_no = 0;
let mut count = 0;
for line in text.split('\n') {
line_no += 1;
count += line.as_bytes().len() + 1;
if count >= index {
break;
}
}
line_no
}

0 comments on commit 05b4a3b

Please sign in to comment.