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