Skip to content

Commit

Permalink
PR #38 mv test suites from main crate
Browse files Browse the repository at this point in the history
Merge branch 'test_crates'
  • Loading branch information
hellux committed May 4, 2023
2 parents e8f2002 + 2ca5f20 commit e209143
Show file tree
Hide file tree
Showing 19 changed files with 192 additions and 59 deletions.
12 changes: 6 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ jobs:
RUSTDOCFLAGS: -D warnings
run: |
make check
suite:
name: Build and run external tests
test_html:
name: Build and run HTML tests
runs-on: ubuntu-latest
steps:
- name: "Checkout repo"
Expand All @@ -44,14 +44,14 @@ jobs:
run: |
rustup update 1.56
rustup default 1.56
- name: "Run unit tests"
run: make suite
- name: "Run HTML unit tests"
run: make test_html_ut
- name: "Setup node"
uses: actions/setup-node@v3
with:
node-version: 18
- name: "Compare benchmark files"
run: make suite_bench
- name: "Compare HTML with reference implementation"
run: make test_html_ref
lint:
name: Lint
runs-on: ubuntu-latest
Expand Down
14 changes: 14 additions & 0 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ members = [
"bench/iai",
"bench/input",
"examples/jotdown_wasm",
"tests/html-ref",
"tests/html-ut",
]
exclude = [
"tests/afl",
Expand All @@ -39,6 +41,4 @@ doc = false
[features]
default = ["html"]
html = [] # html renderer and minimal cli binary
suite = [] # test suite
suite_bench = [] # bench test suite
deterministic = [] # for stable fuzzing
38 changes: 18 additions & 20 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,34 +15,34 @@ docs:

.PHONY: lint
lint:
cargo clippy --workspace -- -D warnings
cargo clippy --workspace --no-default-features -- -D warnings
cargo clippy --workspace --all-features -- -D warnings
cargo fmt --all -- --check
cargo clippy -- -D warnings
cargo clippy --no-default-features -- -D warnings
cargo clippy --all-features -- -D warnings

.PHONY: check
check:
cargo test --workspace
cargo test --workspace --no-default-features

.PHONY: suite
suite:
.PHONY: test_html_ut
test_html_ut:
git submodule update --init modules/djot.js
for f in $$(find modules/djot.js/test -name '*.test' | xargs basename -a); do \
ln -fs ../../modules/djot.js/test/$$f tests/suite/djot_js_$$f; \
ln -fs ../../../modules/djot.js/test/$$f tests/html-ut/ut/djot_js_$$f; \
done
(cd tests/suite && make)
cargo test --features suite suite::
cargo test -p test-html-ut
cargo test -p test-html-ut -- --ignored 2>/dev/null | grep -q 'test result: FAILED. 0 passed'

.PHONY: suite_bench
suite_bench:
.PHONY: test_html_ref
test_html_ref:
git submodule update --init modules/djot.js
for f in $$(find modules/djot.js/bench -name '*.dj' | xargs basename -a); do \
dst=$$(echo $$f | sed 's/-/_/g'); \
ln -fs ../../modules/djot.js/bench/$$f tests/bench/$$dst; \
ln -fs ../../modules/djot.js/bench/$$f tests/html-ref/$$dst; \
done
(cd tests/bench && make)
cargo test --features suite_bench bench::
cargo test -p test-html-ref
cargo test -p test-html-ref -- --ignored 2>/dev/null | grep -q 'test result: FAILED. 0 passed'

.PHONY: bench
bench:
Expand All @@ -52,9 +52,6 @@ bench:
ln -fs ../../modules/djot.js/bench/$$f bench/input/$$dst; \
done

cov: suite suite_bench
LLVM_COV=llvm-cov LLVM_PROFDATA=llvm-profdata cargo llvm-cov --features=suite,suite_bench --workspace --html --ignore-run-fail

AFL_TARGET?=parse
AFL_JOBS?=1
AFL_TARGET_CRASH?=crashes
Expand Down Expand Up @@ -101,11 +98,12 @@ afl_tmin:

clean:
cargo clean
rm -rf bench/iai/target
git submodule deinit -f --all
find tests -type l -path 'tests/suite/*.test' -print0 | xargs -0 rm -f
(cd tests/suite && make clean)
rm -f tests/bench/*.dj
(cd tests/bench && make clean)
find tests -type l -path 'tests/html-ut/ut/*.test' -print0 | xargs -0 rm -f
(cd tests/html-ut && make clean)
rm -f tests/html-ref/*.dj
(cd tests/html-ref && make clean)
find bench -type l -path 'bench/*.dj' -print0 | xargs -0 rm -f
rm -rf tests/afl/out
(cd examples/jotdown_wasm && make clean)
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,19 +121,19 @@ including:
- footnotes.

The HTML output is in some cases not exactly identical to the [reference
implementation][djot-js]. There are two test suites that compares Jotdown with
the reference implementation. One uses the unit tests of the reference
implementation and runs them with Jotdown. It can be run with:
implementation][djot-js]. There are two test suites that compares Jotdown's
HTML output with that of the reference implementation. One uses the unit tests
of the reference implementation and runs them with Jotdown. It can be run with:

```
$ make suite
$ make test_html_ut
```

Another target uses the reference implementation to generate html output for
its benchmark files and compares it to the output of Jotdown:

```
$ make suite_bench
$ make test_html_ref
```

Note that it requires node in order to run the reference implementation.
Expand Down
5 changes: 4 additions & 1 deletion src/html.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,10 @@ impl<'s> Writer<'s> {
Event::Softbreak => out.write_char('\n')?,
Event::Escape | Event::Blankline => {}
Event::ThematicBreak(attrs) => {
out.write_str("\n<hr")?;
if self.not_first_line {
out.write_char('\n')?;
}
out.write_str("<hr")?;
for (a, v) in attrs.iter() {
write!(out, r#" {}=""#, a)?;
v.parts().try_for_each(|part| write_attr(part, &mut out))?;
Expand Down
12 changes: 12 additions & 0 deletions tests/html-ref/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "test-html-ref"
description = "Reference implementation HTML output comparison tests"
version = "0.1.0"
edition = "2021"

[dependencies]
jotdown = { path = "../.." }

[lib]
name = "test_html_ref"
path = "lib.rs"
13 changes: 6 additions & 7 deletions tests/bench/Makefile → tests/html-ref/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ TEST=${TEST_DJ:.dj=}
DJOT_JS=../../modules/djot.js
DJOT_JS_SRC=$(shell find ${DJOT_JS}/src -name '.ts')

mod.rs: ${TEST_DJ} html
echo "use crate::suite_test;" > $@
ref.rs: ${TEST_DJ} html
echo "use crate::compare;" > $@
for name in ${TEST}; do \
name_snake=$$(basename -a $$name); \
skip_reason=$$(grep -E "^$${name_snake}:" skip | cut -d: -f2); \
Expand All @@ -17,10 +17,8 @@ mod.rs: ${TEST_DJ} html
printf ' let src = r###"'; \
cat $$name.dj; \
echo '"###;'; \
printf ' let expected = r###"'; \
cat $$name.html; \
echo '"###;'; \
echo " suite_test!(src, expected);"; \
printf ' let expected = "%s";' "$$name.html"; \
echo " compare!(src, expected);"; \
echo "}"; \
done >> $@

Expand All @@ -36,6 +34,7 @@ djot-js: ${DJOT_JS_SRC}
chmod +x $@

clean:
rm -f *.rs *.html
rm -f ref.rs
rm -f *.html
rm -f html
rm -f djot-js
17 changes: 17 additions & 0 deletions tests/html-ref/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
fn main() {
let has_dj = std::fs::read_dir(".").unwrap().any(|e| {
e.map_or(false, |e| {
e.path()
.extension()
.map_or(false, |ext| ext.to_str() == Some("dj"))
})
});
if has_dj {
let status = std::process::Command::new("make")
.status()
.expect("failed to execute make");
assert!(status.success());
} else {
std::fs::write("ref.rs", &[b'\n']).unwrap();
}
}
32 changes: 32 additions & 0 deletions tests/html-ref/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#[cfg(test)]
mod r#ref;

#[macro_export]
macro_rules! compare {
($src:expr, $expected:expr) => {
use jotdown::Render;
let src = $src;
let expected = std::fs::read_to_string($expected).expect("read failed");
let p = jotdown::Parser::new(src);
let mut actual = String::new();
jotdown::html::Renderer::default()
.push(p, &mut actual)
.unwrap();
assert_eq!(actual, expected, "\n{}", {
use std::io::Write;
let mut child = std::process::Command::new("diff")
.arg("--color=always")
.arg("-")
.arg($expected)
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.spawn()
.expect("spawn diff failed");
let mut stdin = child.stdin.take().unwrap();
let actual = actual.clone();
std::thread::spawn(move || stdin.write_all(actual.as_bytes()).unwrap());
let stdout = child.wait_with_output().unwrap().stdout;
String::from_utf8(stdout).unwrap()
});
};
}
File renamed without changes.
12 changes: 12 additions & 0 deletions tests/html-ut/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "test-html-ut"
description = "HTML output unit tests."
version = "0.1.0"
edition = "2021"

[dependencies]
jotdown = { path = "../.." }

[lib]
name = "test_html_ut"
path = "lib.rs"
14 changes: 6 additions & 8 deletions tests/suite/Makefile → tests/html-ut/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,23 @@

.SUFFIXES: .test .rs

TEST=$(shell find . -name '*.test' | sort)
TEST=$(shell find ut -name '*.test' | sort)
TEST_RS=${TEST:.test=.rs}

BLACKLIST += djot_js_filters # lua filters not implemented
BLACKLIST += djot_js_symb # uses ast
BLACKLIST += djot_js_sourcepos # not parsable

.PHONY: suite
suite: mod.rs

mod.rs: ${TEST_RS}
printf "" > $@
ut/mod.rs: ${TEST_RS}
mkdir -p ut
rm -f $@
for f in ${TEST}; do \
name=$$(basename -s .test $$f); \
echo ${BLACKLIST} | tr ' ' '\n' | grep -q $$name || echo "mod $$name;" >> $@; \
done

.test.rs:
gawk -fgen.awk $< > $@
gawk -fgen.awk $< | head -n-1 > $@

clean:
rm -f *.rs
rm -f ut/*.rs
6 changes: 6 additions & 0 deletions tests/html-ut/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
fn main() {
let status = std::process::Command::new("make")
.status()
.expect("failed to execute make");
assert!(status.success());
}
47 changes: 47 additions & 0 deletions tests/html-ut/cmp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#[macro_export]
macro_rules! compare {
($src:expr, $expected:expr) => {
use jotdown::Render;
let src = $src;
let expected = $expected;
let p = jotdown::Parser::new(src);
let mut actual = String::new();
jotdown::html::Renderer::default()
.push(p, &mut actual)
.unwrap();
assert_eq!(
actual.trim(),
expected.trim(),
concat!(
"\n",
"\x1b[0;1m========================= INPUT ============================\x1b[0m\n",
"\x1b[2m{}",
"\x1b[0;1m=================== ACTUAL vs EXPECTED =====================\x1b[0m\n",
"{}",
"\x1b[0;1m============================================================\x1b[0m\n",
),
$src,
{
let a = actual.trim().split('\n');
let b = expected.trim().split('\n');
let max = a.clone().count().max(b.clone().count());
let a_width = a.clone().map(|a| a.len()).max().unwrap_or(0);
a.chain(std::iter::repeat(""))
.zip(b.chain(std::iter::repeat("")))
.take(max)
.map(|(a, b)| {
format!(
"\x1b[{}m{:a_width$}\x1b[0m {}= \x1b[{}m{}\x1b[0m\n",
if a == b { "2" } else { "31" },
a,
if a == b { '=' } else { '!' },
if a == b { "2" } else { "32" },
b,
a_width = a_width,
)
})
.collect::<String>()
},
);
};
}
4 changes: 2 additions & 2 deletions tests/suite/gen.awk → tests/html-ut/gen.awk
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
BEGIN {
FS=":"
while (getline < "skip") skips[$1]=$2
print "use crate::suite_test;"
print "use crate::compare;"
print ""
}

Expand All @@ -20,7 +20,7 @@ $0 ~ "^`{3,}$" {
close("src")
system("rm -f src")
print "\"##;"
print " suite_test!(src, expected);"
print " compare!(src, expected);"
print "}"
print ""
}
Expand Down
Loading

0 comments on commit e209143

Please sign in to comment.