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

chore(tests): improving test coverage for the CLI #88

Merged
merged 8 commits into from
May 30, 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
4 changes: 0 additions & 4 deletions .github/workflows/rustlib.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,4 @@ jobs:
uses: Swatinem/rust-cache@v2

- run: curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin
- run: cargo install --path . --all-features --debug
- run: cat LICENSE.md | ltrs check
- run: ltrs languages
- run: ltrs check -t "Some text with a apparent mistake"
- run: cargo nextest run --all-features
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Moved LanguageTool docker image to service in GitHub action. [#87](https://github.com/jeertmans/languagetool-rust/pull/87)
- Added automatic benchmarks comparison to CI. [#89](https://github.com/jeertmans/languagetool-rust/pull/89)
- Improving test coverage. [#88](https://github.com/jeertmans/languagetool-rust/pull/88)

## [2.1.2](https://github.com/jeertmans/languagetool-rust/compare/v2.1.1...v2.1.2) 2023-05-29

Expand Down
120 changes: 120 additions & 0 deletions Cargo.lock

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

8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ thiserror = "^1.0"
tokio = {version = "^1.0", features = ["macros", "rt-multi-thread"], optional = true}

[dev-dependencies]
assert_cmd = "2.0.11"
criterion = "0.3"
futures = "0.3"
predicates = "3.0.3"
tempfile = "3.5.0"
tokio = {version = "^1.0", features = ["macros"]}

[features]
Expand Down Expand Up @@ -59,6 +62,11 @@ version = "2.1.2"
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[[test]]
name = "cli"
path = "tests/cli.rs"
required-features = ["cli"]

[[test]]
name = "match-positions"
path = "tests/match_positions.rs"
Expand Down
48 changes: 23 additions & 25 deletions benches/benchmarks/check_texts.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
use criterion::{black_box, criterion_group, Criterion};
use criterion::{criterion_group, Criterion, Throughput};
use futures::future::join_all;
use languagetool_rust::{
check::{CheckRequest, CheckResponse, CheckResponseWithContext},
error::Error,
server::ServerClient,
};

static FILES: [(&str, &str); 3] = [
("small", include_str!("../small.txt")),
("medium", include_str!("../medium.txt")),
("large", include_str!("../large.txt")),
];

async fn request_until_success(req: &CheckRequest, client: &ServerClient) -> CheckResponse {
loop {
match client.check(req).await {
Expand Down Expand Up @@ -54,30 +60,22 @@ async fn check_text_split(text: &str) -> CheckResponse {
.into()
}

#[macro_export]
macro_rules! compare_checks_on_file {
($name:ident, $filename:expr) => {
fn $name(c: &mut Criterion) {
let content = std::fs::read_to_string($filename).unwrap();
let text = content.as_str();
let name = stringify!($name);
c.bench_function(format!("Check basic for {}", name).as_str(), |b| {
b.iter(|| check_text_basic(black_box(text)))
});
c.bench_function(format!("Check split for {}", name).as_str(), |b| {
b.iter(|| check_text_split(black_box(text)))
});
}
};
fn bench_basic(c: &mut Criterion) {
let mut group = c.benchmark_group("basic");

for (name, source) in FILES {
group.throughput(Throughput::Bytes(source.len() as u64));
group.bench_with_input(name, &source, |b, &s| b.iter(|| check_text_basic(s)));
}
}

compare_checks_on_file!(compare_checks_small_file, "./benches/small.txt");
compare_checks_on_file!(compare_checks_medium_file, "./benches/medium.txt");
compare_checks_on_file!(compare_checks_large_file, "./benches/large.txt");
fn bench_split(c: &mut Criterion) {
let mut group = c.benchmark_group("split");

for (name, source) in FILES {
group.throughput(Throughput::Bytes(source.len() as u64));
group.bench_with_input(name, &source, |b, &s| b.iter(|| check_text_split(s)));
}
}

criterion_group!(
checks,
compare_checks_small_file,
compare_checks_medium_file,
compare_checks_large_file
);
criterion_group!(checks, bench_basic, bench_split,);
45 changes: 41 additions & 4 deletions src/lib/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ pub struct CheckRequest {
/// should set variants for at least German and English, as otherwise the
/// spell checking will not work for those, as no spelling dictionary can be
/// selected for just `en` or `de`.
#[cfg_attr(feature = "cli", clap(long))]
#[cfg_attr(feature = "cli", clap(long, conflicts_with = "language"))]
#[serde(serialize_with = "serialize_option_vec_string")]
pub preferred_variants: Option<Vec<String>>,
/// IDs of rules to be enabled, comma-separated.
Expand Down Expand Up @@ -651,7 +651,7 @@ fn parse_filename(s: &str) -> Result<PathBuf> {
#[derive(Debug, Parser)]
pub struct CheckCommand {
/// If present, raw JSON output will be printed instead of annotated text.
/// This has not effect if `--data` is used, because it is never
/// This has no effect if `--data` is used, because it is never
/// annotated.
#[cfg(feature = "cli")]
#[clap(short = 'r', long)]
Expand Down Expand Up @@ -1182,8 +1182,7 @@ impl<'source> Iterator for MatchPositions<'source, std::slice::IterMut<'source,

#[cfg(test)]
mod tests {

use crate::check::{Data, DataAnnotation};
use super::*;

#[derive(Debug)]
enum Token<'source> {
Expand Down Expand Up @@ -1229,4 +1228,42 @@ mod tests {

assert_eq!(data, expected_data);
}

#[test]
fn test_serialize_option_vec_string() {
use serde::Serialize;

#[derive(Serialize)]
struct Foo {
#[serde(serialize_with = "serialize_option_vec_string")]
values: Option<Vec<String>>,
}

impl Foo {
fn new<I, T>(values: I) -> Self
where
I: IntoIterator<Item = T>,
T: ToString,
{
Self {
values: Some(values.into_iter().map(|v| v.to_string()).collect()),
}
}
fn none() -> Self {
Self { values: None }
}
}

let got = serde_json::to_string(&Foo::new(vec!["en-US", "de-DE"])).unwrap();
assert_eq!(got, r#"{"values":"en-US,de-DE"}"#);

let got = serde_json::to_string(&Foo::new(vec!["en-US"])).unwrap();
assert_eq!(got, r#"{"values":"en-US"}"#);

let got = serde_json::to_string(&Foo::new(Vec::<String>::new())).unwrap();
assert_eq!(got, r#"{"values":null}"#);

let got = serde_json::to_string(&Foo::none()).unwrap();
assert_eq!(got, r#"{"values":null}"#);
}
}
Loading