Doctests that require a non-default feature

Hi!

I've found this topic which seems exactly what I need: include certain doctests only on specific features setup.

But, when doing that on my human-repr crate:

/// Human representation count trait, supporting all Rust primitive number types.
pub trait HumanCount: sealed::Sealed + Sized {
    /// Generate beautiful human-readable counts supporting automatic prefixes and custom units.
    #[cfg_attr(
        not(any(feature = "1024", feature = "iec", feature = "space")),
        doc = r#"

    ```
    use human_repr::HumanCount;
    assert_eq!("4.2Mcoins", 4221432u32.human_count("coins"));
    ```
    "#
    )]
    fn human_count<T>(self, unit: T) -> HumanCountData<T>;
}

All I receive is this very weird error, it seems the Rust compiler doesn't expect text inside that doc attribute:

---- src/lib.rs - HumanCount::human_count (line 41) stdout ----
error: unknown start of token: `
 --> src/lib.rs:42:1
  |
4 | ```
  | ^^^
  |
  = note: character appears 2 more times
help: Unicode character '`' (Grave Accent) looks like ''' (Single Quote), but it is not
  |
4 | '''
  |

error: unknown start of token: `
 --> src/lib.rs:45:1
  |
7 | ```
  | ^^^
  |
  = note: character appears 2 more times
help: Unicode character '`' (Grave Accent) looks like ''' (Single Quote), but it is not
  |
7 | '''
  |

error: aborting due to 2 previous errors

Couldn't compile the test.

Another curious detail, the doc is simply ignored if I remove that blank line, the Rust compiler doesn't find it anymore. But I do want that blank line anyway, so it skips one line between the explanation and the example.

Please, what is happening? How can I fix it?

Thanks!

Doc comments are parsed as Markdown. Markdown has two ways to make a code block: ```, or four spaces of indentation. Your string literal has four spaces of indentation in the relevant lines, so the ``` are being taken as part of the code block.

To fix this, you can do one of these:

  1. Remove the indentation.
  2. Don't use raw string literals, and then put an explicit newline and line continuation at the end of each line: \n\. This has the effect of discarding the whitespace at the beginning of the next line. However, this will also discard any wanted indentation.
  3. Use indoc!, which will strip a uniform amount of whitespace from all lines in the literal.
1 Like

Awesome @kpreid! Thank you very much!! :+1:

Ohh @kpreid, please would you happen to know why the Rust compiler simply ignores it with the explicit newline option:

/// Human representation count trait, supporting all Rust primitive number types.
pub trait HumanCount: sealed::Sealed + Sized {
    /// Generate beautiful human-readable counts supporting automatic prefixes and custom units.
    #[cfg_attr(
        not(any(feature = "1024", feature = "iec", feature = "space")),
        doc = r#"\n\
    ```\
    use human_repr::HumanCount;\
    assert_eq!("4.2Mcoins", 4221432u32.human_count("coins"));\
    ```\
    "#
    )]
    fn human_count<T>(self, unit: T) -> HumanCountData<T>;
}

Option 1 did work, but is ugly as hell.
I'm trying the second one before including another dev-dependency, but with the above, it simply finds 12 tests instead of 13...

You probably need \n\ for every trailing \ in your doc string (untested).

1 Like

Thanks @quinedot, you're right, but unfortunately, it still doesn't get found by Rust...

pub trait HumanCount: sealed::Sealed + Sized {
    /// Generate beautiful human-readable counts supporting automatic prefixes and custom units.
    #[cfg_attr(
        not(any(feature = "1024", feature = "iec", feature = "space")),
        doc = r#"\n\n\
    ```\n\
    use human_repr::HumanCount;\n\
    assert_eq!("4.2Mcoins", 4221432u32.human_count("coins"));\n\
    ```\n\
    "#
    )]
    fn human_count<T>(self, unit: T) -> HumanCountData<T>;
}

It is simply ignored, Rust finds 12 tests instead of the current 13...

Oh, you are using a raw string literal r#, so the backslashes are taken literally. You will have to use a non-raw literal, or one of the other two options I suggested.

1 Like

Ahh, I see... :man_facepalming:
I needed it raw because of the several double quotes inside it...

Anyway, I'd prefer Rust returned an error to me, instead of silently ignoring it.
Thanks again!!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.