The Unfun Cat
The Unfun Cat

Reputation: 32008

Error E0433 - Use of undeclared type or module when accessing a module from a test

As a first project in Rust, I'm trying to create a run length encoding library.

This is my src/lib.rs (initially created by cargo):

#[cfg(test)]

mod rle;
mod tests {

    #[test]

    fn it_works() {
        let rle1 = rle::Rle {
            lengths: vec![1, 4, 2],
            values: vec![1, 2, 1],
        };
    }

}

This is my src/rle.rs:

pub struct Rle {
    lengths: Vec<i32>,
    values: Vec<i32>,
}

Using this layout, I get an error[E0433]: failed to resolve. Use of undeclared type or module 'rle'

I have tried to follow the guidelines in the Rust Docs called Crates and Modules.

What am I doing wrong?

In case the layout was not obvious:

$ ls src
lib.rs rle.rs

Upvotes: 7

Views: 8682

Answers (2)

Matthieu M.
Matthieu M.

Reputation: 300349

You have an error in the use of #[cfg(test)].

Rust has two ways of applying attributes:

  • #[...] applies to the next item
  • #![...] applies to the enclosing item

This means that here, #[cfg(test)] is applying to the next item (mod rle;) which will thus only be compiled in test mode. On the other hand, your tests module will always be compiled.

As a result, when NOT running in test mode, you have:

  • no rle module
  • a tests module referring to a rle module

The fix is simple: move the attribute so it applies to mod tests, not mod rle.


Note:

  • as mentioned by Chris, you ALSO need to use super::rle to refer to the rle module.
  • as mentioned by ljedrz, you ALSO need to declare the fields of Rle public to be able to name them from outside the file (a problem you should not have if the tests are in the same file).

Upvotes: 7

ljedrz
ljedrz

Reputation: 22273

You first need to make Rle fields public to be able to access them:

pub struct Rle {
    pub lengths: Vec<i32>,
    pub values: Vec<i32>,
}

And then, in the lib.rs file you should use it like so:

mod rle; // you probably don't want #[cfg(test)] to apply to rle

#[cfg(test)] // this makes the tests module run only during cargo test
mod tests {
    use super::rle::Rle; // now Rle is applicable in the tests module

    #[test]
    fn it_works() {
        let rle1 = Rle {
            lengths: vec![1, 4, 2],
            values: vec![1, 2, 1],
        };
    }

}

Note that I changed let rle1 = rle::Rle { to let rle1 = Rle {, because I imported super::rle::Rle and not just super::rle.

This compiles without issues.

Upvotes: 5

Related Questions