From 0b27bcb08b76fb0baa2229b973b28f6422f46be4 Mon Sep 17 00:00:00 2001 From: Hugo Caillard <911307+hugocaillard@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:54:33 +0200 Subject: [PATCH] feat: add coverage hook on execute and runSnippet in simnet --- components/clarinet-sdk-wasm/src/core.rs | 87 +++++++++++++------ .../clarinet-sdk/node/tests/reports.test.ts | 28 ++++++ 2 files changed, 89 insertions(+), 26 deletions(-) diff --git a/components/clarinet-sdk-wasm/src/core.rs b/components/clarinet-sdk-wasm/src/core.rs index 137d53c19..46b8d417c 100644 --- a/components/clarinet-sdk-wasm/src/core.rs +++ b/components/clarinet-sdk-wasm/src/core.rs @@ -859,6 +859,13 @@ impl SDK { args: &DeployContractArgs, advance_chain_tip: bool, ) -> Result { + let mut hooks: Vec<&mut dyn EvalHook> = Vec::new(); + + let mut coverage_hook = self.coverage_hook.take(); + if let Some(ref mut hook) = coverage_hook { + hooks.push(hook); + } + let execution = { let session = self.get_session_mut(); if advance_chain_tip { @@ -888,6 +895,8 @@ impl SDK { } }; + self.coverage_hook = coverage_hook; + if let EvaluationResult::Contract(ref result) = &execution.result { let contract_id = result.contract.analysis.contract_identifier.clone(); if let Some(contract_interface) = &result.contract.analysis.contract_interface { @@ -989,38 +998,64 @@ impl SDK { #[wasm_bindgen(js_name=runSnippet)] pub fn run_snippet(&mut self, snippet: String) -> String { - let session = self.get_session_mut(); - match session.eval(snippet.clone(), None, false) { - Ok(res) => match res.result { - EvaluationResult::Snippet(result) => clarity_values::to_raw_value(&result.result), - EvaluationResult::Contract(_) => unreachable!( - "Contract evaluation result should not be returned from eval_snippet", - ), - }, - Err(diagnostics) => { - let mut message = "error:".to_string(); - diagnostics.iter().for_each(|d| { - message = format!("{message}\n{}", d.message); - }); - message - } + let mut hooks: Vec<&mut dyn EvalHook> = Vec::new(); + + let mut coverage_hook = self.coverage_hook.take(); + if let Some(ref mut hook) = coverage_hook { + hooks.push(hook); } + + let execution = { + let session = self.get_session_mut(); + match session.eval(snippet.clone(), Some(hooks), false) { + Ok(res) => match res.result { + EvaluationResult::Snippet(result) => { + clarity_values::to_raw_value(&result.result) + } + EvaluationResult::Contract(_) => unreachable!( + "Contract evaluation result should not be returned from eval_snippet", + ), + }, + Err(diagnostics) => { + let mut message = "error:".to_string(); + diagnostics.iter().for_each(|d| { + message = format!("{message}\n{}", d.message); + }); + message + } + } + }; + + self.coverage_hook = coverage_hook; + execution } #[wasm_bindgen(js_name=execute)] pub fn execute(&mut self, snippet: String) -> Result { - let session = self.get_session_mut(); - match session.eval(snippet.clone(), None, false) { - Ok(res) => Ok(execution_result_to_transaction_res(&res)), - Err(diagnostics) => { - let message = diagnostics - .iter() - .map(|d| d.message.to_string()) - .collect::>() - .join("\n"); - Err(format!("error: {}", message)) - } + let mut hooks: Vec<&mut dyn EvalHook> = Vec::new(); + + let mut coverage_hook = self.coverage_hook.take(); + if let Some(ref mut hook) = coverage_hook { + hooks.push(hook); } + + let execution = { + let session = self.get_session_mut(); + match session.eval(snippet.clone(), Some(hooks), false) { + Ok(res) => Ok(execution_result_to_transaction_res(&res)), + Err(diagnostics) => { + let message = diagnostics + .iter() + .map(|d| d.message.to_string()) + .collect::>() + .join("\n"); + Err(format!("error: {}", message)) + } + } + }; + + self.coverage_hook = coverage_hook; + execution } #[wasm_bindgen(js_name=executeCommand)] diff --git a/components/clarinet-sdk/node/tests/reports.test.ts b/components/clarinet-sdk/node/tests/reports.test.ts index 39ef49821..6f047abfd 100644 --- a/components/clarinet-sdk/node/tests/reports.test.ts +++ b/components/clarinet-sdk/node/tests/reports.test.ts @@ -107,3 +107,31 @@ describe("simnet can report both costs and coverage", () => { expect(reports.coverage.length).greaterThan(0); }); }); + +describe.only("run-snippet and execute also report coverage", () => { + it("simnet.execute reports coverage", async () => { + const simnet = await initSimnet("tests/fixtures/Clarinet.toml", true, { + trackCoverage: true, + trackCosts: false, + }); + simnet.execute("(contract-call? .counter increment)"); + simnet.execute("(contract-call? .counter increment)"); + + const reports = simnet.collectReport(false, ""); + // line 26, within the increment function, is executed twice + expect(reports.coverage).toContain("DA:26,2"); + }); + + it("simnet.runSnippet reports coverage", async () => { + const simnet = await initSimnet("tests/fixtures/Clarinet.toml", true, { + trackCoverage: true, + trackCosts: false, + }); + simnet.runSnippet("(contract-call? .counter increment)"); + simnet.runSnippet("(contract-call? .counter increment)"); + + const reports = simnet.collectReport(false, ""); + // line 26, within the increment function, is executed twice + expect(reports.coverage).toContain("DA:26,2"); + }); +});