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