-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
add a --chapter option to mdbook test. #1741
Conversation
…ic to the name of the rustdoc tool.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! This seems like it could be useful.
I'd like to suggest that perhaps the -c
flag could take either a chapter name or file path. In most cases, I know the file path but not the chapter name. File paths also support command-line completion, whereas chapter names need to be typed exactly (and deal with shell quoting and such).
Can you also update the documentation at https://github.com/rust-lang/mdBook/blob/master/guide/src/cli/test.md?
src/theme/index.hbs
Outdated
if (theme && theme.startsWith('"') && theme.endsWith('"')) { | ||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1)); | ||
} | ||
|
||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) { | ||
if (sidebar && sidebar.startsWith('"') && sidebar.endsWith('"')) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These changes seem unrelated to the PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
they were null reference bugs I ran into while testing this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer unrelated changes to not be included.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a bit different as I couldn't get the tests to pass without this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which tests aren't passing? What kind of errors are you seeing? I don't believe there are any javascript tests, so it is not clear to me how this could have any impact on anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, trying to repro it I can't find it any more and I see there's a try{ } catch (e) { }
around this whole thing, so it's possible I caught the exception in the debugger and mistook it for a bug when it was expecting the try/catch block to catch it and continue. So I reverted these changes.
Done. |
@clovett Just checking in if you are still interested in this. It looks like there are some test failures. |
I am still interested in this PR, but I'm kinda stumped by the test failures. Clearly the test output changes, and I tried to fix that, but I'm not sure why it didn't work. |
The PR changes the output to use |
Ah, thanks for the hint - I think I got it now. |
@ehuss - yay the tests are passing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this will need some tests.
Also, can you add some kind of error message if the --chapter
value doesn't match anything?
src/book/mod.rs
Outdated
/// Run `rustdoc` tests on the book, linking against the provided libraries. | ||
pub fn test(&mut self, library_paths: Vec<&str>) -> Result<()> { | ||
/// Run `rustdoc` tests on the book, linking against the provided libraries | ||
/// and optionally testing only a signal named chapter while skipping the others. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// and optionally testing only a signal named chapter while skipping the others. | |
/// and optionally testing only a single named chapter while skipping the others. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
src/book/mod.rs
Outdated
pub fn test(&mut self, library_paths: Vec<&str>) -> Result<()> { | ||
/// Run `rustdoc` tests on the book, linking against the provided libraries | ||
/// and optionally testing only a signal named chapter while skipping the others. | ||
pub fn test(&mut self, library_paths: Vec<&str>, chapter: Option<&str>) -> Result<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately we can't change the API as that would be a semver breaking change.
I think you will need to add a new method, and have the old test
call it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done, I added "test_chapter", but instead of duplicating the code I just make test call test_chapter and I added a couple new tests for "test_chapter".
src/book/mod.rs
Outdated
if chapter.is_some() | ||
&& ch.name != chapter.unwrap() | ||
&& chapter_path.to_str().unwrap() != chapter.unwrap() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to avoid using unwrap here. Perhaps more like this:
if chapter.is_some() | |
&& ch.name != chapter.unwrap() | |
&& chapter_path.to_str().unwrap() != chapter.unwrap() | |
if let Some(chapter) = chapter { | |
if ch.name != chapter && chapter_path.to_str() != Some(chapter) { |
However, this logic seems wrong. It seems to require that the --chapter
value passed in equals both the chapter name and its filename. I would expect it to match one or the other. Perhaps something more like?
!(ch.name == chapter || chapter_path.to_str() == Some(chapter))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it works, notice this is the inverse of the test !(ch.name == chapter || chapter_path == chapter)
src/theme/index.hbs
Outdated
if (theme && theme.startsWith('"') && theme.endsWith('"')) { | ||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1)); | ||
} | ||
|
||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) { | ||
if (sidebar && sidebar.startsWith('"') && sidebar.endsWith('"')) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer unrelated changes to not be included.
test: add unit tests for test_chapter
I added: --chapterThe |
src/book/mod.rs
Outdated
if chapter_name != "" && ch.name != chapter_name && cp != chapter_name { | ||
info!("Skipping chapter '{}'...", ch.name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This all seemed to have reverted back to using an empty string as a sentinel instead of an Option. Is there any particular reason for that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry this might be my Rust ignorance, I couldn't figure out how to compare chapter : Option<&str>
and ch.name: String
. Rust complains: "can't compare std::string::String
with std::option::Option<&str>
". So, moving them both to &str solved the problem, but I guess I could instead convert ch.name
to Option<&str>
using:
let cn: Option<&str> = Some(&ch.name);
I pushed this change to see if this is what you prefer...
self.test_chapter(library_paths, None) | ||
} | ||
|
||
/// Run `rustdoc` tests on a specific chapter of the book, linking against the provided libraries. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a little unclear to me on what happens if chapter
is None. Can it include a little more explanation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure thing, I added clarifying comments // test_chapter with chapter:None will run all tests.
and on the test_chapter
function itself the doc comment: /// If
chapteris
None, all tests will be run.
@ehuss I think I resolved all the excellent issues you raised. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Just some code style suggestions.
src/book/mod.rs
Outdated
let cp = chapter_path.to_str(); | ||
let cn: Option<&str> = Some(&ch.name); | ||
|
||
if chapter.is_some() && cn != chapter && cp != chapter { | ||
info!("Skipping chapter '{}'...", ch.name); | ||
continue; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of using local variables like this, I still think it would be clearer to use something like the suggestion I posted before. The local variables create an indirection where you then have to refer to other parts of the code to figure out what they mean. Using the values directly I think makes it a little clearer as to what is being checked.
Also, after testing this out a bit, I feel like the output is overwhelmed with the "skipping chapter" text. I'm thinking it might be better to reduce that to a debug
message to reduce the noise.
Perhaps something like this:
let cp = chapter_path.to_str(); | |
let cn: Option<&str> = Some(&ch.name); | |
if chapter.is_some() && cn != chapter && cp != chapter { | |
info!("Skipping chapter '{}'...", ch.name); | |
continue; | |
}; | |
if let Some(chapter) = chapter { | |
if ch.name != chapter && chapter_path.to_str() != Some(chapter) { | |
debug!("Skipping chapter '{}'...", ch.name); | |
continue; | |
} | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The skipping chapter
prompts are how you find the chapter names so you can write mdbook test -c ?
for example then you find the chapter name you want to test and run the specific command. But I could make it so that it looks for the specific string "?" so it only prints in that case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I pushed the if-check looking for command line arg "?" instead and I added that to the help text to make it discoverable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, and I see now how you are using if let Some
to remove the need for local variables, so I pushed that fix too.
src/book/mod.rs
Outdated
if chapter.is_some() && !chapter_found { | ||
bail!(format!("Chapter not found: {:?}", chapter)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This produces some strange output. Generally it is recommended to not use debug displays for user output. Also, the bail!
macro can take formatted strings directly, there is no need to use format!
. I think it might be better to extract the name through a pattern and use a display impl. Something like this:
if chapter.is_some() && !chapter_found { | |
bail!(format!("Chapter not found: {:?}", chapter)); | |
} | |
if let Some(chapter) = chapter { | |
if !chapter_found { | |
bail!("Chapter not found: {}", chapter); | |
} | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Much better thanks, I merged your fix. I was just copying the use of bail
from a few lines earlier: bail!("One or more tests failed");
, so unless there is a better error formatter available, I'll leave the bail as you have written it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
Sometimes when working on large books it is handy to be able to run mdbook on a single chapter of a book. For example: