Can I test just the code in a single module? - rust

I've got a Rust project that uses a fairly large framework. Compilation and macro expansion take a really long time. If I make a tiny change to the code, it takes a minute or more before before "cargo test" actually executes.
Is it possible to create a sub-project or sub-module within the same crate and test just the code in the module, assuming there are no dependencies on code outside the module?

You might be interested in "cargo workspaces" (https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html).
Essentially, instead of splitting your code into multiple mods, you split it into multiple crates. These crates can depend on each other via "path dependencies". For example, you could have something like:
[dependencies]
my_helper_crate = { path = "path/to/crate" }
The book has much more detail on this, but a nice feature of using workspaces is that your crates can have separate Cargo.tomls, but share a Cargo.lock, so you won't get issues around incompatible versions of crates.
With this setup, you can build one crate without building the rest of them, so you can cut down on a dev feedback loop.
However, if you have crate_a which depends on crate_b, building crate_a still requires building crate_b, there's not really any getting around that. The benefit is mainly for the leaves of your dependency graph.

Yeah, cargo test will take arguments which match specific tests that you want to run (Cargo book). For example, if you have modules foo and bar, you can run cargo test foo to run tests from that module, excluding all others.

Related

Prevent access to dependencies in examples in Rust project?

I am making a library in rust, and I learned that I could put example usages of the library in an examples directory in the root directory and then run them with cargo run --example hello. However, I noticed that the dependencies I specify in Cargo.toml are also available in the example code. This is a bit odd to me. These dependencies belong to the library and the user shouldn't be aware of them and certainly not use them himself (unless he happens to depend on them too, I guess).
For example, I have nalgebra = "0.31.0" in Cargo.toml and use it as a backend for vectors and matrices and other mathematical operations.
I created my own wrappers for vectors and matrices, so the user shouldn't access nalgebra types directly. I find it weird that when writing examples for the library, I can write use nalgebra as na; and use it without any issues. I guess it's helpful for debugging purposes, but when writing a complete example, this code shouldn't compile.
Is there a way to generate compiler errors when trying to use dependencies in example code, or is it simply my responsibility to write examples that reflect actual usage of the library?
is it simply my responsibility to write examples that reflect actual usage of the library?
Yes.
This comes up in other situations too: as long as you're writing code inside a single Cargo package, all that code shares a common set of dependencies (with the exception that [dev-dependencies] are not available to lib and bin targets, only test, example, and bench targets).
If you want a different set of dependencies, the only option is to split the example(s) into a separate package (which can be in a workspace with the library package). In my experience, it's somewhat common for Rust projects to have a separate package for examples, particularly when those examples have shared code; for example, a graphics library whose examples need window-management code might have structure like
Cargo.toml # workspace declaration
the-library/
Cargo.toml
src/
lib.rs
examples/
Cargo.toml # has a `{ path = "../the-library" }` dependency
src/
lib.rs # contains setup code the examples use
examples/
ex1.rs
ex2.rs
There is a disadvantage to doing this: your examples won't be included in the package uploaded to the registry, and the new rustdoc feature that shows snippets of examples in the docs of functions that they use, won't find these examples.
However, if your only concern is “the examples shouldn't refer to this library”, then probably the best option is to take care writing the examples.
You can also use clippy to check for unwanted mentions of functions or types, with the disallowed_methods and disallowed_types lints. However, the lists of disallowed items are package-wide configuration, so you'd have to specifically disable the lint inside your library so that clippy doesn't warn on those uses of the dependency.

Rust how to define benchmark only dependencies in Cargo?

How can I only include a package used for benchmarking when I run cargo bench?
The documentation for targets suggests that this is possible but I can't get it to work.
https://doc.rust-lang.org/cargo/reference/cargo-targets.html
Benchmark dependencies don't get their own section in cargo.toml. You need to put them in the [dev-dependencies] along with test dependencies.
As pointed out by #Dogbert in the comments, there is a related issue:
https://github.com/rust-lang/cargo/issues/1596
There is also this useful suggestion to move the benchmarks/quickcheck into a separate repository and use the public interface.
#bluss bluss commented on 2 May 2020 For such cases like benchmarks,
for now I'd recommend using an additional non-published crate that you
keep in the same repository, that depends on your library and contains
the benchmarks. It will need to use the public APIs, of course, but
that's ok in most cases. As an example of this, ndarray has a
subdirectory for blas-tests that runs tests that depend on BLAS.

What is the exact difference between a Crate and a Package?

