1pub mod ecal;
2pub mod execute;
3pub mod setup;
4
5use crate::execute::TestExecutor;
6use crate::setup::{
7 ContractDeploymentSetup, ContractTestSetup, DeploymentSetup, ScriptTestSetup, TestSetup,
8};
9use ecal::EcalSyscallHandler;
10use forc_pkg::{self as pkg, BuildOpts, DumpOpts};
11use forc_util::tx_utils::decode_fuel_vm_log_data;
12use fuel_abi_types::abi::program::ProgramABI;
13use fuel_abi_types::revert_info::RevertInfo;
14use fuel_tx as tx;
15use fuel_vm::checked_transaction::builder::TransactionBuilderExt;
16use fuel_vm::{self as vm};
17use pkg::TestPassCondition;
18use pkg::{Built, BuiltPackage};
19use rand::{Rng, SeedableRng};
20use rayon::prelude::*;
21use std::{collections::HashMap, fs, path::PathBuf, sync::Arc};
22use sway_core::BuildTarget;
23use sway_types::Span;
24use tx::consensus_parameters::ConsensusParametersV1;
25use tx::{ConsensusParameters, ContractParameters, ScriptParameters, TxParameters};
26use vm::interpreter::{InterpreterParams, MemoryInstance};
27use vm::prelude::SecretKey;
28
29#[derive(Debug)]
31pub enum Tested {
32 Package(Box<TestedPackage>),
33 Workspace(Vec<TestedPackage>),
34}
35
36#[derive(Debug)]
38pub struct TestedPackage {
39 pub built: Box<pkg::BuiltPackage>,
40 pub tests: Vec<TestResult>,
42}
43
44#[derive(Debug)]
45pub struct TestDetails {
46 pub file_path: Arc<PathBuf>,
48 pub line_number: usize,
50}
51
52#[derive(Debug, Clone)]
54pub struct TestFilter<'a> {
55 pub filter_phrase: &'a str,
57 pub exact_match: bool,
60}
61
62#[derive(Debug, Clone)]
64pub struct TestResult {
65 pub name: String,
67 pub duration: std::time::Duration,
69 pub span: Span,
71 pub file_path: Arc<PathBuf>,
73 pub state: vm::state::ProgramState,
75 pub condition: pkg::TestPassCondition,
77 pub logs: Vec<fuel_tx::Receipt>,
79 pub gas_used: u64,
81 pub ecal: Box<EcalSyscallHandler>,
83}
84
85const TEST_METADATA_SEED: u64 = 0x7E57u64;
86type ContractDependencyMap = HashMap<pkg::Pinned, Vec<Arc<pkg::BuiltPackage>>>;
88
89pub enum BuiltTests {
91 Package(PackageTests),
92 Workspace(Vec<PackageTests>),
93}
94
95#[derive(Debug)]
102pub enum PackageTests {
103 Contract(PackageWithDeploymentToTest),
104 Script(PackageWithDeploymentToTest),
105 Predicate(Arc<pkg::BuiltPackage>),
106 Library(Arc<pkg::BuiltPackage>),
107}
108
109#[derive(Debug)]
111pub struct ContractToTest {
112 pkg: Arc<pkg::BuiltPackage>,
114 without_tests_bytecode: pkg::BuiltPackageBytecode,
116 contract_dependencies: Vec<Arc<pkg::BuiltPackage>>,
117}
118
119#[derive(Debug)]
121pub struct ScriptToTest {
122 pkg: Arc<pkg::BuiltPackage>,
124 contract_dependencies: Vec<Arc<pkg::BuiltPackage>>,
125}
126
127#[derive(Debug)]
129pub enum PackageWithDeploymentToTest {
130 Script(ScriptToTest),
131 Contract(ContractToTest),
132}
133
134#[derive(Default, Clone)]
136pub struct TestOpts {
137 pub pkg: pkg::PkgOpts,
138 pub print: pkg::PrintOpts,
139 pub minify: pkg::MinifyOpts,
140 pub binary_outfile: Option<String>,
142 pub debug_outfile: Option<String>,
146 pub hex_outfile: Option<String>,
148 pub build_target: BuildTarget,
150 pub build_profile: String,
152 pub release: bool,
155 pub error_on_warnings: bool,
157 pub time_phases: bool,
159 pub profile: bool,
161 pub metrics_outfile: Option<String>,
163 pub experimental: Vec<sway_features::Feature>,
165 pub no_experimental: Vec<sway_features::Feature>,
167}
168
169#[derive(Default, Clone)]
171pub struct TestPrintOpts {
172 pub pretty_print: bool,
173 pub print_logs: bool,
174}
175
176pub struct DecodedLog {
178 pub value: String,
179}
180
181impl TestedPackage {
182 pub fn tests_passed(&self) -> bool {
183 self.tests.iter().all(|test| test.passed())
184 }
185}
186
187impl PackageWithDeploymentToTest {
188 fn pkg(&self) -> &BuiltPackage {
192 match self {
193 PackageWithDeploymentToTest::Script(script) => &script.pkg,
194 PackageWithDeploymentToTest::Contract(contract) => &contract.pkg,
195 }
196 }
197
198 fn contract_dependencies(&self) -> impl Iterator<Item = &Arc<BuiltPackage>> + '_ {
200 match self {
201 PackageWithDeploymentToTest::Script(script_to_test) => {
202 script_to_test.contract_dependencies.iter()
203 }
204 PackageWithDeploymentToTest::Contract(contract_to_test) => {
205 contract_to_test.contract_dependencies.iter()
206 }
207 }
208 }
209
210 fn deploy(&self) -> anyhow::Result<TestSetup> {
215 let gas_price = 0;
217 let params = maxed_consensus_params();
218 let storage = vm::storage::MemoryStorage::default();
219 let interpreter_params = InterpreterParams::new(gas_price, params.clone());
220 let mut interpreter: vm::prelude::Interpreter<_, _, _, vm::interpreter::NotSupportedEcal> =
221 vm::interpreter::Interpreter::with_storage(
222 MemoryInstance::new(),
223 storage,
224 interpreter_params,
225 );
226
227 let contract_dependency_setups = self
230 .contract_dependencies()
231 .map(|built_pkg| deployment_transaction(built_pkg, &built_pkg.bytecode, ¶ms));
232
233 let contract_dependency_ids = contract_dependency_setups
235 .map(|(contract_id, tx)| {
236 let tx = tx
238 .into_ready(gas_price, params.gas_costs(), params.fee_params(), None)
239 .unwrap();
240 interpreter.transact(tx).map_err(anyhow::Error::msg)?;
241 Ok(contract_id)
242 })
243 .collect::<anyhow::Result<Vec<_>>>()?;
244
245 let deployment_setup = if let PackageWithDeploymentToTest::Contract(contract_to_test) = self
246 {
247 let (root_contract_id, root_contract_tx) = deployment_transaction(
250 &contract_to_test.pkg,
251 &contract_to_test.without_tests_bytecode,
252 ¶ms,
253 );
254 let root_contract_tx = root_contract_tx
255 .into_ready(gas_price, params.gas_costs(), params.fee_params(), None)
256 .unwrap();
257 interpreter
259 .transact(root_contract_tx)
260 .map_err(anyhow::Error::msg)?;
261 let storage = interpreter.as_ref().clone();
262 DeploymentSetup::Contract(ContractTestSetup {
263 storage,
264 contract_dependency_ids,
265 root_contract_id,
266 })
267 } else {
268 let storage = interpreter.as_ref().clone();
269 DeploymentSetup::Script(ScriptTestSetup {
270 storage,
271 contract_dependency_ids,
272 })
273 };
274
275 Ok(TestSetup::WithDeployment(deployment_setup))
276 }
277}
278
279fn get_contract_dependency_map(
284 built: &Built,
285 build_plan: &pkg::BuildPlan,
286) -> ContractDependencyMap {
287 let built_members: HashMap<&pkg::Pinned, Arc<pkg::BuiltPackage>> =
288 built.into_members().collect();
289 build_plan
291 .member_nodes()
292 .map(|member_node| {
293 let graph = build_plan.graph();
294 let pinned_member = graph[member_node].clone();
295 let contract_dependencies = build_plan
296 .contract_dependencies(member_node)
297 .map(|contract_dependency_node_ix| graph[contract_dependency_node_ix].clone())
298 .filter_map(|pinned| built_members.get(&pinned))
299 .cloned()
300 .collect::<Vec<_>>();
301 (pinned_member, contract_dependencies)
302 })
303 .collect()
304}
305
306impl BuiltTests {
307 pub fn from_built(built: Built, build_plan: &pkg::BuildPlan) -> anyhow::Result<BuiltTests> {
309 let contract_dependencies = get_contract_dependency_map(&built, build_plan);
310 let built = match built {
311 Built::Package(built_pkg) => BuiltTests::Package(PackageTests::from_built_pkg(
312 built_pkg,
313 &contract_dependencies,
314 )),
315 Built::Workspace(built_workspace) => {
316 let pkg_tests = built_workspace
317 .into_iter()
318 .map(|built_pkg| {
319 PackageTests::from_built_pkg(built_pkg, &contract_dependencies)
320 })
321 .collect();
322 BuiltTests::Workspace(pkg_tests)
323 }
324 };
325 Ok(built)
326 }
327}
328
329impl<'a> PackageTests {
330 pub(crate) fn built_pkg_with_tests(&'a self) -> &'a BuiltPackage {
335 match self {
336 PackageTests::Contract(contract) => contract.pkg(),
337 PackageTests::Script(script) => script.pkg(),
338 PackageTests::Predicate(predicate) => predicate,
339 PackageTests::Library(library) => library,
340 }
341 }
342
343 fn from_built_pkg(
345 built_pkg: Arc<BuiltPackage>,
346 contract_dependencies: &ContractDependencyMap,
347 ) -> PackageTests {
348 let built_without_tests_bytecode = built_pkg.bytecode_without_tests.clone();
349 let contract_dependencies: Vec<Arc<pkg::BuiltPackage>> = contract_dependencies
350 .get(&built_pkg.descriptor.pinned)
351 .cloned()
352 .unwrap_or_default();
353 match built_without_tests_bytecode {
354 Some(contract_without_tests) => {
355 let contract_to_test = ContractToTest {
356 pkg: built_pkg,
357 without_tests_bytecode: contract_without_tests,
358 contract_dependencies,
359 };
360 PackageTests::Contract(PackageWithDeploymentToTest::Contract(contract_to_test))
361 }
362 None => match built_pkg.tree_type {
363 sway_core::language::parsed::TreeType::Predicate => {
364 PackageTests::Predicate(built_pkg)
365 }
366 sway_core::language::parsed::TreeType::Library => PackageTests::Library(built_pkg),
367 sway_core::language::parsed::TreeType::Script => {
368 let script_to_test = ScriptToTest {
369 pkg: built_pkg,
370 contract_dependencies,
371 };
372 PackageTests::Script(PackageWithDeploymentToTest::Script(script_to_test))
373 }
374 _ => unreachable!("contracts are already handled"),
375 },
376 }
377 }
378
379 pub(crate) fn run_tests(
381 &self,
382 test_runners: &rayon::ThreadPool,
383 test_filter: Option<&TestFilter>,
384 ) -> anyhow::Result<TestedPackage> {
385 let pkg_with_tests = self.built_pkg_with_tests();
386 let tests = test_runners.install(|| {
387 pkg_with_tests
388 .bytecode
389 .entries
390 .par_iter()
391 .filter_map(|entry| {
392 if let Some(test_entry) = entry.kind.test() {
393 let name = entry.finalized.fn_name.clone();
396 if let Some(filter) = test_filter {
397 if !filter.filter(&name) {
398 return None;
399 }
400 }
401 return Some((entry, test_entry));
402 }
403 None
404 })
405 .map(|(entry, test_entry)| {
406 let offset = u32::try_from(entry.finalized.imm)
408 .expect("test instruction offset out of range");
409 let name = entry.finalized.fn_name.clone();
410 let test_setup = self.setup()?;
411 TestExecutor::build(
412 &pkg_with_tests.bytecode.bytes,
413 offset,
414 test_setup,
415 test_entry,
416 name,
417 )?
418 .execute()
419 })
420 .collect::<anyhow::Result<_>>()
421 })?;
422
423 Ok(TestedPackage {
424 built: Box::new(pkg_with_tests.clone()),
425 tests,
426 })
427 }
428
429 pub fn setup(&self) -> anyhow::Result<TestSetup> {
434 match self {
435 PackageTests::Contract(contract_to_test) => {
436 let test_setup = contract_to_test.deploy()?;
437 Ok(test_setup)
438 }
439 PackageTests::Script(script_to_test) => {
440 let test_setup = script_to_test.deploy()?;
441 Ok(test_setup)
442 }
443 PackageTests::Predicate(_) | PackageTests::Library(_) => Ok(
444 TestSetup::WithoutDeployment(vm::storage::MemoryStorage::default()),
445 ),
446 }
447 }
448}
449
450impl From<TestOpts> for pkg::BuildOpts {
451 fn from(val: TestOpts) -> Self {
452 pkg::BuildOpts {
453 pkg: val.pkg,
454 print: val.print,
455 minify: val.minify,
456 dump: DumpOpts::default(),
457 binary_outfile: val.binary_outfile,
458 debug_outfile: val.debug_outfile,
459 hex_outfile: val.hex_outfile,
460 build_target: val.build_target,
461 build_profile: val.build_profile,
462 release: val.release,
463 error_on_warnings: val.error_on_warnings,
464 time_phases: val.time_phases,
465 profile: val.profile,
466 metrics_outfile: val.metrics_outfile,
467 tests: true,
468 member_filter: Default::default(),
469 experimental: val.experimental,
470 no_experimental: val.no_experimental,
471 }
472 }
473}
474
475impl TestOpts {
476 pub fn into_build_opts(self) -> pkg::BuildOpts {
478 pkg::BuildOpts {
479 pkg: self.pkg,
480 print: self.print,
481 minify: self.minify,
482 dump: DumpOpts::default(),
483 binary_outfile: self.binary_outfile,
484 debug_outfile: self.debug_outfile,
485 hex_outfile: self.hex_outfile,
486 build_target: self.build_target,
487 build_profile: self.build_profile,
488 release: self.release,
489 error_on_warnings: self.error_on_warnings,
490 time_phases: self.time_phases,
491 profile: self.profile,
492 metrics_outfile: self.metrics_outfile,
493 tests: true,
494 member_filter: Default::default(),
495 experimental: self.experimental,
496 no_experimental: self.no_experimental,
497 }
498 }
499}
500
501impl TestResult {
502 pub fn passed(&self) -> bool {
504 match &self.condition {
505 TestPassCondition::ShouldRevert(revert_code) => match revert_code {
506 Some(revert_code) => self.state == vm::state::ProgramState::Revert(*revert_code),
507 None => matches!(self.state, vm::state::ProgramState::Revert(_)),
508 },
509 TestPassCondition::ShouldNotRevert => {
510 !matches!(self.state, vm::state::ProgramState::Revert(_))
511 }
512 }
513 }
514
515 pub fn revert_code(&self) -> Option<u64> {
517 match self.state {
518 vm::state::ProgramState::Revert(revert_code) => Some(revert_code),
519 _ => None,
520 }
521 }
522
523 pub fn revert_info(
524 &self,
525 program_abi: Option<&ProgramABI>,
526 logs: &[fuel_tx::Receipt],
527 ) -> Option<RevertInfo> {
528 let decode_last_log_data = |log_id: &str, program_abi: &ProgramABI| {
529 logs.last()
530 .and_then(|log| {
531 if let fuel_tx::Receipt::LogData {
532 data: Some(data), ..
533 } = log
534 {
535 decode_fuel_vm_log_data(log_id, data, program_abi).ok()
536 } else {
537 None
538 }
539 })
540 .map(|decoded_log| decoded_log.value)
541 };
542
543 self.revert_code()
544 .map(|revert_code| RevertInfo::new(revert_code, program_abi, decode_last_log_data))
545 }
546
547 pub fn details(&self) -> anyhow::Result<TestDetails> {
549 let span_start = self.span.start();
550 let file_str = fs::read_to_string(&*self.file_path)?;
551 let line_number = file_str[..span_start]
552 .chars()
553 .filter(|&c| c == '\n')
554 .count();
555 Ok(TestDetails {
556 file_path: self.file_path.clone(),
557 line_number,
558 })
559 }
560}
561
562pub enum TestRunnerCount {
565 Manual(usize),
566 Auto,
567}
568
569#[derive(Clone, Debug, Default)]
570pub struct TestCount {
571 pub total: usize,
572 pub ignored: usize,
573}
574
575impl TestFilter<'_> {
576 fn filter(&self, fn_name: &str) -> bool {
577 if self.exact_match {
578 fn_name == self.filter_phrase
579 } else {
580 fn_name.contains(self.filter_phrase)
581 }
582 }
583}
584
585impl BuiltTests {
586 pub fn test_count(&self, test_filter: Option<&TestFilter>) -> TestCount {
588 let pkgs: Vec<&PackageTests> = match self {
589 BuiltTests::Package(pkg) => vec![pkg],
590 BuiltTests::Workspace(workspace) => workspace.iter().collect(),
591 };
592 pkgs.iter()
593 .flat_map(|pkg| {
594 pkg.built_pkg_with_tests()
595 .bytecode
596 .entries
597 .iter()
598 .filter_map(|entry| entry.kind.test().map(|test| (entry, test)))
599 })
600 .fold(TestCount::default(), |acc, (pkg_entry, _)| {
601 let num_ignored = match &test_filter {
602 Some(filter) => {
603 if filter.filter(&pkg_entry.finalized.fn_name) {
604 acc.ignored
605 } else {
606 acc.ignored + 1
607 }
608 }
609 None => acc.ignored,
610 };
611 TestCount {
612 total: acc.total + 1,
613 ignored: num_ignored,
614 }
615 })
616 }
617
618 pub fn run(
620 self,
621 test_runner_count: TestRunnerCount,
622 test_filter: Option<TestFilter>,
623 ) -> anyhow::Result<Tested> {
624 let test_runners = match test_runner_count {
625 TestRunnerCount::Manual(runner_count) => rayon::ThreadPoolBuilder::new()
626 .num_threads(runner_count)
627 .build(),
628 TestRunnerCount::Auto => rayon::ThreadPoolBuilder::new().build(),
629 }?;
630 run_tests(self, &test_runners, test_filter)
631 }
632}
633
634pub fn build(opts: TestOpts) -> anyhow::Result<BuiltTests> {
636 let build_opts: BuildOpts = opts.into();
637 let build_plan = pkg::BuildPlan::from_pkg_opts(&build_opts.pkg)?;
638 let built = pkg::build_with_options(&build_opts, None)?;
639 BuiltTests::from_built(built, &build_plan)
640}
641
642pub(crate) fn maxed_consensus_params() -> ConsensusParameters {
645 let script_params = ScriptParameters::DEFAULT
646 .with_max_script_length(u64::MAX)
647 .with_max_script_data_length(u64::MAX);
648 let tx_params = TxParameters::DEFAULT.with_max_size(u64::MAX);
649 let contract_params = ContractParameters::DEFAULT
650 .with_contract_max_size(u64::MAX)
651 .with_max_storage_slots(u64::MAX);
652 ConsensusParameters::V1(ConsensusParametersV1 {
653 script_params,
654 tx_params,
655 contract_params,
656 ..Default::default()
657 })
658}
659
660fn deployment_transaction(
663 built_pkg: &pkg::BuiltPackage,
664 without_tests_bytecode: &pkg::BuiltPackageBytecode,
665 params: &tx::ConsensusParameters,
666) -> ContractDeploymentSetup {
667 let mut storage_slots = built_pkg.storage_slots.clone();
669 storage_slots.sort();
670 let bytecode = &without_tests_bytecode.bytes;
671 let contract = tx::Contract::from(bytecode.clone());
672 let root = contract.root();
673 let state_root = tx::Contract::initial_state_root(storage_slots.iter());
674 let salt = tx::Salt::zeroed();
675 let contract_id = contract.id(&salt, &root, &state_root);
676
677 let rng = &mut rand::rngs::StdRng::seed_from_u64(TEST_METADATA_SEED);
679
680 let secret_key = SecretKey::random(rng);
682 let utxo_id = rng.r#gen();
683 let amount = 1;
684 let maturity = 1u32.into();
685 let asset_id = tx::AssetId::BASE;
689 let tx_pointer = rng.r#gen();
690 let block_height = (u32::MAX >> 1).into();
691
692 let tx = tx::TransactionBuilder::create(bytecode.as_slice().into(), salt, storage_slots)
693 .with_params(params.clone())
694 .add_unsigned_coin_input(secret_key, utxo_id, amount, asset_id, tx_pointer)
695 .add_output(tx::Output::contract_created(contract_id, state_root))
696 .maturity(maturity)
697 .finalize_checked(block_height);
698 (contract_id, tx)
699}
700
701fn run_tests(
705 built: BuiltTests,
706 test_runners: &rayon::ThreadPool,
707 test_filter: Option<TestFilter>,
708) -> anyhow::Result<Tested> {
709 match built {
710 BuiltTests::Package(pkg) => {
711 let tested_pkg = pkg.run_tests(test_runners, test_filter.as_ref())?;
712 Ok(Tested::Package(Box::new(tested_pkg)))
713 }
714 BuiltTests::Workspace(workspace) => {
715 let tested_pkgs = workspace
716 .into_iter()
717 .map(|pkg| pkg.run_tests(test_runners, test_filter.as_ref()))
718 .collect::<anyhow::Result<Vec<TestedPackage>>>()?;
719 Ok(Tested::Workspace(tested_pkgs))
720 }
721 }
722}
723
724#[cfg(test)]
725mod tests {
726 use std::path::PathBuf;
727
728 use crate::{build, BuiltTests, TestFilter, TestOpts, TestResult};
729
730 const TEST_DATA_FOLDER_NAME: &str = "test_data";
733 const TEST_LIBRARY_PACKAGE_NAME: &str = "test_library";
735 const TEST_CONTRACT_PACKAGE_NAME: &str = "test_contract";
737 const TEST_PREDICATE_PACKAGE_NAME: &str = "test_predicate";
739 const TEST_SCRIPT_PACKAGE_NAME: &str = "test_script";
741
742 fn test_package_built_tests(package_name: &str) -> anyhow::Result<BuiltTests> {
745 let cargo_manifest_dir = env!("CARGO_MANIFEST_DIR");
746 let library_package_dir = PathBuf::from(cargo_manifest_dir)
747 .join(TEST_DATA_FOLDER_NAME)
748 .join(package_name);
749 let library_package_dir_string = library_package_dir.to_string_lossy().to_string();
750 let build_options = TestOpts {
751 pkg: forc_pkg::PkgOpts {
752 path: Some(library_package_dir_string),
753 ..Default::default()
754 },
755 ..Default::default()
756 };
757 build(build_options)
758 }
759
760 fn test_package_test_results(
761 package_name: &str,
762 test_filter: Option<TestFilter>,
763 ) -> anyhow::Result<Vec<TestResult>> {
764 let built_tests = test_package_built_tests(package_name)?;
765 let test_runner_count = crate::TestRunnerCount::Auto;
766 let tested = built_tests.run(test_runner_count, test_filter)?;
767 match tested {
768 crate::Tested::Package(tested_pkg) => Ok(tested_pkg.tests),
769 crate::Tested::Workspace(_) => {
770 unreachable!("test_library is a package, not a workspace.")
771 }
772 }
773 }
774
775 #[test]
776 fn test_filter_exact_match() {
777 let filter_phrase = "test_bam";
778 let test_filter = TestFilter {
779 filter_phrase,
780 exact_match: true,
781 };
782
783 let test_library_results =
784 test_package_test_results(TEST_LIBRARY_PACKAGE_NAME, Some(test_filter.clone()))
785 .unwrap();
786 let tested_library_test_count = test_library_results.len();
787
788 let test_contract_results =
789 test_package_test_results(TEST_CONTRACT_PACKAGE_NAME, Some(test_filter.clone()))
790 .unwrap();
791 let tested_contract_test_count = test_contract_results.len();
792
793 let test_predicate_results =
794 test_package_test_results(TEST_PREDICATE_PACKAGE_NAME, Some(test_filter.clone()))
795 .unwrap();
796 let tested_predicate_test_count = test_predicate_results.len();
797
798 let test_script_results =
799 test_package_test_results(TEST_SCRIPT_PACKAGE_NAME, Some(test_filter)).unwrap();
800 let tested_script_test_count = test_script_results.len();
801
802 assert_eq!(tested_library_test_count, 1);
803 assert_eq!(tested_contract_test_count, 1);
804 assert_eq!(tested_predicate_test_count, 1);
805 assert_eq!(tested_script_test_count, 1);
806 }
807
808 #[test]
809 fn test_filter_exact_match_all_ignored() {
810 let filter_phrase = "test_ba";
811 let test_filter = TestFilter {
812 filter_phrase,
813 exact_match: true,
814 };
815
816 let test_library_results =
817 test_package_test_results(TEST_LIBRARY_PACKAGE_NAME, Some(test_filter.clone()))
818 .unwrap();
819 let tested_library_test_count = test_library_results.len();
820
821 let test_contract_results =
822 test_package_test_results(TEST_CONTRACT_PACKAGE_NAME, Some(test_filter.clone()))
823 .unwrap();
824 let tested_contract_test_count = test_contract_results.len();
825
826 let test_predicate_results =
827 test_package_test_results(TEST_PREDICATE_PACKAGE_NAME, Some(test_filter.clone()))
828 .unwrap();
829 let tested_predicate_test_count = test_predicate_results.len();
830
831 let test_script_results =
832 test_package_test_results(TEST_SCRIPT_PACKAGE_NAME, Some(test_filter)).unwrap();
833 let tested_script_test_count = test_script_results.len();
834
835 assert_eq!(tested_library_test_count, 0);
836 assert_eq!(tested_contract_test_count, 0);
837 assert_eq!(tested_predicate_test_count, 0);
838 assert_eq!(tested_script_test_count, 0);
839 }
840
841 #[test]
842 fn test_filter_match_all_ignored() {
843 let filter_phrase = "this_test_does_not_exists";
844 let test_filter = TestFilter {
845 filter_phrase,
846 exact_match: false,
847 };
848
849 let test_library_results =
850 test_package_test_results(TEST_LIBRARY_PACKAGE_NAME, Some(test_filter.clone()))
851 .unwrap();
852 let tested_library_test_count = test_library_results.len();
853
854 let test_contract_results =
855 test_package_test_results(TEST_CONTRACT_PACKAGE_NAME, Some(test_filter.clone()))
856 .unwrap();
857 let tested_contract_test_count = test_contract_results.len();
858
859 let test_predicate_results =
860 test_package_test_results(TEST_PREDICATE_PACKAGE_NAME, Some(test_filter.clone()))
861 .unwrap();
862 let tested_predicate_test_count = test_predicate_results.len();
863
864 let test_script_results =
865 test_package_test_results(TEST_SCRIPT_PACKAGE_NAME, Some(test_filter)).unwrap();
866 let tested_script_test_count = test_script_results.len();
867
868 assert_eq!(tested_library_test_count, 0);
869 assert_eq!(tested_contract_test_count, 0);
870 assert_eq!(tested_predicate_test_count, 0);
871 assert_eq!(tested_script_test_count, 0);
872 }
873
874 #[test]
875 fn test_filter_one_match() {
876 let filter_phrase = "test_ba";
877 let test_filter = TestFilter {
878 filter_phrase,
879 exact_match: false,
880 };
881
882 let test_library_results =
883 test_package_test_results(TEST_LIBRARY_PACKAGE_NAME, Some(test_filter.clone()))
884 .unwrap();
885 let tested_library_test_count = test_library_results.len();
886
887 let test_contract_results =
888 test_package_test_results(TEST_CONTRACT_PACKAGE_NAME, Some(test_filter.clone()))
889 .unwrap();
890 let tested_contract_test_count = test_contract_results.len();
891
892 let test_predicate_results =
893 test_package_test_results(TEST_PREDICATE_PACKAGE_NAME, Some(test_filter.clone()))
894 .unwrap();
895 let tested_predicate_test_count = test_predicate_results.len();
896
897 let test_script_results =
898 test_package_test_results(TEST_SCRIPT_PACKAGE_NAME, Some(test_filter)).unwrap();
899 let tested_script_test_count = test_script_results.len();
900
901 assert_eq!(tested_library_test_count, 1);
902 assert_eq!(tested_contract_test_count, 1);
903 assert_eq!(tested_predicate_test_count, 1);
904 assert_eq!(tested_script_test_count, 1);
905 }
906
907 #[test]
908 fn test_filter_all_match() {
909 let filter_phrase = "est_b";
910 let test_filter = TestFilter {
911 filter_phrase,
912 exact_match: false,
913 };
914
915 let test_library_results =
916 test_package_test_results(TEST_LIBRARY_PACKAGE_NAME, Some(test_filter.clone()))
917 .unwrap();
918 let tested_library_test_count = test_library_results.len();
919
920 let test_contract_results =
921 test_package_test_results(TEST_CONTRACT_PACKAGE_NAME, Some(test_filter.clone()))
922 .unwrap();
923 let tested_contract_test_count = test_contract_results.len();
924
925 let test_predicate_results =
926 test_package_test_results(TEST_PREDICATE_PACKAGE_NAME, Some(test_filter.clone()))
927 .unwrap();
928 let tested_predicate_test_count = test_predicate_results.len();
929
930 let test_script_results =
931 test_package_test_results(TEST_SCRIPT_PACKAGE_NAME, Some(test_filter)).unwrap();
932 let tested_script_test_count = test_script_results.len();
933
934 assert_eq!(tested_library_test_count, 2);
935 assert_eq!(tested_contract_test_count, 2);
936 assert_eq!(tested_predicate_test_count, 2);
937 assert_eq!(tested_script_test_count, 2);
938 }
939
940 #[test]
941 fn test_no_filter() {
942 let test_filter = None;
943
944 let test_library_results =
945 test_package_test_results(TEST_LIBRARY_PACKAGE_NAME, test_filter.clone()).unwrap();
946 let tested_library_test_count = test_library_results.len();
947
948 let test_contract_results =
949 test_package_test_results(TEST_CONTRACT_PACKAGE_NAME, test_filter.clone()).unwrap();
950 let tested_contract_test_count = test_contract_results.len();
951
952 let test_predicate_results =
953 test_package_test_results(TEST_PREDICATE_PACKAGE_NAME, test_filter.clone()).unwrap();
954 let tested_predicate_test_count = test_predicate_results.len();
955
956 let test_script_results =
957 test_package_test_results(TEST_SCRIPT_PACKAGE_NAME, test_filter).unwrap();
958 let tested_script_test_count = test_script_results.len();
959
960 assert_eq!(tested_library_test_count, 2);
961 assert_eq!(tested_contract_test_count, 2);
962 assert_eq!(tested_predicate_test_count, 2);
963 assert_eq!(tested_script_test_count, 2);
964 }
965}