remacs / remacs

Rust :heart: Emacs
GNU General Public License v3.0
4.59k stars 308 forks source link

Writing tests with remacs-sys dependencies #299

Open rlupton20 opened 7 years ago

rlupton20 commented 7 years ago

Hi, I jut discovered this project yesterday, and first would like to say this is a cool idea, even if just a chance to dig into the emacs internals. So I decided to get stuck in, first by writing a few tests in lisp.rs, just to get oriented. This issue is mostly to track my progress, gather input, and help future wayfarers.

I wrote this little test

#[test]
fn test_float_promotion_on_exceeding_max_int() {
    let x = LispObject::int_or_float_from_fixnum(MOST_POSITIVE_FIXNUM+1);
    assert!(x.as_fixnum() == None);
}

but on running cargo test I get a linker error

  = note: /home/richard/remacs/rust_src/target/debug/deps/remacs-c65f4237c5aa0389.0.o: In function `remacs::lisp::{{impl}}::from_float':
          /home/richard/remacs/rust_src/src/lisp.rs:78: undefined reference to `make_float'
          collect2: error: ld returned 1 exit status

(make check also fails with this test in place, cargo build works - to be expected since presumably on build we don't need to do any linking).

Tracing this through, I found make_float is declared as an C function in remacs-sys, and defined in src/alloc.c. I could work all the way down, and port all of the functions across to rust, but perhaps in general there is some merit to being able to pin these functions with tests before doing the port. This would also make it more viable for people to contribute tests to the project as a way to get started.

Searching around, I couldn't find an obvious way to make cargo test link against the C code - is it known if there is a way to do this? Presumably we want cargo build to ignore linking.

Wilfred commented 7 years ago

Great question! Yes, we don't have a solution yet: the few tests we have don't link against remacs-sys because of exactly this problem.

We've mostly been porting elisp functions, so you can test them by starting an Remacs instance and just calling the functions in ielm. This works, but of course it's not well-suited for other bits of code.

We would really benefit from a better solution, but we don't have one yet.

DavidDeSimone commented 7 years ago

(Warning Shameless Plug):

Once I finish up my work on, https://github.com/Wilfred/remacs/pull/286, I plan on finishing the next milestone for my mocking library, mock_derive. The next milestone will allow us to mock the results of extern "C" calls for tests. While not a perfect solution in my mind, it will allow us to write tests and piece meal bring over functions without having to figure out linking our C code to the Rust tests.

rlupton20 commented 7 years ago

Cool! That sounds like a good middle ground for the moment. Plausibly this is the kind of enhancement that might have some traction in the cargo community (namely being able to provide extra linking parameters for test vs. build). C ports must be a common use case for Rust. Probably wouldn't be too hard to implement either. If I find some time...

DavidDeSimone commented 7 years ago

As promised, I have opened a PR using the aforementioned crate. https://github.com/Wilfred/remacs/pull/304

shaleh commented 6 years ago

In related news, I added support for elisp tests targeting files in rust_src/src. These are functional rather than unit tests but they are better than nothing.