I come from a Java background and have recently started with Rust.
The official Rust doc is pretty self-explanatory except the chapter that explains Crates and Packages.
The official doc complicates it with so many ORs and ANDs while explaining the two.
This reddit post explains it a little better, but is not thorough.
What is the exact difference between a Crate and Package in Rust? Where/When do we use them?
Much thanks!
Crates
From the perspective of the Rust compiler, "crate" is the name of the compilation unit. A crate consists of an hierarchy of modules in one or multiple files. This is in contrast to most "traditional" compiled languages like Java, C or C++, where the compilation unit is a single file.
From the perspective of an user, this definition isn't really helpful. Indeed, in most cases, you will need to distinguish between two types of crates:
binary crates can be compiled to executables by the Rust compiler. For example, Cargo, the Rust package manager, is a binary crate translated by the Rust compiler to the executable that you use to manage your project.
library crates are what you'd simply call libraries in other languages. A binary crate can depend on library crates to use functionality supplied by the libraries.
Packages
The concept of packages does not originate in the Rust compiler, but in Cargo, the Rust package manager. At least for simple projects, a package is also what you will check into version control.
A package consists of one or multiple crates, but no more than one library crate.
Creating packages
to create a new package consisting of one binary crate, you can run cargo new
to create a new package consisting of one library crate, you can run cargo new --lib
to create a package consisting of a library as well as one or multiple binaries, you can run either cargo new or cargo new --lib and then modify the package directory structure to add the other crate
When should you use crates, and when should you use packages?
As you can see now, this question doesn't really make sense – you should and must always use both. A package can't exist without at least one crate, and a crate is (at least if you are using Cargo) always part of a package.
Therefore, a better question is this:
When should you put multiple crates into one package?
There are multiple reasons to have more than one crate in a package. For example:
If you have a binary crate, it is idiomatic to have the "business logic" in a library in the same package. This has multiple advantages:
Libraries can be integration tested while binaries can't
If you later decide that the business logic needs to also be used in another binary, it is trivial to add this second binary to the package and also use the library
If you have a library crate that generates some files (a database engine or something like that), you may want to have a helper binary to inspect those files
Note that if you have a very big project, you may instead want to use the workspace feature of Cargo in these cases.

Test for GHC compile time errors

I'm working on proto-lens#400 tweaking a Haskell code generator. In one of the tests I'd like to verify that certain API has not been built. Specifically, I want to ensure that a certain type of program will not type check successfully. I'd also have a similar program with one identifier changed which should compile, to guard against a typo breaking the test. Reading Extending and using GHC as a Library I have managed to have my test write a small file and compile it using GHC as a library.
But I need the code emitted by the test to load some other modules. Specifically the output of the code generator of that project and its runtime environment with transitive dependencies. I have at best a very rough understanding of stack and hpack, which is providing the build time system. I know I can add dependencies to some package.yaml file to make them available to individual tests, but I have no clue how to access such dependencies from the GHC session set up as part of running the test. I imagine I might find some usable data in some environment variables, but I also believe such an approach might be undocumented and prone to break without warning.
How can I have a test case use GHC as a library and have it access dependencies expressed in package.yaml? Or alternatively, can I use some construct other than a regular test case to express a file with dependencies but check that the file won't compile?
I don't know if this applies to you because there are too many details going way over my head, but one way to test for type errors is to build your test suite with -fdefer-type-errors and to catch the exception at run-time (of type TypeError).

Is there a generic way to consume my dependency's grunt build process?

Let's say I have a project where I want to use Lo-Dash and jQuery, but I don't need all of the features.
Sure, both these projects have build tools so I can compile exactly the versions I need to save valuable bandwidth and parsing time, but I think it's quite uncomfortable and ugly to install both of them locally, generate my versions and then check them it into my repository.
Much rather I'd like to integrate their grunt process into my own and create custom builds on the go, which would be much more maintainable.
The Lo-Dash team offers this functionality with a dedicated cli and even wraps it with a grunt task. That's very nice indeed, but I want a generic solution for this problem, as it shouldn't be necessary to have every package author replicate this.
I tried to achieve this somehow with grunt-shell hackery, but as far as I know it's not possible to devDependencies more than one level deep, which makes it impossible even more ugly to execute the required grunt tasks.
So what's your take on this, or should I just move this over to the 0.5.0 discussion of grunt?
What you ask assumes that the package has:
A dependency on Grunt to build a distribution; most popular libraries have this, but some of the less common ones may still use shell scripts or the npm run command for general minification/compression.
Some way of generating a custom build in the first place with a dedicated tool like Modernizr or Lo-Dash has.
You could perhaps substitute number 2 with a generic one that parses both your source code and the library code and uses code coverage to eliminate unnecessary functions from the library. This is already being developed (see goldmine), however I can't make any claims about how good that is because I haven't used it.
Also, I'm not sure how that would work in a AMD context where there are a lot of interconnected dependencies; ideally you'd be able to run the r.js optimiser and get an almond build for production, and then filter that for unnecessary functions (most likely Istanbul, would then have to make sure that the filtered script passed all your unit/integration tests). Not sure how that would end up looking but it'd be pretty cool if that could happen. :-)
However, there is a task especially for running Grunt tasks from 'sub-gruntfiles' that you might like to have a look at: grunt-subgrunt.

Resources