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!!