Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compilation failed when test inside of submodule #5

Open
Mingun opened this issue Mar 12, 2022 · 1 comment
Open

Compilation failed when test inside of submodule #5

Mingun opened this issue Mar 12, 2022 · 1 comment
Labels
enhancement New feature or request

Comments

@Mingun
Copy link

Mingun commented Mar 12, 2022

I trying to replace macro_rules-based tests in my PR with generic-tests one. Everyseen works fine when I define test function in the test module (which is annotated with #[generic_tests::define]), but when I move my test into inner test::submod module, the compilation fails with impossible to find a trait.

I want to define my tests tree, including tests in the inner modules, like I do that for the ordinary tests framework, and then copy that tree for every set of template parameters. Is this possible?

The code that demonstrates problem:
use std::io::BufRead;

//---------------------------------------------------------------
// quick-xml like code
trait BufferedInput<'b, B> {
  fn read(&mut self, buf: B) -> &'b [u8];
}

/// Generic reader, copies data from reader into intermediate buffer
impl<'b, R: BufRead> BufferedInput<'b, &'b mut Vec<u8>> for R {
  /// Read & Copy data from `self` into `buf`,
  /// return data that borrow from `buf`
  fn read(&mut self, buf: &'b mut Vec<u8>) -> &'b [u8] {
    &buf[..]
  }
}

/// Borrowed reader, zero-copy
impl<'i> BufferedInput<'i, ()> for &'i [u8] {
  /// Directly borrow data from `self`, do not copy,
  /// return data that borrow from `self`
  fn read(&mut self, _buf: ()) -> &'i [u8] {
    self
  }
}

//---------------------------------------------------------------
// My tests
#[cfg(test)]
#[generic_tests::define]
mod test {
  /// Helper trait for `generic_tests` crate
  trait Storage<'b>: Default {
    type Buffer;

    /// Returns buffer for `BufferedInput::read`
    fn buffer(&'b mut self) -> Self::Buffer;
  }
  impl<'b> Storage<'b> for () {
    type Buffer = ();
    fn buffer(&'b mut self) {}
  }
  impl<'b> Storage<'b> for Vec<u8> {
    type Buffer = &'b mut Vec<u8>;
    fn buffer(&'b mut self) -> Self::Buffer {
      self
    }
  }

  #[test]
  fn test<S>()
    where for<'b> S: Storage<'b>,
          for<'b> &'b [u8]: crate::BufferedInput<'b, <S as Storage<'b>>::Buffer>,
  {
    let mut storage = S::default();

    storage.buffer();
  }

  mod submod {
    use super::Storage;
    use crate::BufferedInput;

    // This is failed to compile
    #[test]
    fn test<S>()
      where for<'b> S: Storage<'b>,
            for<'b> &'b [u8]: BufferedInput<'b, <S as Storage<'b>>::Buffer>,
    {
      let mut storage = S::default();

      storage.buffer();
    }
  }

  /// Tests for reader that generates events that borrow from the provided buffer
  #[instantiate_tests(<Vec<u8>>)]
  mod buffered {}

