#architecture #cargo-subcommand #subcommand #cargo #testing #plugin

app cargo-archtest

CLI of arch_test_core for rule based architecture tests

6 releases

0.1.8 Jun 15, 2021
0.1.7 Jun 14, 2021

#401 in Cargo plugins

AGPL-3.0

145KB
4K SLoC

ArchTest

crates.io crates.io codecov license Crates.io Crates.2io

ArchTest is a rule based architecture testing tool. It applies static analyses on the specified rust project to extract use relationships.

Features

  • Detect cyclic dependencies level wise or module wise
  • Prohibit parent access
  • Define layer relationships like MayNotAccess, MayOnlyAccess, MyNotBeAccessedBy, MayOnlyBeAccessedBy
  • And more, please consult the documentation.

Install

You can install it either as sub command of Cargo or as a package in your developer dependencies.

# Sub command
cargo install cargo-archtest --force

# Package
[dev-dependencies]
arch_test_core = "*"

How to use it

Using the Cargo sub command

Define in the cargo root path a file called architecture.json. Fill it according to the Specification struct. Example:

{
  "layer_names": ["analyzer", "parser", "domain_values", "entities", "materials", "services", "tests", "utils"],
  "access_rules": [
    "NoLayerCyclicDependencies",
    "NoModuleCyclicDependencies",
    "NoParentAccess",
    {
      "MayNotAccess": {
        "accessor": "parser",
        "accessed": ["analyzer"],
        "when_same_parent": true
      }
    },
    {
      "MayOnlyBeAccessedBy": {
        "accessors": ["services", "tests"],
        "accessed": "materials",
        "when_same_parent": false
      }
    },
    {
      "MayNotBeAccessedBy": {
        "accessors": ["materials", "domain_values", "entities", "utils"],
        "accessed": "services",
        "when_same_parent": true
      }
    }
  ]
}

Using a rust test

You can use the Architecture struct in order to define your architecture. Afterwards you check it for failures.

let architecture = Architecture::new(hash_set!["analyzer".to_owned(), "parser".to_owned(), ...])
.with_access_rule(NoParentAccess)
.with_access_rule(NoModuleCyclicDependencies)
.with_access_rule(NoLayerCyclicDependencies)
...
.with_access_rule(MayNotAccess::new(
    "materials".to_owned(),
    hash_set!["tests".to_owned()],
    true,
));
let module_tree = ModuleTree::new("src/lib.rs");
assert!(architecture.validate_access_rules().is_ok());
assert!(architecture.check_access_rules(&module_tree).is_ok());

If you are interested in the failure you can pretty print it like this:

architecture.check_access_rules(&module_tree).err().unwrap().print(module_tree.tree());

Continuous integration

You can use it in continuous integration by using either methods. If you decide to use the Cargo sub command on GitHub, the following snippet will allow you to test your project.

arch_test:
  name: ArchTest
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v2
    - uses: actions-rs/install@v0.1
      with:
        crate: cargo-archtest
        version: latest
    - run: cargo archtest

Dependencies

~8.5MB
~163K SLoC