Skip to content
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

Change rustdoc to test code blocks by default #12298

Merged
merged 2 commits into from
Feb 16, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 12 additions & 20 deletions src/doc/rustdoc.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,34 +100,29 @@ rustdoc --test crate.rs

## Defining tests

Rust documentation currently uses the markdown format, and code blocks can refer
to any piece of code-related documentation, which isn't always rust. Because of
this, only code blocks with the language of "rust" will be considered for
testing.
Rust documentation currently uses the markdown format, and rustdoc treats all
code blocks as testable-by-default. In order to not run a test over a block of
code, the `ignore` string can be added to the three-backtick form of markdown
code block.

~~~
```rust
```
// This is a testable code block
```

```
```ignore
// This is not a testable code block
```

// This is not a testable code block (4-space indent)
// This is a testable code block (4-space indent)
~~~

In addition to only testing "rust"-language code blocks, there are additional
specifiers that can be used to dictate how a code block is tested:
In addition to the `ignore` directive, you can specify that the test's execution
should fail with the `should_fail` directive.

~~~
```rust,ignore
// This code block is ignored by rustdoc, but is passed through to the test
// harness
```

```rust,should_fail
// This code block is expected to generate a failure
```should_fail
// This code block is expected to generate a failure when run
```
~~~

Expand All @@ -143,7 +138,7 @@ that one can still write things like `#[deriving(Eq)]`).
# the doc-generating tool. In order to display them anyway in this particular
# case, the character following the leading '#' is not a usual space like in
# these first five lines but a non breakable one.
#
#
# // showing 'fib' in this documentation would just be tedious and detracts from
# // what's actualy being documented.
# fn fib(n: int) { n + 2 }
Expand All @@ -169,9 +164,6 @@ rustdoc --test lib.rs --test-args 'foo'

// See what's possible when running tests
rustdoc --test lib.rs --test-args '--help'

// Run all ignored tests
rustdoc --test lib.rs --test-args '--ignored'
~~~

When testing a library, code examples will often show how functions are used,
Expand Down
2 changes: 1 addition & 1 deletion src/libextra/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ An object is a series of string keys mapping to values, in `"key": value` format
Arrays are enclosed in square brackets ([ ... ]) and objects in curly brackets ({ ... }).
A simple JSON document encoding a person, his/her age, address and phone numbers could look like:
```
```ignore
{
"FirstName": "John",
"LastName": "Doe",
Expand Down
2 changes: 1 addition & 1 deletion src/libextra/stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ pub fn write_5_number_summary(w: &mut io::Writer,
/// As an example, the summary with 5-number-summary `(min=15, q1=17, med=20, q3=24, max=31)` might
/// display as:
///
/// ~~~~
/// ~~~~ignore
/// 10 | [--****#******----------] | 40
/// ~~~~

Expand Down
2 changes: 1 addition & 1 deletion src/libglob/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ pub struct Paths {
///
/// The above code will print:
///
/// ```
/// ```ignore
/// /media/pictures/kittens.jpg
/// /media/pictures/puppies.jpg
/// ```
Expand Down
16 changes: 9 additions & 7 deletions src/librustdoc/html/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,21 +172,23 @@ pub fn render(w: &mut io::Writer, s: &str) -> fmt::Result {
pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) {
extern fn block(_ob: *buf, text: *buf, lang: *buf, opaque: *libc::c_void) {
unsafe {
if text.is_null() || lang.is_null() { return }
let (test, shouldfail, ignore) =
if text.is_null() { return }
let (shouldfail, ignore) = if lang.is_null() {
(false, false)
} else {
vec::raw::buf_as_slice((*lang).data,
(*lang).size as uint, |lang| {
let s = str::from_utf8(lang).unwrap();
(s.contains("rust"), s.contains("should_fail"),
s.contains("ignore"))
});
if !test { return }
(s.contains("should_fail"), s.contains("ignore"))
})
};
if ignore { return }
vec::raw::buf_as_slice((*text).data, (*text).size as uint, |text| {
let tests: &mut ::test::Collector = intrinsics::transmute(opaque);
let text = str::from_utf8(text).unwrap();
let mut lines = text.lines().map(|l| stripped_filtered_line(l).unwrap_or(l));
let text = lines.to_owned_vec().connect("\n");
tests.add_test(text, ignore, shouldfail);
tests.add_test(text, shouldfail);
})
}
}
Expand Down
17 changes: 9 additions & 8 deletions src/librustdoc/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub fn run(input: &str, matches: &getopts::Matches) -> int {
0
}

fn runtest(test: &str, cratename: &str, libs: HashSet<Path>) {
fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, should_fail: bool) {
let test = maketest(test, cratename);
let parsesess = parse::new_parse_sess();
let input = driver::StrInput(test);
Expand Down Expand Up @@ -130,9 +130,10 @@ fn runtest(test: &str, cratename: &str, libs: HashSet<Path>) {
match out {
Err(e) => fail!("couldn't run the test: {}", e),
Ok(out) => {
if !out.status.success() {
fail!("test executable failed:\n{}",
str::from_utf8(out.error));
if should_fail && out.status.success() {
fail!("test executable succeeded when it should have failed");
} else if !should_fail && !out.status.success() {
fail!("test executable failed:\n{}", str::from_utf8(out.error));
}
}
}
Expand Down Expand Up @@ -169,7 +170,7 @@ pub struct Collector {
}

impl Collector {
pub fn add_test(&mut self, test: &str, ignore: bool, should_fail: bool) {
pub fn add_test(&mut self, test: &str, should_fail: bool) {
let test = test.to_owned();
let name = format!("{}_{}", self.names.connect("::"), self.cnt);
self.cnt += 1;
Expand All @@ -180,11 +181,11 @@ impl Collector {
self.tests.push(test::TestDescAndFn {
desc: test::TestDesc {
name: test::DynTestName(name),
ignore: ignore,
should_fail: should_fail,
ignore: false,
should_fail: false, // compiler failures are test failures
},
testfn: test::DynTestFn(proc() {
runtest(test, cratename, libs);
runtest(test, cratename, libs, should_fail);
}),
});
}
Expand Down
2 changes: 1 addition & 1 deletion src/libstd/comm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
//! let (port, chan) = Chan::new();
//! spawn(proc() {
//! chan.send(10);
//! })
//! });
//! assert_eq!(port.recv(), 10);
//!
//! // Create a shared channel which can be sent along from many tasks
Expand Down
12 changes: 6 additions & 6 deletions src/libstd/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ function, but the `format!` macro is a syntax extension which allows it to
leverage named parameters. Named parameters are listed at the end of the
argument list and have the syntax:
```
```ignore
identifier '=' expression
```
Expand All @@ -107,7 +107,7 @@ and if all references to one argument do not provide a type, then the format `?`
is used (the type's rust-representation is printed). For example, this is an
invalid format string:
```
```ignore
{0:d} {0:s}
```
Expand All @@ -123,7 +123,7 @@ must have the type `uint`. Although a `uint` can be printed with `{:u}`, it is
illegal to reference an argument as such. For example, this is another invalid
format string:
```
```ignore
{:.*s} {0:u}
```
Expand Down Expand Up @@ -334,7 +334,7 @@ This example is the equivalent of `{0:s}` essentially.
The select method is a switch over a `&str` parameter, and the parameter *must*
be of the type `&str`. An example of the syntax is:
```
```ignore
{0, select, male{...} female{...} other{...}}
```
Expand All @@ -353,7 +353,7 @@ The plural method is a switch statement over a `uint` parameter, and the
parameter *must* be a `uint`. A plural method in its full glory can be specified
as:
```
```ignore
{0, plural, offset=1 =1{...} two{...} many{...} other{...}}
```
Expand Down Expand Up @@ -381,7 +381,7 @@ should not be too alien. Arguments are formatted with python-like syntax,
meaning that arguments are surrounded by `{}` instead of the C-like `%`. The
actual grammar for the formatting syntax is:
```
```ignore
format_string := <text> [ format <text> ] *
format := '{' [ argument ] [ ':' format_spec ] [ ',' function_spec ] '}'
argument := integer | identifier
Expand Down
17 changes: 13 additions & 4 deletions src/libstd/io/comm_adapters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,16 @@ use vec::{bytes, CloneableVector, MutableVector, ImmutableVector};
/// # Example
///
/// ```
/// let reader = PortReader::new(port);
/// use std::io::PortReader;
///
/// let (port, chan) = Chan::new();
/// # drop(chan);
/// let mut reader = PortReader::new(port);
///
/// let mut buf = ~[0u8, ..100];
/// match reader.read(buf) {
/// Some(nread) => println!("Read {} bytes", nread),
/// None => println!("At the end of the stream!")
/// Ok(nread) => println!("Read {} bytes", nread),
/// Err(e) => println!("read error: {}", e),
/// }
/// ```
pub struct PortReader {
Expand Down Expand Up @@ -83,7 +87,12 @@ impl Reader for PortReader {
/// # Example
///
/// ```
/// let writer = ChanWriter::new(chan);
/// # #[allow(unused_must_use)];
/// use std::io::ChanWriter;
///
/// let (port, chan) = Chan::new();
/// # drop(port);
/// let mut writer = ChanWriter::new(chan);
/// writer.write("hello, world".as_bytes());
/// ```
pub struct ChanWriter {
Expand Down
13 changes: 8 additions & 5 deletions src/libstd/io/net/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,18 @@ impl UnixListener {
/// # Example
///
/// ```
/// # fn main() {}
/// # fn foo() {
/// # #[allow(unused_must_use)];
/// use std::io::net::unix::UnixListener;
/// use std::io::Listener;
/// use std::io::{Listener, Acceptor};
///
/// let server = Path::new("path/to/my/socket");
/// let mut stream = UnixListener::bind(&server);
/// for client in stream.incoming() {
/// let mut client = client;
/// let server = Path::new("/path/to/my/socket");
/// let stream = UnixListener::bind(&server);
/// for mut client in stream.listen().incoming() {
/// client.write([1, 2, 3, 4]);
/// }
/// # }
/// ```
pub fn bind<P: ToCStr>(path: &P) -> IoResult<UnixListener> {
LocalIo::maybe_raise(|io| {
Expand Down
9 changes: 7 additions & 2 deletions src/libstd/kinds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ pub mod marker {
/// Given a struct `S` that includes a type parameter `T`
/// but does not actually *reference* that type parameter:
///
/// ```
/// ```ignore
/// use std::cast;
///
/// struct S<T> { x: *() }
/// fn get<T>(s: &S<T>) -> T {
/// unsafe {
Expand Down Expand Up @@ -109,6 +111,8 @@ pub mod marker {
/// but does not actually *reference* that type parameter:
///
/// ```
/// use std::cast;
///
/// struct S<T> { x: *() }
/// fn get<T>(s: &S<T>, v: T) {
/// unsafe {
Expand Down Expand Up @@ -147,7 +151,8 @@ pub mod marker {
/// "interior" mutability:
///
/// ```
/// struct Cell<T> { priv value: T }
/// pub struct Cell<T> { priv value: T }
/// # fn main() {}
/// ```
///
/// The type system would infer that `value` is only read here and
Expand Down
4 changes: 2 additions & 2 deletions src/libstd/logging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ disabled except for `error!` (a log level of 1). Logging is controlled via the
`RUST_LOG` environment variable. The value of this environment variable is a
comma-separated list of logging directives. A logging directive is of the form:
```
```ignore
path::to::module=log_level
```
Expand All @@ -65,7 +65,7 @@ all modules is set to this value.
Some examples of valid values of `RUST_LOG` are:
```
```ignore
hello // turns on all logging for the 'hello' module
info // turns on all info logging
hello=debug // turns on debug logging for 'hello'
Expand Down
Loading