  /// Tests for reader that generates events that borrow from the input
  #[instantiate_tests(<()>)]
  mod borrowed {}
}
`cargo expand --tests` output
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use std::io::BufRead;
trait BufferedInput<'b, B> {
    fn read(&mut self, buf: B) -> &'b [u8];
}
/// Generic reader, copies data from reader into intermediate buffer
impl<'b, R: BufRead> BufferedInput<'b, &'b mut Vec<u8>> for R {
    /// Read & Copy data from `self` into `buf`,
    /// return data that borrow from `buf`
    fn read(&mut self, buf: &'b mut Vec<u8>) -> &'b [u8] {
        &buf[..]
    }
}
/// Borrowed reader, zero-copy
impl<'i> BufferedInput<'i, ()> for &'i [u8] {
    /// Directly borrow data from `self`, do not copy,
    /// return data that borrow from `self`
    fn read(&mut self, _buf: ()) -> &'i [u8] {
        self
    }
}
#[cfg(test)]
mod test {
    /// Helper trait for `generic_tests` crate
    trait Storage<'b>: Default {
        type Buffer;
        /// Returns buffer for `BufferedInput::read`
        fn buffer(&'b mut self) -> Self::Buffer;
    }
    impl<'b> Storage<'b> for () {
        type Buffer = ();
        fn buffer(&'b mut self) {}
    }
    impl<'b> Storage<'b> for Vec<u8> {
        type Buffer = &'b mut Vec<u8>;
        fn buffer(&'b mut self) -> Self::Buffer {
            self
        }
    }
    fn test<S>()
    where
        for<'b> S: Storage<'b>,
        for<'b> &'b [u8]: crate::BufferedInput<'b, <S as Storage<'b>>::Buffer>,
    {
        let mut storage = S::default();
        storage.buffer();
    }
    mod submod {
        use super::Storage;
        use crate::BufferedInput;
        extern crate test;
        #[cfg(test)]
        #[rustc_test_marker]
        pub const test: test::TestDescAndFn = test::TestDescAndFn {
            desc: test::TestDesc {
                name: test::StaticTestName("test::submod::test"),
                ignore: false,
                allow_fail: false,
                compile_fail: false,
                no_run: false,
                should_panic: test::ShouldPanic::No,
                test_type: test::TestType::UnitTest,
            },
            testfn: test::StaticTestFn(|| test::assert_test_result(test())),
        };
        fn test<S>()
        where
            for<'b> S: Storage<'b>,
            for<'b> &'b [u8]: BufferedInput<'b, <S as Storage<'b>>::Buffer>,
        {
            let mut storage = S::default();
            storage.buffer();
        }
    }
    /// Tests for reader that generates events that borrow from the provided buffer
    mod buffered {
        #[allow(unused_imports)]
        use super::*;
        extern crate test;
        #[cfg(test)]
        #[rustc_test_marker]
        pub const test: test::TestDescAndFn = test::TestDescAndFn {
            desc: test::TestDesc {
                name: test::StaticTestName("test::buffered::test"),
                ignore: false,
                allow_fail: false,
                compile_fail: false,
                no_run: false,
                should_panic: test::ShouldPanic::No,
                test_type: test::TestType::UnitTest,
            },
            testfn: test::StaticTestFn(|| test::assert_test_result(test())),
        };
        fn test() {
            mod shim {
                pub(super) mod _generic_tests_call_sig {
                    #[allow(unused_imports)]
                    use super::super::super::*;
                    pub(in super::super) struct Args {}
                    pub(super) type Ret = ();
                }
                #[allow(unused_imports)]
                use super::super::*;
                pub(super) unsafe fn shim(
                    _args: _generic_tests_call_sig::Args,
                ) -> _generic_tests_call_sig::Ret {
                    super::super::test::<Vec<u8>>()
                }
            }
            let args = shim::_generic_tests_call_sig::Args {};
            unsafe { shim::shim(args) }
        }
    }
    /// Tests for reader that generates events that borrow from the input
    mod borrowed {
        #[allow(unused_imports)]
        use super::*;
        extern crate test;
        #[cfg(test)]
        #[rustc_test_marker]
        pub const test: test::TestDescAndFn = test::TestDescAndFn {
            desc: test::TestDesc {
                name: test::StaticTestName("test::borrowed::test"),
                ignore: false,
                allow_fail: false,
                compile_fail: false,
                no_run: false,
                should_panic: test::ShouldPanic::No,
                test_type: test::TestType::UnitTest,
            },
            testfn: test::StaticTestFn(|| test::assert_test_result(test())),
        };
        fn test() {
            mod shim {
                pub(super) mod _generic_tests_call_sig {
                    #[allow(unused_imports)]
                    use super::super::super::*;
                    pub(in super::super) struct Args {}
                    pub(super) type Ret = ();
                }
                #[allow(unused_imports)]
                use super::super::*;
                pub(super) unsafe fn shim(
                    _args: _generic_tests_call_sig::Args,
                ) -> _generic_tests_call_sig::Ret {
                    super::super::test::<()>()
                }
            }
            let args = shim::_generic_tests_call_sig::Args {};
            unsafe { shim::shim(args) }
        }
    }
}
#[rustc_main]
pub fn main() -> () {
    extern crate test;
    test::test_main_static(&[&test, &test, &test])
}
@mzabaluev mzabaluev added the enhancement New feature or request label Mar 16, 2022
@mzabaluev
Copy link
Owner

mzabaluev commented Mar 16, 2022

Thank you for the feature suggestion. The macro does not look into submodules as currently implemented.

It should be possible to transform [test] functions defined in submodules, by instantiating into the replicated submodule tree under the instantiation module, and emit a glob import from the original module of a test into its instantiation submodules in order for all the support code and imported names from the original module to be visible to the instantiation. But it's a substantial amount of work I'm not ready to commit to at the moment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants