Skip to content

Add support for #[cfg(test)] attribute #2168

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

rw1nkler
Copy link
Contributor

@rw1nkler rw1nkler commented May 13, 2025

Description

This commit adds a #[cfg(test)] attribute that you can use to mark functions or procs that are only meant for testing. When marked this way, they won't be lowered to IR. The original request in #1524 was just for functions, but I applied the same idea to procs as well.

Implementation details

This feature uses a test_only flag in the Function class to mark functions and procs that are only used for tests. When converting code to IR, functions and procs marked as test-only are skipped, unless the convert_tests option is enabled. This allows test helpers to be included in the IR if needed.

IR conversion now provides clearer error messages. If a test-only function or proc is selected for conversion without the convert_tests option, a dedicated error is shown. Same happens when a test-only function is called from a regular function or proc and IR is being dumped.

In DSLX, the interpreter will fail if a test-only function is called from a regular one. This check is not yet in place for procs, as communication between regular and test-only procs involves more complexity, but I can add it too if needed.

Resolves #1524

@rw1nkler rw1nkler force-pushed the 76622-test-utility-methods branch from 6bee119 to fe6d77c Compare May 16, 2025 16:05
@rw1nkler rw1nkler changed the title Add support for test utility functions Add support for #[cfg(test)] attribute May 16, 2025
@rw1nkler rw1nkler force-pushed the 76622-test-utility-methods branch from fe6d77c to 6b3fc81 Compare May 19, 2025 14:33
@rw1nkler rw1nkler marked this pull request as ready for review May 19, 2025 14:48
@rw1nkler
Copy link
Contributor Author

FYI @richmckeever @dplassgit

@proppy
Copy link
Member

proppy commented May 19, 2025

@rw1nkler can you add DSLX examples w/ tests functions?

@proppy
Copy link
Member

proppy commented May 19, 2025

#[cfg(test)]

This does seems slightly inconsistent w/ our current annotations #[test] and #[test_proc], should we switch everything to #[cfg(something)] or add something like #[test_aux/helper] and #[test_proc_aux/helper].

@allight
Copy link
Collaborator

allight commented May 19, 2025

#[cfg(test)]

This does seems slightly inconsistent w/ our current annotations #[test] and #[test_proc], should we switch everything to #[cfg(something)] or add something like #[test_aux/helper] and #[test_proc_aux/helper].

This is consistent with how rust does things (sort of, #[cfg(whatever)] acts more like a #ifdef and style is to place it on the 'tests' module but its pretty close): rust docs

@proppy
Copy link
Member

proppy commented May 19, 2025

This is consistent with how rust does things (sort of, #[cfg(whatever)] acts more like a #ifdef and style is to place it on the 'tests' module but its pretty close): rust docs

Ah you're right that's close to what Rust does:

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        let result = add(2, 2);
        assert_eq!(result, 4);
    }
}

I guess one difference is that because they have mod they can enable cfg[test) for a whole hierarchy and don't have to annotate everything single helper functions/procs.

Maybe worth logging as a issue if we want something similar as a follow-up.

Copy link
Collaborator

@cdleary cdleary left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, is there a test for what happens when we refer to an entity that's test-only though in a non-test scenario? Seems like it'd be nicer to make a DSLX level error message instead of having a linker-style error at IR conversion/opt time.

@rw1nkler rw1nkler force-pushed the 76622-test-utility-methods branch from 6b3fc81 to e5bb172 Compare May 20, 2025 12:01
@rw1nkler
Copy link
Contributor Author

Looks good, is there a test for what happens when we refer to an entity that's test-only though in a non-test scenario? Seems like it'd be nicer to make a DSLX level error message instead of having a linker-style error at IR conversion/opt time.

There's a test that checks if a test utility function was called from a regular function or proc:
https://github.com/google/xls/pull/2168/files#diff-c24b2f53453f91215eec0d6d76daf6a9e03f9c780d0f9710472388af1fe1ce11R1686

Right now, there are no checks for spawning utility procs inside regular procs.
If we want to catch those cases too, I can work on adding that.

@@ -2208,6 +2208,11 @@ DocRef Formatter::Format(const Function& n) {
arena_.MakeText("\")]"),
arena_.hard_line(),
}));
} else if (n.test_only() && !is_test) {
fn_pieces.push_back(ConcatN(arena_, {
arena_.MakeText("#[cfg(test)]"),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be good to expose an inline constexpr std::string_view from ast_utils.h that is the "cfg(test)" string, so that in real code we don't have to repeat it in different places (it's fine to repeat it in test DSLX).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the constant

@mikex-oss
Copy link
Collaborator

FYI @rw1nkler looks like you'll need to rebase to get this in.

@rw1nkler rw1nkler force-pushed the 76622-test-utility-methods branch from e5bb172 to 71546c3 Compare June 3, 2025 13:13
@rw1nkler rw1nkler requested a review from richmckeever June 3, 2025 14:06
} else if (n.test_only() && !is_test) {
fn_pieces.push_back(
ConcatN(arena_, {
arena_.MakeText("#"),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The proc version inserts the whole attribute at the same time. Is there a benefit either way?

@@ -2376,6 +2376,8 @@ class Function : public AstNode {
disable_format_ = disable_format;
}
bool disable_format() const { return disable_format_; }
void set_test_only(bool test_only) { test_only_ = test_only; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If at all possible this should be done in the constructor instead of in a mutator

Copy link
Contributor Author

@rw1nkler rw1nkler Jun 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to be consistent with other attributes like dslx_format_disable or extern_verilog. If using a constructor is preferred I can change that.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, having the bit in the constructor is preferred. The other mutator methods are only present out of necessity due to quirks in the parser.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[enhancement] Support test utility methods
7 participants