[][src]Attribute Macro datatest_derive::files

#[files]

Proc macro handling #[files(...)] syntax. This attribute defines rules for deriving test function arguments from file paths. There are two types of rules:

  1. Pattern rule, <arg_name> in "<regexp>"
  2. Template rule, <arg_name> = "regexp"

There must be only one pattern rule defined in the attribute. It defines a regular expression to run against all files found in the test directory.

Template rule defines rules how the name of the matched file is transformed to get related files.

This macro is responsible for generating a test descriptor (datatest::FilesTestDesc) based on the #[files(..)] attribute attached to the test function.

There are four fields specific for these type of tests we need to fill in:

  1. root, which is the root directory to scan for the tests (relative to the root of the crate with tests)
  2. params, slice of strings, each string is either a template or pattern assigned to the function argument
  3. pattern, an index of the "pattern" argument (since exactly one is required, it is just an index in the params array).
  4. testfn, test function trampoline.

Few words about trampoline function. Each test function could have a unique signature, depending on which types it needs and which files it requires as an input. However, our test framework should be capable of running these test functions via some standardized interface. This interface is fn(&[PathBuf]). Each slice element matches test function argument (so length of this slice is the same as amount of arguments test function has).

In addition to that, this trampoline function is also responsible for mapping &PathBuf references into argument types. There is some trait magic involved to make code work for both cases when function takes argument as a slice (&str, &[u8) and for cases when function takes argument as owned (String, Vec<u8>).

The difficulty here is that for owned arguments we can create value and just pass it down to the function. However, for arguments taking slices, we need to store value somewhere on the stack and pass a reference.

I could have made this proc macro to handle these cases explicitly and generate a different code, but I decided to not add a complexity of type analysis to the proc macro and use traits instead. See datatest::TakeArg and datatest::DeriveArg to see how this mechanism works.