How do I use a module from multiple unit test modules? - testing

I have two modules with unit tests and I want to access constants/variables with expected test results from both of those modules.
File: src/lib.rs
mod other;
#[cfg( test )]
mod tests {
mod expected;
use crate::tests::expected::FOUR;
#[test]
fn it_works() {
let result = 2 + 2;
assert_eq!( result, FOUR );
}
}
File: src/other.rs
#[cfg( test )]
mod tests {
use crate::tests::expected::EIGHT;
#[test]
fn it_works() {
let result = 4 + 4;
assert_eq!( result, EIGHT );
}
}
File src/tests/expected.rs
pub const FOUR: i32 = 4;
pub const EIGHT: i32 = 8;
From src/lib.rs I can access the constants within expected.rs. But this is not true from src/other.rs. I get the follwing error:
error[E0603]: module `expected` is private
--> src/other.rs:3:20
|
3 | use crate::tests::expected::EIGHT;
| ^^^^^^^^ private module
|
note: the module `expected` is defined here
--> src/lib.rs:5:2
|
5 | mod expected;
| ^^^^^^^^^^^^^
I have no idea how to make expected public. Where would I place expected.rs or how would I make it accessible from the test code of other modules of the library?

Related

rust-numpy asks for a different version of ndarray

I can reproduce the problem I am currently having with Cargo.toml and lib.rs as shown below.
use ndarray::{ArrayD, ArrayViewD, ArrayViewMutD};
use numpy::{IntoPyArray, PyArrayDyn, PyReadonlyArrayDyn};
use pyo3::prelude::{pymodule, PyModule, PyResult, Python};
#[pymodule]
fn rust_ext(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
// immutable example
fn axpy(a: f64, x: ArrayViewD<'_, f64>, y: ArrayViewD<'_, f64>) -> ArrayD<f64> {
a * &x + &y
}
// mutable example (no return)
fn mult(a: f64, mut x: ArrayViewMutD<'_, f64>) {
x *= a;
}
// wrapper of `axpy`
#[pyfn(m, "axpy")]
fn axpy_py<'py>(
py: Python<'py>,
a: f64,
x: PyReadonlyArrayDyn<f64>,
y: PyReadonlyArrayDyn<f64>,
) -> &'py PyArrayDyn<f64> {
let x = x.as_array();
let y = y.as_array();
axpy(a, x, y).into_pyarray(py)
}
// wrapper of `mult`
#[pyfn(m, "mult")]
fn mult_py(_py: Python<'_>, a: f64, x: &PyArrayDyn<f64>) -> PyResult<()> {
let x = unsafe { x.as_array_mut() };
mult(a, x);
Ok(())
}
Ok(())
}
This code is from the README.md of rust-numpy.
We also created a Cargo.toml as shown below.
[package]
name = "pyotest"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
pyo3 = { version = "0.13",features=["extension-module"] }
numpy = "0.13"
ndarray = "0.14"
[lib]
name="preprocess"
crate-type = ["cdylib"]
If you do this, two versions of ndarray will be installed, resulting in version conflicts, so it will not compile.
The error message is as follows
Compiling pyotest v0.1.0 (/home/bokutotu/pyotest)
error[E0308]: mismatched types
--> src/lib.rs:50:17
|
50 | axpy(a, x, y).into_pyarray(py)
| ^ expected struct `ArrayBase`, found struct `ndarray::ArrayBase`
|
= note: expected struct `ArrayBase<ViewRepr<&f64>, Dim<IxDynImpl>>`
found struct `ndarray::ArrayBase<ndarray::ViewRepr<&f64>, ndarray::dimension::dim::Dim<ndarray::dimension::dynindeximpl::IxDynImpl>>`
= note: perhaps two different versions of crate `ndarray` are being used?
error[E0308]: mismatched types
--> src/lib.rs:50:20
|
50 | axpy(a, x, y).into_pyarray(py)
| ^ expected struct `ArrayBase`, found struct `ndarray::ArrayBase`
|
= note: expected struct `ArrayBase<ViewRepr<&f64>, Dim<IxDynImpl>>`
found struct `ndarray::ArrayBase<ndarray::ViewRepr<&f64>, ndarray::dimension::dim::Dim<ndarray::dimension::dynindeximpl::IxDynImpl>>`
= note: perhaps two different versions of crate `ndarray` are being used?
error[E0599]: no method named `into_pyarray` found for struct `ArrayBase<OwnedRepr<f64>, Dim<IxDynImpl>>` in the current scope
--> src/lib.rs:50:23
|
50 | axpy(a, x, y).into_pyarray(py)
| ^^^^^^^^^^^^ method not found in `ArrayBase<OwnedRepr<f64>, Dim<IxDynImpl>>`
error[E0308]: mismatched types
--> src/lib.rs:57:17
|
57 | mult(a, x);
| ^ expected struct `ArrayBase`, found struct `ndarray::ArrayBase`
|
= note: expected struct `ArrayBase<ViewRepr<&mut f64>, Dim<IxDynImpl>>`
found struct `ndarray::ArrayBase<ndarray::ViewRepr<&mut f64>, ndarray::dimension::dim::Dim<ndarray::dimension::dynindeximpl::IxDynImpl>>`
= note: perhaps two different versions of crate `ndarray` are being used?
warning: unused import: `IntoPyArray`
--> src/lib.rs:25:13
|
25 | use numpy::{IntoPyArray, PyArrayDyn, PyReadonlyArrayDyn};
| ^^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
error: aborting due to 4 previous errors; 1 warning emitted
Some errors have detailed explanations: E0308, E0599.
For more information about an error, try `rustc --explain E0308`.
error: could not compile `pyotest`
To learn more, run the command again with --verbose.
You can also check Cargo.lock to see that it is trying to install two versions of ndarray.
....
[[package]]
name = "ndarray"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c0d5c9540a691d153064dc47a4db2504587a75eae07bf1d73f7a596ebc73c04"
dependencies = [
"matrixmultiply 0.2.4",
"num-complex 0.3.1",
"num-integer",
"num-traits",
"rawpointer",
]
...
[[package]]
name = "ndarray"
version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08e854964160a323e65baa19a0b1a027f76d590faba01f05c0cbc3187221a8c9"
dependencies = [
"matrixmultiply 0.3.1",
"num-complex 0.4.0",
"num-integer",
"num-traits",
"rawpointer",
]
...
[[package]]
name = "numpy"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a996bcd58fb29bef9debf717330cd8876c3b4adbeea4939020a5326a3afad4d9"
dependencies = [
"cfg-if 0.1.10",
"libc",
"ndarray 0.15.3",
"num-complex 0.4.0",
"num-traits",
"pyo3",
]
As you can see, I have installed a strange version due to rust-numpy. What should I do in this case?
I want to use 0.14 for ndarray-linalg because of the version of ndarray.

