diff --git a/.github/workflows/code-coverage-deploy.yml b/.github/workflows/code-coverage-deploy.yml index e9113c516e..4f0a40d45a 100644 --- a/.github/workflows/code-coverage-deploy.yml +++ b/.github/workflows/code-coverage-deploy.yml @@ -97,6 +97,7 @@ jobs: commit-message: "Actions: Update coverage indexes" comment: + permissions: write-all needs: deploy-coverage runs-on: ubuntu-latest steps: @@ -114,51 +115,6 @@ jobs: key: ${{ runner.os }}-${{ env.rust_release }}-${{ github.event.repository.updated_at }} restore-keys: ${{ runner.os }}-${{ env.rust_release }} - - name: Install rust ${{ env.rust_release }} - run: rustup update ${{ env.rust_release }} && rustup default ${{ env.rust_release }} - - # from https://github.com/bewee/rustdoc-coverage-action-example/ - - name: Fetch base - run: git fetch origin ${{ github.event.workflow_run.event.pull_request.base.sha }} - - - name: Checkout base - run: git checkout ${{ github.event.workflow_run.event.pull_request.base.sha }} - - - name: Calculate base doc coverage - uses: bewee/rustdoc-coverage-action@v1 - - name: Fetch head - run: git fetch origin ${{ github.event.workflow_run.event.pull_request.head.sha }} - - name: Checkout head - run: git checkout ${{ github.event.workflow_run.event.pull_request.head.sha }} - - - name: Calculate doc coverage - id: coverage - uses: bewee/rustdoc-coverage-action@v1 - - - name: Download code coverage info for main - run: | - wget https://conjure-cp.github.io/coverage/main/lcov.info - - - - name: Find coverage comment - uses: peter-evans/find-comment@v1 - id: fc - with: - issue-number: ${{ github.event.workflow_run.event.pull_request.number }} - comment-author: "github-actions[bot]" - body-includes: "## Documentation Coverage" - - - name: Delete coverage comment if it exists - if: steps.fc.outputs.comment-id != '' - uses: actions/github-script@v6 - with: - script: | - github.rest.issues.deleteComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: ${{ steps.fc.outputs.comment-id }} - }) - - name: Set shas id: sha uses: actions/github-script@v6 @@ -177,54 +133,103 @@ jobs: // whatever GITHUB_SHA is. return callee_run.head_sha; - - name: Install lcov - run: | - sudo apt-get install -y lcov + - name: Download artifact + uses: dawidd6/action-download-artifact@v2 + with: + name: code-coverage-${{ steps.sha.outputs.result }} + workflow: code-coverage.yml + path: ./deploy + + - name: Get PR number + id: prnum + run: | + echo "num=$(cat deploy/prnumber)" > $GITHUB_OUTPUT + + - name: Install rust ${{ env.rust_release }} + run: rustup update ${{ env.rust_release }} && rustup default ${{ env.rust_release }} - - name: Generate lcov summary for main - id: lcov-main + - name: Generate lcov summary for main and pr + continue-on-error: true + id: lcov run: | - wget https://conjure-cp.github.io/coverage/main/lcov.info - echo "summary=$(lcov --summary lcov.info --exclude '.cargo/**/*.rs')" >> "$GITHUB_OUTPUT" - - name: Generate lcov summary for PR - id: lcov-pr + sudo apt-get install -y lcov + wget https://${{github.repository_owner}}.github.io/conjure-oxide/coverage/main/lcov.info + lcov --summary lcov.info > cov.txt + echo "main<> $GITHUB_OUTPUT + echo "$(cat cov.txt | tail -n +3)" >> $GITHUB_OUTPUT + echo 'EOFABC' >> $GITHUB_OUTPUT + + lcov --summary ./deploy/lcov.info > cov.txt + echo "pr<> $GITHUB_OUTPUT + echo "$(cat cov.txt | tail -n +3)" >> $GITHUB_OUTPUT + echo 'EOFABC' >> $GITHUB_OUTPUT + + - name: Get doc-coverage for main and pr + id: doccov run: | - wget https://conjure-cp.github.io/coverage/${{steps.sha.outputs.result}}/lcov.info - echo "summary=$(lcov --summary lcov.info --exclude '.cargo/**/*.rs')" >> "$GITHUB_OUTPUT" + wget https://${{github.repository_owner}}.github.io/conjure-oxide/coverage/main/doc-coverage.txt + echo "main<> $GITHUB_OUTPUT + echo "$(cat doc-coverage.txt)" >> $GITHUB_OUTPUT + echo 'EOFABC' >> $GITHUB_OUTPUT + echo "pr<> $GITHUB_OUTPUT + echo "$(cat ./deploy/doc-coverage.txt)" >> $GITHUB_OUTPUT + echo 'EOFABC' >> $GITHUB_OUTPUT + - name: Find coverage comment + uses: peter-evans/find-comment@v1 + continue-on-error: true + id: fc + with: + issue-number: ${{steps.prnum.outputs.num}} + comment-author: "github-actions[bot]" + body-includes: "## Documentation Coverage" + + - name: Delete coverage comment if it exists + if: steps.fc.outputs.comment-id != '' + uses: actions/github-script@v6 + with: + script: | + github.rest.issues.deleteComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: ${{ steps.fc.outputs.comment-id }} + }) - name: Create coverage comment uses: peter-evans/create-or-update-comment@v1 with: - comment-id: ${{ steps.fc.outputs.comment-id }} - issue-number: ${{ github.event.workflow_run.event.pull_request.number }} + issue-number: ${{steps.prnum.outputs.num}} body: | ## Documentation Coverage - **${{steps.coverage.outputs.documented}}** documented (**${{steps.coverage.outputs.diff-documented}}**). - **${{steps.coverage.outputs.examples}}** with examples (**${{steps.coverage.outputs.diff-examples}}**). +
+ This PR + + ``` + ${{steps.doccov.outputs.pr}} + ``` + +
- Documentation Coverage Report - ${{steps.coverage.outputs.table}} + Main + + ``` + ${{steps.doccov.outputs.main}} + ``` +
## Code Coverage - **Summary** + [This PR](https://${{github.repository_owner}}.github.io/conjure-oxide/coverage/${{steps.sha.outputs.result}}) - This PR: ``` - ${{ steps.lcov-pr.outputs.summary }} + ${{steps.lcov.outputs.pr}} ``` - Main: - ``` - ${{ steps.lcov-main.outputs.summary }} + [Main](https://${{github.repository_owner}}.github.io/conjure-oxide/coverage/main) ``` - - **Full Coverage Reports** - - * [This PR](https://conjure-cp.github.io/conjure-oxide/coverage/${{ steps.sha.outputs.result }}). - * [Main](https://conjure-cp.github.io/conjure-oxide/coverage/main). + ${{steps.lcov.outputs.main}} + ``` \ No newline at end of file diff --git a/.github/workflows/code-coverage-main.yml b/.github/workflows/code-coverage-main.yml index 55ec21dd85..4ccea6f574 100644 --- a/.github/workflows/code-coverage-main.yml +++ b/.github/workflows/code-coverage-main.yml @@ -44,22 +44,20 @@ jobs: run: | ./tools/coverage.sh - - name: Print documentation coverage to job summary + - name: Generate documentation coverage run: | - echo '```' >> $GITHUB_STEP_SUMMARY - RUSTDOCFLAGS='-Z unstable-options --show-coverage' cargo +nightly doc --workspace --no-deps | tee -a /dev/fd/2 >> $GITHUB_STEP_SUMMARY - echo '```' >> $GITHUB_STEP_SUMMARY + RUSTDOCFLAGS='-Z unstable-options --show-coverage' cargo +nightly doc --workspace --no-deps > doc-coverage.txt - - name: Generate documentation coverage JSON for diffs in PRs + - name: Generate documentation coverage JSON run: | - RUSTDOCFLAGS='-Z unstable-options --output-format json --show-coverage' cargo +nightly doc --workspace --no-deps > rustdoc-coverage-report.json + RUSTDOCFLAGS='-Z unstable-options --output-format json --show-coverage' cargo +nightly doc --workspace --no-deps > doc-coverage.json - - run: | mkdir -p deploy/ cp -r target/debug/coverage/* deploy/ # html cp target/debug/lcov.info deploy/ # used for diffing code coverage in PR comments - cp rustdoc-coverage-report.json deploy/ # used for diffing doc coverage in PR comments + cp doc-coverage.json deploy/ + cp doc-coverage.txt deploy/ - name: Copy coverage report to /main. uses: JamesIves/github-pages-deploy-action@v4 diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 85c1fed3b1..bd0ab372ea 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -58,10 +58,21 @@ jobs: run: | ./tools/coverage.sh + - name: Generate documentation coverage + run: | + RUSTDOCFLAGS='-Z unstable-options --show-coverage' cargo +nightly doc --workspace --no-deps > doc-coverage.txt + + - name: Generate documentation coverage JSON + run: | + RUSTDOCFLAGS='-Z unstable-options --output-format json --show-coverage' cargo +nightly doc --workspace --no-deps > doc-coverage.json + - run: | mkdir -p deploy/ cp -r target/debug/coverage/* deploy/ # html cp target/debug/lcov.info deploy/ # used for comments + cp doc-coverage.json deploy/ + cp doc-coverage.txt deploy/ + echo "${{github.event.pull_request.number}}" > deploy/prnumber - name: Archive code coverage results for deployment uses: actions/upload-artifact@v3 diff --git a/.github/workflows/docs-generate.yml b/.github/workflows/docs-generate.yml index 73ca348c84..6bba66cd46 100644 --- a/.github/workflows/docs-generate.yml +++ b/.github/workflows/docs-generate.yml @@ -20,14 +20,8 @@ jobs: - name: Get Sha id: sha run: | - if [[ ${{ github.event_name }} == 'pull_request' ]] - then - echo -e "sha=${{ github.event.pull_request.head.sha }}" >> "$GITHUB_OUTPUT" - echo -e "sha=${{ github.event.pull_request.head.sha }}" - else - echo -e "sha=${{ github.sha }}" >> "$GITHUB_OUTPUT" - echo -e "sha=${{ github.sha }}" - fi + echo -e "sha=${{ github.sha }}" >> "$GITHUB_OUTPUT" + echo -e "sha=${{ github.sha }}" - uses: actions/cache@v3 with: @@ -59,5 +53,5 @@ jobs: - name: Archive code coverage results uses: actions/upload-artifact@v3 with: - name: docs-${{ steps.sha.outputs.sha }} + name: docs-${{github.sha}} path: deploy/** diff --git a/Cargo.lock b/Cargo.lock index f84d31701f..870fadc504 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -895,18 +895,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", diff --git a/conjure_oxide/Cargo.toml b/conjure_oxide/Cargo.toml index 2e11dc5af3..e84ae3b198 100644 --- a/conjure_oxide/Cargo.toml +++ b/conjure_oxide/Cargo.toml @@ -15,7 +15,7 @@ conjure_rules = {path = "../crates/conjure_rules" } serde = { version = "1.0.196", features = ["derive"] } serde_json = "1.0.113" serde_with = "3.6.1" -thiserror = "1.0.56" +thiserror = "1.0.57" minion_rs = {path = "../solvers/minion" } anyhow = "1.0.79" clap = { version = "4.5.0", features = ["derive"] } diff --git a/conjure_oxide/src/parse.rs b/conjure_oxide/src/parse.rs index 0fd2463579..f9b0baa346 100644 --- a/conjure_oxide/src/parse.rs +++ b/conjure_oxide/src/parse.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; +use conjure_core::metadata::Metadata; use serde_json::Value; use crate::ast::{Constant, DecisionVariable, Domain, Expression, Model, Name, Range}; @@ -246,14 +247,15 @@ fn parse_vec_op( fn parse_constant(constant: &serde_json::Map) -> Option { match &constant["Constant"] { - Value::Object(int) if int.contains_key("ConstantInt") => { - Some(Expression::Constant(Constant::Int( + Value::Object(int) if int.contains_key("ConstantInt") => Some(Expression::Constant( + Metadata::new(), + Constant::Int( int["ConstantInt"].as_array()?[1] .as_i64()? .try_into() .unwrap(), - ))) - } + ), + )), otherwise => panic!("Unhandled parse_constant {:#?}", otherwise), } } diff --git a/conjure_oxide/src/rules/base.rs b/conjure_oxide/src/rules/base.rs index d454c3711d..feeec2e8cc 100644 --- a/conjure_oxide/src/rules/base.rs +++ b/conjure_oxide/src/rules/base.rs @@ -1,4 +1,6 @@ -use conjure_core::{ast::Constant as Const, ast::Expression as Expr, rule::RuleApplicationError}; +use conjure_core::{ + ast::Constant as Const, ast::Expression as Expr, metadata::Metadata, rule::RuleApplicationError, +}; use conjure_rules::register_rule; /*****************************************************************************/ @@ -102,7 +104,7 @@ fn sum_constants(expr: &Expr) -> Result { let mut changed = false; for e in exprs { match e { - Expr::Constant(Const::Int(i)) => { + Expr::Constant(metadata, Const::Int(i)) => { sum += i; changed = true; } @@ -112,7 +114,8 @@ fn sum_constants(expr: &Expr) -> Result { if !changed { return Err(RuleApplicationError::RuleNotApplicable); } - new_exprs.push(Expr::Constant(Const::Int(sum))); + // TODO (kf77): Get existing metadata instead of creating a new one + new_exprs.push(Expr::Constant(Metadata::new(), Const::Int(sum))); Ok(Expr::Sum(new_exprs)) // Let other rules handle only one Expr being contained in the sum } _ => Err(RuleApplicationError::RuleNotApplicable), @@ -302,10 +305,10 @@ fn remove_constants_from_or(expr: &Expr) -> Result { let mut changed = false; for e in exprs { match e { - Expr::Constant(Const::Bool(val)) => { + Expr::Constant(metadata, Const::Bool(val)) => { if *val { // If we find a true, the whole expression is true - return Ok(Expr::Constant(Const::Bool(true))); + return Ok(Expr::Constant(metadata.clone(), Const::Bool(true))); } else { // If we find a false, we can ignore it changed = true; @@ -338,10 +341,10 @@ fn remove_constants_from_and(expr: &Expr) -> Result let mut changed = false; for e in exprs { match e { - Expr::Constant(Const::Bool(val)) => { + Expr::Constant(metadata, Const::Bool(val)) => { if !*val { // If we find a false, the whole expression is false - return Ok(Expr::Constant(Const::Bool(false))); + return Ok(Expr::Constant(metadata.clone(), Const::Bool(false))); } else { // If we find a true, we can ignore it changed = true; @@ -370,7 +373,9 @@ fn remove_constants_from_and(expr: &Expr) -> Result fn evaluate_constant_not(expr: &Expr) -> Result { match expr { Expr::Not(contents) => match contents.as_ref() { - Expr::Constant(Const::Bool(val)) => Ok(Expr::Constant(Const::Bool(!val))), + Expr::Constant(metadata, Const::Bool(val)) => { + Ok(Expr::Constant(metadata.clone(), Const::Bool(!val))) + } _ => Err(RuleApplicationError::RuleNotApplicable), }, _ => Err(RuleApplicationError::RuleNotApplicable), diff --git a/conjure_oxide/src/rules/constant.rs b/conjure_oxide/src/rules/constant.rs index d46347bf3f..47f5ccb5db 100644 --- a/conjure_oxide/src/rules/constant.rs +++ b/conjure_oxide/src/rules/constant.rs @@ -1,4 +1,6 @@ -use conjure_core::{ast::Constant as Const, ast::Expression as Expr, rule::RuleApplicationError}; +use conjure_core::{ + ast::Constant as Const, ast::Expression as Expr, metadata::Metadata, rule::RuleApplicationError, +}; use conjure_rules::register_rule; #[register_rule] @@ -7,7 +9,7 @@ fn apply_eval_constant(expr: &Expr) -> Result { return Err(RuleApplicationError::RuleNotApplicable); } let res = eval_constant(expr) - .map(Expr::Constant) + .map(|c| Expr::Constant(Metadata::new(), c)) .ok_or(RuleApplicationError::RuleNotApplicable); res } @@ -18,7 +20,7 @@ fn apply_eval_constant(expr: &Expr) -> Result { /// `Some(Const)` if the expression can be simplified to a constant pub fn eval_constant(expr: &Expr) -> Option { match expr { - Expr::Constant(c) => Some(c.clone()), + Expr::Constant(m, c) => Some(c.clone()), Expr::Reference(_) => None, Expr::Eq(a, b) => bin_op::(|a, b| a == b, a, b) diff --git a/conjure_oxide/src/rules/minion.rs b/conjure_oxide/src/rules/minion.rs index 3cda28877c..4357eb9c3b 100644 --- a/conjure_oxide/src/rules/minion.rs +++ b/conjure_oxide/src/rules/minion.rs @@ -1,4 +1,6 @@ -use conjure_core::{ast::Constant as Const, ast::Expression as Expr, rule::RuleApplicationError}; +use conjure_core::{ + ast::Constant as Const, ast::Expression as Expr, metadata::Metadata, rule::RuleApplicationError, +}; use conjure_rules::register_rule; /************************************************************************/ @@ -120,7 +122,7 @@ fn lt_to_ineq(expr: &Expr) -> Result { Expr::Lt(a, b) => Ok(Expr::Ineq( a.clone(), b.clone(), - Box::new(Expr::Constant(Const::Int(-1))), + Box::new(Expr::Constant(Metadata::new(), Const::Int(-1))), )), _ => Err(RuleApplicationError::RuleNotApplicable), } @@ -139,7 +141,7 @@ fn gt_to_ineq(expr: &Expr) -> Result { Expr::Gt(a, b) => Ok(Expr::Ineq( b.clone(), a.clone(), - Box::new(Expr::Constant(Const::Int(-1))), + Box::new(Expr::Constant(Metadata::new(), Const::Int(-1))), )), _ => Err(RuleApplicationError::RuleNotApplicable), } @@ -158,7 +160,7 @@ fn geq_to_ineq(expr: &Expr) -> Result { Expr::Geq(a, b) => Ok(Expr::Ineq( b.clone(), a.clone(), - Box::new(Expr::Constant(Const::Int(0))), + Box::new(Expr::Constant(Metadata::new(), Const::Int(0))), )), _ => Err(RuleApplicationError::RuleNotApplicable), } @@ -177,7 +179,7 @@ fn leq_to_ineq(expr: &Expr) -> Result { Expr::Leq(a, b) => Ok(Expr::Ineq( a.clone(), b.clone(), - Box::new(Expr::Constant(Const::Int(0))), + Box::new(Expr::Constant(Metadata::new(), Const::Int(0))), )), _ => Err(RuleApplicationError::RuleNotApplicable), } diff --git a/conjure_oxide/src/solvers/minion.rs b/conjure_oxide/src/solvers/minion.rs index 88d38b11a2..965eb1e743 100644 --- a/conjure_oxide/src/solvers/minion.rs +++ b/conjure_oxide/src/solvers/minion.rs @@ -8,6 +8,7 @@ use crate::ast::{ Expression as ConjureExpression, Model as ConjureModel, Name as ConjureName, Range as ConjureRange, }; +use conjure_core::metadata::Metadata; pub use minion_rs::ast::Model as MinionModel; use minion_rs::ast::{ Constant as MinionConstant, Constraint as MinionConstraint, Var as MinionVar, @@ -199,7 +200,7 @@ fn must_be_ref(e: ConjureExpression) -> Result { fn must_be_const(e: ConjureExpression) -> Result { match e { - ConjureExpression::Constant(ConjureConstant::Int(n)) => Ok(n), + ConjureExpression::Constant(_, ConjureConstant::Int(n)) => Ok(n), x => Err(SolverError::InvalidInstance( SOLVER, format!("expected a constant, but got `{0:?}`", x), @@ -239,7 +240,7 @@ mod tests { let x = ConjureExpression::Reference(ConjureName::UserName("x".to_owned())); let y = ConjureExpression::Reference(ConjureName::UserName("y".to_owned())); let z = ConjureExpression::Reference(ConjureName::UserName("z".to_owned())); - let four = ConjureExpression::Constant(ConjureConstant::Int(4)); + let four = ConjureExpression::Constant(Metadata::new(), ConjureConstant::Int(4)); let geq = ConjureExpression::SumGeq( vec![x.to_owned(), y.to_owned(), z.to_owned()], diff --git a/conjure_oxide/tests/generated_tests.rs b/conjure_oxide/tests/generated_tests.rs index 6c7dd6f015..b954dc18f2 100644 --- a/conjure_oxide/tests/generated_tests.rs +++ b/conjure_oxide/tests/generated_tests.rs @@ -1,6 +1,9 @@ use conjure_oxide::ast::Model; use conjure_oxide::parse::model_from_json; +use conjure_oxide::solvers::minion::MinionModel; +use conjure_oxide::solvers::FromConjureModel; use serde_json::Value; +use std::collections::HashMap; use std::env; use std::error::Error; use std::fs::File; @@ -24,6 +27,7 @@ pub fn integration_test(path: &str, essence_base: &str) -> Result<(), Box Result<(), Box Result<(), Box) -> bool { + true +} + /// Recursively sorts the keys of all JSON objects within the provided JSON value. /// /// serde_json will output JSON objects in an arbitrary key order. diff --git a/conjure_oxide/tests/integration/basic/bool/01/bool-01.essence b/conjure_oxide/tests/integration/basic/bool/01/bool-01.essence.disabled similarity index 100% rename from conjure_oxide/tests/integration/basic/bool/01/bool-01.essence rename to conjure_oxide/tests/integration/basic/bool/01/bool-01.essence.disabled diff --git a/conjure_oxide/tests/integration/basic/bool/02/bool-02.essence b/conjure_oxide/tests/integration/basic/bool/02/bool-02.essence.disabled similarity index 100% rename from conjure_oxide/tests/integration/basic/bool/02/bool-02.essence rename to conjure_oxide/tests/integration/basic/bool/02/bool-02.essence.disabled diff --git a/conjure_oxide/tests/integration/basic/bool/03/bool-03.essence b/conjure_oxide/tests/integration/basic/bool/03/bool-03.essence.disabled similarity index 100% rename from conjure_oxide/tests/integration/basic/bool/03/bool-03.essence rename to conjure_oxide/tests/integration/basic/bool/03/bool-03.essence.disabled diff --git a/conjure_oxide/tests/integration/minion-lowlevel/README b/conjure_oxide/tests/integration/minion-lowlevel/README new file mode 100644 index 0000000000..6c89f5b3d0 --- /dev/null +++ b/conjure_oxide/tests/integration/minion-lowlevel/README @@ -0,0 +1,2 @@ +These models have already been (mostly) simplified by Savile Row. +Useful primarily to test the Minion bindings. diff --git a/conjure_oxide/tests/integration/xyz/input.expected-parse.serialised.json b/conjure_oxide/tests/integration/xyz/input.expected-parse.serialised.json index 74c2572538..6608cb60b2 100644 --- a/conjure_oxide/tests/integration/xyz/input.expected-parse.serialised.json +++ b/conjure_oxide/tests/integration/xyz/input.expected-parse.serialised.json @@ -27,9 +27,14 @@ ] }, { - "Constant": { - "Int": 4 - } + "Constant": [ + { + "dirtyclean": false + }, + { + "Int": 4 + } + ] } ] }, diff --git a/conjure_oxide/tests/integration/xyz/input.expected-rewrite.serialised.json b/conjure_oxide/tests/integration/xyz/input.expected-rewrite.serialised.json index 70aefa0e08..2847eb4e8a 100644 --- a/conjure_oxide/tests/integration/xyz/input.expected-rewrite.serialised.json +++ b/conjure_oxide/tests/integration/xyz/input.expected-rewrite.serialised.json @@ -21,9 +21,14 @@ } ], { - "Constant": { - "Int": 4 - } + "Constant": [ + { + "dirtyclean": false + }, + { + "Int": 4 + } + ] } ] }, @@ -47,9 +52,14 @@ } ], { - "Constant": { - "Int": 4 - } + "Constant": [ + { + "dirtyclean": false + }, + { + "Int": 4 + } + ] } ] }, @@ -66,9 +76,14 @@ } }, { - "Constant": { - "Int": 0 - } + "Constant": [ + { + "dirtyclean": false + }, + { + "Int": 0 + } + ] } ] } diff --git a/conjure_oxide/tests/rewrite_tests.rs b/conjure_oxide/tests/rewrite_tests.rs index df5ae91031..397f5ae662 100644 --- a/conjure_oxide/tests/rewrite_tests.rs +++ b/conjure_oxide/tests/rewrite_tests.rs @@ -1,6 +1,6 @@ // Tests for rewriting/simplifying parts of the AST -use conjure_core::rule::Rule; +use conjure_core::{metadata::Metadata, rule::Rule}; use conjure_rules::{get_rule_by_name, get_rules}; use core::panic; use std::collections::HashMap; @@ -17,13 +17,13 @@ fn rules_present() { #[test] fn sum_of_constants() { let valid_sum_expression = Expression::Sum(vec![ - Expression::Constant(Constant::Int(1)), - Expression::Constant(Constant::Int(2)), - Expression::Constant(Constant::Int(3)), + Expression::Constant(Metadata::new(), Constant::Int(1)), + Expression::Constant(Metadata::new(), Constant::Int(2)), + Expression::Constant(Metadata::new(), Constant::Int(3)), ]); let invalid_sum_expression = Expression::Sum(vec![ - Expression::Constant(Constant::Int(1)), + Expression::Constant(Metadata::new(), Constant::Int(1)), Expression::Reference(Name::UserName(String::from("a"))), ]); @@ -43,7 +43,7 @@ fn evaluate_sum_of_constants(expr: &Expression) -> Option { let mut sum = 0; for e in expressions { match e { - Expression::Constant(Constant::Int(value)) => { + Expression::Constant(_, Constant::Int(value)) => { sum += value; } _ => return None, @@ -59,24 +59,24 @@ fn evaluate_sum_of_constants(expr: &Expression) -> Option { fn recursive_sum_of_constants() { let complex_expression = Expression::Eq( Box::new(Expression::Sum(vec![ - Expression::Constant(Constant::Int(1)), - Expression::Constant(Constant::Int(2)), + Expression::Constant(Metadata::new(), Constant::Int(1)), + Expression::Constant(Metadata::new(), Constant::Int(2)), Expression::Sum(vec![ - Expression::Constant(Constant::Int(1)), - Expression::Constant(Constant::Int(2)), + Expression::Constant(Metadata::new(), Constant::Int(1)), + Expression::Constant(Metadata::new(), Constant::Int(2)), ]), Expression::Reference(Name::UserName(String::from("a"))), ])), - Box::new(Expression::Constant(Constant::Int(3))), + Box::new(Expression::Constant(Metadata::new(), Constant::Int(3))), ); let correct_simplified_expression = Expression::Eq( Box::new(Expression::Sum(vec![ - Expression::Constant(Constant::Int(1)), - Expression::Constant(Constant::Int(2)), - Expression::Constant(Constant::Int(3)), + Expression::Constant(Metadata::new(), Constant::Int(1)), + Expression::Constant(Metadata::new(), Constant::Int(2)), + Expression::Constant(Metadata::new(), Constant::Int(3)), Expression::Reference(Name::UserName(String::from("a"))), ])), - Box::new(Expression::Constant(Constant::Int(3))), + Box::new(Expression::Constant(Metadata::new(), Constant::Int(3))), ); let simplified_expression = simplify_expression(complex_expression.clone()); @@ -87,7 +87,7 @@ fn simplify_expression(expr: Expression) -> Expression { match expr { Expression::Sum(expressions) => { if let Some(result) = evaluate_sum_of_constants(&Expression::Sum(expressions.clone())) { - Expression::Constant(Constant::Int(result)) + Expression::Constant(Metadata::new(), Constant::Int(result)) } else { Expression::Sum(expressions.into_iter().map(simplify_expression).collect()) } @@ -110,15 +110,18 @@ fn rule_sum_constants() { let unwrap_sum = get_rule_by_name("unwrap_sum").unwrap(); let mut expr = Expression::Sum(vec![ - Expression::Constant(Constant::Int(1)), - Expression::Constant(Constant::Int(2)), - Expression::Constant(Constant::Int(3)), + Expression::Constant(Metadata::new(), Constant::Int(1)), + Expression::Constant(Metadata::new(), Constant::Int(2)), + Expression::Constant(Metadata::new(), Constant::Int(3)), ]); expr = sum_constants.apply(&expr).unwrap(); expr = unwrap_sum.apply(&expr).unwrap(); - assert_eq!(expr, Expression::Constant(Constant::Int(6))); + assert_eq!( + expr, + Expression::Constant(Metadata::new(), Constant::Int(6)) + ); } #[test] @@ -126,8 +129,8 @@ fn rule_sum_mixed() { let sum_constants = get_rule_by_name("sum_constants").unwrap(); let mut expr = Expression::Sum(vec![ - Expression::Constant(Constant::Int(1)), - Expression::Constant(Constant::Int(2)), + Expression::Constant(Metadata::new(), Constant::Int(1)), + Expression::Constant(Metadata::new(), Constant::Int(2)), Expression::Reference(Name::UserName(String::from("a"))), ]); @@ -137,7 +140,7 @@ fn rule_sum_mixed() { expr, Expression::Sum(vec![ Expression::Reference(Name::UserName(String::from("a"))), - Expression::Constant(Constant::Int(3)), + Expression::Constant(Metadata::new(), Constant::Int(3)), ]) ); } @@ -148,10 +151,10 @@ fn rule_sum_geq() { let mut expr = Expression::Geq( Box::new(Expression::Sum(vec![ - Expression::Constant(Constant::Int(1)), - Expression::Constant(Constant::Int(2)), + Expression::Constant(Metadata::new(), Constant::Int(1)), + Expression::Constant(Metadata::new(), Constant::Int(2)), ])), - Box::new(Expression::Constant(Constant::Int(3))), + Box::new(Expression::Constant(Metadata::new(), Constant::Int(3))), ); expr = flatten_sum_geq.apply(&expr).unwrap(); @@ -160,10 +163,10 @@ fn rule_sum_geq() { expr, Expression::SumGeq( vec![ - Expression::Constant(Constant::Int(1)), - Expression::Constant(Constant::Int(2)), + Expression::Constant(Metadata::new(), Constant::Int(1)), + Expression::Constant(Metadata::new(), Constant::Int(2)), ], - Box::new(Expression::Constant(Constant::Int(3))) + Box::new(Expression::Constant(Metadata::new(), Constant::Int(3))) ) ); } @@ -190,14 +193,17 @@ fn reduce_solve_xyz() { // 2 + 3 - 1 let mut expr1 = Expression::Sum(vec![ - Expression::Constant(Constant::Int(2)), - Expression::Constant(Constant::Int(3)), - Expression::Constant(Constant::Int(-1)), + Expression::Constant(Metadata::new(), Constant::Int(2)), + Expression::Constant(Metadata::new(), Constant::Int(3)), + Expression::Constant(Metadata::new(), Constant::Int(-1)), ]); expr1 = sum_constants.apply(&expr1).unwrap(); expr1 = unwrap_sum.apply(&expr1).unwrap(); - assert_eq!(expr1, Expression::Constant(Constant::Int(4))); + assert_eq!( + expr1, + Expression::Constant(Metadata::new(), Constant::Int(4)) + ); // a + b + c = 4 expr1 = Expression::Leq( @@ -217,7 +223,7 @@ fn reduce_solve_xyz() { Expression::Reference(Name::UserName(String::from("b"))), Expression::Reference(Name::UserName(String::from("c"))), ], - Box::new(Expression::Constant(Constant::Int(4))) + Box::new(Expression::Constant(Metadata::new(), Constant::Int(4))) ) ); @@ -232,7 +238,7 @@ fn reduce_solve_xyz() { Expression::Ineq( Box::new(Expression::Reference(Name::UserName(String::from("a")))), Box::new(Expression::Reference(Name::UserName(String::from("b")))), - Box::new(Expression::Constant(Constant::Int(-1))) + Box::new(Expression::Constant(Metadata::new(), Constant::Int(-1))) ) ); @@ -269,12 +275,16 @@ fn rule_remove_double_negation() { let remove_double_negation = get_rule_by_name("remove_double_negation").unwrap(); let mut expr = Expression::Not(Box::new(Expression::Not(Box::new(Expression::Constant( + Metadata::new(), Constant::Bool(true), ))))); expr = remove_double_negation.apply(&expr).unwrap(); - assert_eq!(expr, Expression::Constant(Constant::Bool(true))); + assert_eq!( + expr, + Expression::Constant(Metadata::new(), Constant::Bool(true)) + ); } #[test] @@ -283,10 +293,10 @@ fn rule_unwrap_nested_or() { let mut expr = Expression::Or(vec![ Expression::Or(vec![ - Expression::Constant(Constant::Bool(true)), - Expression::Constant(Constant::Bool(false)), + Expression::Constant(Metadata::new(), Constant::Bool(true)), + Expression::Constant(Metadata::new(), Constant::Bool(false)), ]), - Expression::Constant(Constant::Bool(true)), + Expression::Constant(Metadata::new(), Constant::Bool(true)), ]); expr = unwrap_nested_or.apply(&expr).unwrap(); @@ -294,9 +304,9 @@ fn rule_unwrap_nested_or() { assert_eq!( expr, Expression::Or(vec![ - Expression::Constant(Constant::Bool(true)), - Expression::Constant(Constant::Bool(false)), - Expression::Constant(Constant::Bool(true)), + Expression::Constant(Metadata::new(), Constant::Bool(true)), + Expression::Constant(Metadata::new(), Constant::Bool(false)), + Expression::Constant(Metadata::new(), Constant::Bool(true)), ]) ); } @@ -307,10 +317,10 @@ fn rule_unwrap_nested_and() { let mut expr = Expression::And(vec![ Expression::And(vec![ - Expression::Constant(Constant::Bool(true)), - Expression::Constant(Constant::Bool(false)), + Expression::Constant(Metadata::new(), Constant::Bool(true)), + Expression::Constant(Metadata::new(), Constant::Bool(false)), ]), - Expression::Constant(Constant::Bool(true)), + Expression::Constant(Metadata::new(), Constant::Bool(true)), ]); expr = unwrap_nested_and.apply(&expr).unwrap(); @@ -318,9 +328,9 @@ fn rule_unwrap_nested_and() { assert_eq!( expr, Expression::And(vec![ - Expression::Constant(Constant::Bool(true)), - Expression::Constant(Constant::Bool(false)), - Expression::Constant(Constant::Bool(true)), + Expression::Constant(Metadata::new(), Constant::Bool(true)), + Expression::Constant(Metadata::new(), Constant::Bool(false)), + Expression::Constant(Metadata::new(), Constant::Bool(true)), ]) ); } @@ -330,8 +340,8 @@ fn unwrap_nested_or_not_changed() { let unwrap_nested_or = get_rule_by_name("unwrap_nested_or").unwrap(); let expr = Expression::Or(vec![ - Expression::Constant(Constant::Bool(true)), - Expression::Constant(Constant::Bool(false)), + Expression::Constant(Metadata::new(), Constant::Bool(true)), + Expression::Constant(Metadata::new(), Constant::Bool(false)), ]); let result = unwrap_nested_or.apply(&expr); @@ -344,8 +354,8 @@ fn unwrap_nested_and_not_changed() { let unwrap_nested_and = get_rule_by_name("unwrap_nested_and").unwrap(); let expr = Expression::And(vec![ - Expression::Constant(Constant::Bool(true)), - Expression::Constant(Constant::Bool(false)), + Expression::Constant(Metadata::new(), Constant::Bool(true)), + Expression::Constant(Metadata::new(), Constant::Bool(false)), ]); let result = unwrap_nested_and.apply(&expr); @@ -358,14 +368,26 @@ fn remove_trivial_and_or() { let remove_trivial_and = get_rule_by_name("remove_trivial_and").unwrap(); let remove_trivial_or = get_rule_by_name("remove_trivial_or").unwrap(); - let mut expr_and = Expression::And(vec![Expression::Constant(Constant::Bool(true))]); - let mut expr_or = Expression::Or(vec![Expression::Constant(Constant::Bool(false))]); + let mut expr_and = Expression::And(vec![Expression::Constant( + Metadata::new(), + Constant::Bool(true), + )]); + let mut expr_or = Expression::Or(vec![Expression::Constant( + Metadata::new(), + Constant::Bool(false), + )]); expr_and = remove_trivial_and.apply(&expr_and).unwrap(); expr_or = remove_trivial_or.apply(&expr_or).unwrap(); - assert_eq!(expr_and, Expression::Constant(Constant::Bool(true))); - assert_eq!(expr_or, Expression::Constant(Constant::Bool(false))); + assert_eq!( + expr_and, + Expression::Constant(Metadata::new(), Constant::Bool(true)) + ); + assert_eq!( + expr_or, + Expression::Constant(Metadata::new(), Constant::Bool(false)) + ); } #[test] @@ -373,14 +395,17 @@ fn rule_remove_constants_from_or() { let remove_constants_from_or = get_rule_by_name("remove_constants_from_or").unwrap(); let mut expr = Expression::Or(vec![ - Expression::Constant(Constant::Bool(true)), - Expression::Constant(Constant::Bool(false)), + Expression::Constant(Metadata::new(), Constant::Bool(true)), + Expression::Constant(Metadata::new(), Constant::Bool(false)), Expression::Reference(Name::UserName(String::from("a"))), ]); expr = remove_constants_from_or.apply(&expr).unwrap(); - assert_eq!(expr, Expression::Constant(Constant::Bool(true))); + assert_eq!( + expr, + Expression::Constant(Metadata::new(), Constant::Bool(true)) + ); } #[test] @@ -388,14 +413,17 @@ fn rule_remove_constants_from_and() { let remove_constants_from_and = get_rule_by_name("remove_constants_from_and").unwrap(); let mut expr = Expression::And(vec![ - Expression::Constant(Constant::Bool(true)), - Expression::Constant(Constant::Bool(false)), + Expression::Constant(Metadata::new(), Constant::Bool(true)), + Expression::Constant(Metadata::new(), Constant::Bool(false)), Expression::Reference(Name::UserName(String::from("a"))), ]); expr = remove_constants_from_and.apply(&expr).unwrap(); - assert_eq!(expr, Expression::Constant(Constant::Bool(false))); + assert_eq!( + expr, + Expression::Constant(Metadata::new(), Constant::Bool(false)) + ); } #[test] @@ -557,7 +585,7 @@ fn rewrite_solve_xyz() { Expression::Reference(variable_b.clone()), Expression::Reference(variable_c.clone()), ])), - Box::new(Expression::Constant(Constant::Int(4))), + Box::new(Expression::Constant(Metadata::new(), Constant::Int(4))), ), Expression::Lt( Box::new(Expression::Reference(variable_a.clone())), @@ -684,14 +712,14 @@ fn choose_rewrite(results: &Vec) -> Option { #[test] fn eval_const_int() { - let expr = Expression::Constant(Constant::Int(1)); + let expr = Expression::Constant(Metadata::new(), Constant::Int(1)); let result = eval_constant(&expr); assert_eq!(result, Some(Constant::Int(1))); } #[test] fn eval_const_bool() { - let expr = Expression::Constant(Constant::Bool(true)); + let expr = Expression::Constant(Metadata::new(), Constant::Bool(true)); let result = eval_constant(&expr); assert_eq!(result, Some(Constant::Bool(true))); } @@ -699,8 +727,8 @@ fn eval_const_bool() { #[test] fn eval_const_and() { let expr = Expression::And(vec![ - Expression::Constant(Constant::Bool(true)), - Expression::Constant(Constant::Bool(false)), + Expression::Constant(Metadata::new(), Constant::Bool(true)), + Expression::Constant(Metadata::new(), Constant::Bool(false)), ]); let result = eval_constant(&expr); assert_eq!(result, Some(Constant::Bool(false))); @@ -716,9 +744,9 @@ fn eval_const_ref() { #[test] fn eval_const_nested_ref() { let expr = Expression::Sum(vec![ - Expression::Constant(Constant::Int(1)), + Expression::Constant(Metadata::new(), Constant::Int(1)), Expression::And(vec![ - Expression::Constant(Constant::Bool(true)), + Expression::Constant(Metadata::new(), Constant::Bool(true)), Expression::Reference(Name::UserName(String::from("a"))), ]), ]); @@ -729,8 +757,8 @@ fn eval_const_nested_ref() { #[test] fn eval_const_eq_int() { let expr = Expression::Eq( - Box::new(Expression::Constant(Constant::Int(1))), - Box::new(Expression::Constant(Constant::Int(1))), + Box::new(Expression::Constant(Metadata::new(), Constant::Int(1))), + Box::new(Expression::Constant(Metadata::new(), Constant::Int(1))), ); let result = eval_constant(&expr); assert_eq!(result, Some(Constant::Bool(true))); @@ -739,8 +767,8 @@ fn eval_const_eq_int() { #[test] fn eval_const_eq_bool() { let expr = Expression::Eq( - Box::new(Expression::Constant(Constant::Bool(true))), - Box::new(Expression::Constant(Constant::Bool(true))), + Box::new(Expression::Constant(Metadata::new(), Constant::Bool(true))), + Box::new(Expression::Constant(Metadata::new(), Constant::Bool(true))), ); let result = eval_constant(&expr); assert_eq!(result, Some(Constant::Bool(true))); @@ -749,8 +777,8 @@ fn eval_const_eq_bool() { #[test] fn eval_const_eq_mixed() { let expr = Expression::Eq( - Box::new(Expression::Constant(Constant::Int(1))), - Box::new(Expression::Constant(Constant::Bool(true))), + Box::new(Expression::Constant(Metadata::new(), Constant::Int(1))), + Box::new(Expression::Constant(Metadata::new(), Constant::Bool(true))), ); let result = eval_constant(&expr); assert_eq!(result, None); @@ -759,8 +787,8 @@ fn eval_const_eq_mixed() { #[test] fn eval_const_sum_mixed() { let expr = Expression::Sum(vec![ - Expression::Constant(Constant::Int(1)), - Expression::Constant(Constant::Bool(true)), + Expression::Constant(Metadata::new(), Constant::Int(1)), + Expression::Constant(Metadata::new(), Constant::Bool(true)), ]); let result = eval_constant(&expr); assert_eq!(result, None); @@ -775,7 +803,7 @@ fn eval_const_sum_xyz() { Expression::Reference(Name::UserName(String::from("y"))), Expression::Reference(Name::UserName(String::from("z"))), ])), - Box::new(Expression::Constant(Constant::Int(4))), + Box::new(Expression::Constant(Metadata::new(), Constant::Int(4))), ), Expression::Geq( Box::new(Expression::Reference(Name::UserName(String::from("x")))), @@ -789,8 +817,8 @@ fn eval_const_sum_xyz() { #[test] fn eval_const_or() { let expr = Expression::Or(vec![ - Expression::Constant(Constant::Bool(false)), - Expression::Constant(Constant::Bool(false)), + Expression::Constant(Metadata::new(), Constant::Bool(false)), + Expression::Constant(Metadata::new(), Constant::Bool(false)), ]); let result = eval_constant(&expr); assert_eq!(result, Some(Constant::Bool(false))); diff --git a/crates/conjure_core/Cargo.toml b/crates/conjure_core/Cargo.toml index 735cc7e2dd..323891840f 100644 --- a/crates/conjure_core/Cargo.toml +++ b/crates/conjure_core/Cargo.toml @@ -9,7 +9,7 @@ serde_json = "1.0.113" serde_with = "3.6.1" strum = "0.26.1" strum_macros = "0.26.1" -thiserror = "1.0.50" +thiserror = "1.0.57" doc_solver_support = {path= "../doc_solver_support"} [lints] diff --git a/crates/conjure_core/src/ast.rs b/crates/conjure_core/src/ast.rs index 4bf8451296..7884465b56 100644 --- a/crates/conjure_core/src/ast.rs +++ b/crates/conjure_core/src/ast.rs @@ -4,6 +4,8 @@ use serde_with::serde_as; use std::collections::HashMap; use std::fmt::{Debug, Display, Formatter}; +use crate::metadata::Metadata; + #[serde_as] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Model { @@ -162,7 +164,7 @@ pub enum Expression { Nothing, #[solver(Minion, SAT)] - Constant(Constant), + Constant(Metadata, Constant), #[solver(Minion)] Reference(Name), @@ -220,7 +222,7 @@ impl Expression { } match self { - Expression::Constant(_) => None, + Expression::Constant(_, _) => None, Expression::Reference(_) => None, Expression::Nothing => None, Expression::Sum(exprs) => Some(exprs.iter().collect()), @@ -243,7 +245,7 @@ impl Expression { /// Returns a clone of the same expression type with the given sub-expressions. pub fn with_sub_expressions(&self, sub: Vec<&Expression>) -> Expression { match self { - Expression::Constant(c) => Expression::Constant(c.clone()), + Expression::Constant(m, c) => Expression::Constant(m.clone(), c.clone()), Expression::Reference(name) => Expression::Reference(name.clone()), Expression::Nothing => Expression::Nothing, Expression::Sum(_) => Expression::Sum(sub.iter().cloned().cloned().collect()), @@ -290,7 +292,7 @@ impl Expression { pub fn is_constant(&self) -> bool { match self { - Expression::Constant(_) => true, + Expression::Constant(_, _) => true, _ => false, } } @@ -327,7 +329,7 @@ impl Display for Constant { impl Display for Expression { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match &self { - Expression::Constant(c) => write!(f, "Constant::{}", c), + Expression::Constant(m, c) => write!(f, "Constant({}, {})", m, c), Expression::Reference(name) => write!(f, "Reference({})", name), Expression::Nothing => write!(f, "Nothing"), Expression::Sum(expressions) => write!(f, "Sum({})", display_expressions(expressions)), diff --git a/crates/conjure_core/src/lib.rs b/crates/conjure_core/src/lib.rs index df41804d3b..4753a103a8 100644 --- a/crates/conjure_core/src/lib.rs +++ b/crates/conjure_core/src/lib.rs @@ -1,5 +1,5 @@ pub mod ast; +pub mod metadata; pub mod rule; - pub mod solvers; pub use solvers::Solver; diff --git a/crates/conjure_core/src/metadata.rs b/crates/conjure_core/src/metadata.rs new file mode 100644 index 0000000000..ca964cbb42 --- /dev/null +++ b/crates/conjure_core/src/metadata.rs @@ -0,0 +1,32 @@ +use serde::{Deserialize, Serialize}; +use std::fmt::{Debug, Display}; + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct Metadata { + pub dirtyclean: bool, +} + +impl Metadata { + pub fn new() -> Metadata { + Metadata { dirtyclean: false } + } +} + +impl Display for Metadata { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Metadata") + } +} + +// impl Display for Metadata where T: for<'a> MetadataKind<'a> { +// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +// write!(f, "Metadata") +// } +// } + +// +// impl Metadata where T: for<'a> MetadataKind<'a> { +// fn new(a: T) -> Metadata { +// Metadata { a } +// } +// } diff --git a/solvers/minion/Cargo.toml b/solvers/minion/Cargo.toml index 9aa022555f..fb7b019b99 100644 --- a/solvers/minion/Cargo.toml +++ b/solvers/minion/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] anyhow = "1.0.79" -thiserror = "1.0.56" +thiserror = "1.0.57" [build-dependencies] bindgen = "0.69.4" diff --git a/tools/coverage.sh b/tools/coverage.sh index 823cbb8f01..e6928d2930 100755 --- a/tools/coverage.sh +++ b/tools/coverage.sh @@ -74,6 +74,6 @@ echo_err "info: running tests" cargo +nightly test --workspace echo_err "info: generating coverage reports" -grcov . -s . --binary-path ./target/debug -t html --branch --ignore-not-existing --ignore 'target/**/*.rs' --ignore '**/main.rs' --ignore '**/build.rs' -o ./target/debug/coverage -grcov . -s . --binary-path ./target/debug -t lcov --branch --ignore-not-existing --ignore 'target/**/*.rs' --ignore '**/main.rs' --ignore '**/build.rs' -o ./target/debug/lcov.info +grcov . -s . --binary-path ./target/debug -t html --ignore-not-existing --ignore "$HOME"'/.cargo/**/*.rs' --ignore 'target/**/*.rs' --ignore '**/main.rs' --ignore '**/build.rs' -o ./target/debug/coverage +grcov . -s . --binary-path ./target/debug -t lcov --ignore-not-existing --ignore "$HOME"'/.cargo/**/*.rs' --ignore 'target/**/*.rs' --ignore '.cargo/**/*.rs' --ignore '**/main.rs' --ignore '**/build.rs' -o ./target/debug/lcov.info rm -rf **/*.profraw *.profraw