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