How to pass a stm32f3discovery API into a function?

I am trying to create a separate file/module that has functions that can deal with the LEDs or gyro for the stm32f3discovery. I am trying to pass the stm32f3 API that holds all of the registers into a function to then use inside.
When I run this code, I get an error saying "there is no field '###' on type '##'". How can I do this?
main.rs
#![no_std]
#![no_main]
use stm32f3::stm32f303;
mod my_api;
#[entry]
fn main() -> ! {
let periph = stm32f303::Peripherals::take().unwrap();
let gpioe = periph.GPIOE;
let rcc = periph.RCC;
my_api::led::setup_led(&gpioe, &rcc);
loop {
my_api::led::all_led_on(&gpioe);
}
}
my_api.rs
pub mod led {
pub fn setup_led<G, R>(gpio: &G, rcc: &R) {
*rcc.ahbenr.modify(|_, w| w.iopeen().set_bit()); //enables clock
*gpio.moder.modify(|_, w| {
w.moder8().bits(0b01);
w.moder9().bits(0b01);
w.moder10().bits(0b01);
w.moder11().bits(0b01);
w.moder12().bits(0b01);
w.moder13().bits(0b01);
w.moder14().bits(0b01);
w.moder15().bits(0b01)
});
}
pub fn all_led_on<G>(gpio: &G) {
*gpio.odr.modify(|_, w| {
w.odr8().set_bit();
w.odr9().set_bit();
w.odr10().set_bit();
w.odr11().set_bit();
w.odr12().set_bit();
w.odr13().set_bit();
w.odr14().set_bit();
w.odr15().set_bit()
});
}
pub fn all_led_off<G>(gpio: &G) {
*gpio.odr.modify(|_, w| {
w.odr8().clear_bit();
w.odr9().clear_bit();
w.odr10().clear_bit();
w.odr11().clear_bit();
w.odr12().clear_bit();
w.odr13().clear_bit();
w.odr14().clear_bit();
w.odr15().clear_bit()
});
}
}
Error
error[E0609]: no field `odr` on type `&G`
--> src/my_api.rs:30:15
|
29 | pub fn all_led_off <G> (gpio: &G) {
| - type parameter 'G' declared here
30 | *gpio.odr.modify(|_,w| {
| ^^^
It has this error for all of the calls onto any of the registers
Instead of using a generic to try and force our way into passing in a type that you don't know use something like:
let my_name: () = 39.2;
It will give an error that will tell you what the value on the right is and you can use that to work out what data type you can pass into the function. As shown printing variable type in rust

rust - trouble importing module

I have encountered a strange error preventing one of my files from importing a module
This is my src directory
src/
functions.rs
main.rs
unit_test.rs
Here is unit_test.rs
mod functions;
#[cfg(test)] // only compiles on test
// make module f_test
mod f_test{
// mark function as test
#[test]
#[should_panic]
fn test_basic() {
assert_eq!();
panic!("oh no");
}
#[test]
fn test_add(){
assert_eq!(functions::add(1,2), 1 + 2);
}
#[test]
#[should_panic]
fn test_bad_add(){
assert_eq!(functions::add(1,2), 1 + 2);
}
}
When I try to run cargo test I get this
[vinessa#komputilo unitTest]$ cargo test
Compiling unitTest v0.1.0 (/home/vinessa/Dev/Rust/unitTest)
error[E0583]: file not found for module `functions`
--> src/unit_test.rs:1:5
|
1 | mod functions;
| ^^^^^^^^^
|
= help: name the file either unit_test/functions.rs or unit_test/functions/mod.rs inside the directory "src"
Strange thing, if I add "mod functions;" to main.rs, cargo won't complain about that file, only for unit_test.rs
I am lost please help
I think you want to declare mod functions in main.rs:
mod unit_test;
mod functions; // declare this module here
fn main() {
println!("Hello, world!");
}
I think you want this in unit_test.rs:
#[cfg(test)] // only compiles on test
// make module f_test
mod f_test{
use crate::functions; // use module here
// mark function as test
#[test]
#[should_panic]
fn test_basic() {
assert_eq!(1, 1);
panic!("oh no");
}
#[test]
fn test_add(){
assert_eq!(functions::add(1,2), 1 + 2);
}
#[test]
#[should_panic]
fn test_bad_add(){
assert_eq!(functions::add(1,2), 1 + 2);
}
}
Additionally, your #[should_panic] is incorrect as it stands.
Obligatory link: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html

Why Isn't This Module Visible?

I'm coding a hash in Rust for practice. The code looks like this:
pub fn get_fnv1a32(to_hash:&str) -> u32{
const OFFSET_BASIS:u32 = 2_166_136_261;
const PRIME:u32 = 16_777_619;
if !to_hash.is_empty(){
let mut hash = OFFSET_BASIS;
for b in to_hash.bytes(){
hash = hash ^ (b as u32);
hash = hash.wrapping_mul(PRIME);
}
hash
}
else
{
0
}
}
And this is the code I'm trying to use to test this:
mod fnv;
#[cfg(test)]
mod tests {
#[test]
fn get_correct_hash(){
assert_eq!(0x7a78f512, fnv::get_fnv1a32("Hello world!"));
}
#[test]
fn hash_handles_empty_string_correctly(){
assert_eq!(0, fnv::get_fnv1a32(""));
}
}
The test code is in lib.rs and the get_fnv1a32 function is in fnv.rs. They're both in the same directory. But when I try to run cargo test I keep getting these messages:
Compiling hashes v0.1.0 (U:\skunkworks\rust\hashes)
warning: function is never used: `get_fnv1a32`
--> src\fnv.rs:1:8
|
1 | pub fn get_fnv1a32(to_hash:&str) -> u32{
| ^^^^^^^^^^^
|
= note: `#[warn(dead_code)]` on by default
error[E0433]: failed to resolve: use of undeclared type or module `fnv`
--> src\lib.rs:7:32
|
7 | assert_eq!(0x7a78f512, fnv::get_fnv1a32("Hello world!"));
| ^^^ use of undeclared type or module `fnv`
error[E0433]: failed to resolve: use of undeclared type or module `fnv`
--> src\lib.rs:12:23
|
12 | assert_eq!(0, fnv::get_fnv1a32(""));
| ^^^ use of undeclared type or module `fnv`
error: aborting due to 2 previous errors
I can't figure out what I'm doing wrong. I tried changing the mod fnv; line at the top to pub mod fnv; and that gets rid of the dead code warning but it doesn't fix the two errors. What do I need to do to get the get_fnv1a32 function to be visible in the lib.rs file?
Not that I would think it would matter but the version of rustc is rustc 1.41.0 (5e1a79984 2020-01-27)
The test module is separate from the outer module. Add
use super::*;
or an equivalent statement like use crate::fnv inside the tests module to make the fnv module visible.

Iterating over a range of generic type

I have a trait
trait B {
type Index: Sized + Copy;
fn bounds(&self) -> (Self::Index, Self::Index);
}
I want to get all the Indexes within bounds:
fn iterate<T: B>(it: &T) {
let (low, high) = it.bounds();
for i in low..high {}
}
This won't work since there's no constraint that the type T can be "ranged" over, and the compiler says as much:
error[E0277]: the trait bound `<T as B>::Index: std::iter::Step` is not satisfied
--> src/main.rs:8:5
|
8 | for i in low..high {}
| ^^^^^^^^^^^^^^^^^^^^^ the trait `std::iter::Step` is not implemented for `<T as B>::Index`
|
= help: consider adding a `where <T as B>::Index: std::iter::Step` bound
= note: required because of the requirements on the impl of `std::iter::Iterator` for `std::ops::Range<<T as B>::Index>`
I tried adding the Step bound to Index
use std::iter::Step;
trait B {
type Index: Sized + Copy + Step;
fn bounds(&self) -> (Self::Index, Self::Index);
}
but apparently it isn't stable:
error: use of unstable library feature 'step_trait': likely to be replaced by finer-grained traits (see issue #42168)
--> src/main.rs:1:5
|
1 | use std::iter::Step;
| ^^^^^^^^^^^^^^^
error: use of unstable library feature 'step_trait': likely to be replaced by finer-grained traits (see issue #42168)
--> src/main.rs:4:32
|
4 | type Index: Sized + Copy + Step;
| ^^^^
Am I missing something or is it just not possible to do so right now?
If you want to require that a Range<T> can be iterated over, just use that as your trait bound:
trait Bounded {
type Index: Sized + Copy;
fn bounds(&self) -> (Self::Index, Self::Index);
}
fn iterate<T>(it: &T)
where
T: Bounded,
std::ops::Range<T::Index>: IntoIterator,
{
let (low, high) = it.bounds();
for i in low..high {}
}
fn main() {}
To do this kind of thing generically the num crate is helpful.
extern crate num;
use num::{Num, One};
use std::fmt::Debug;
fn iterate<T>(low: T, high: T)
where
T: Num + One + PartialOrd + Copy + Clone + Debug,
{
let one = T::one();
let mut i = low;
loop {
if i > high {
break;
}
println!("{:?}", i);
i = i + one;
}
}
fn main() {
iterate(0i32, 10i32);
iterate(5u8, 7u8);
iterate(0f64, 10f64);
}