auto merge of #12298 : alexcrichton/rust/rustdoc-testing, r=sfackler

It's too easy to forget the `rust` tag to test something.

Closes #11698
This commit is contained in:
bors 2014-02-15 16:36:27 -08:00
commit 0c62d9d83d
21 changed files with 131 additions and 100 deletions

View File

@ -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
```
~~~
@ -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 }
@ -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,

View File

@ -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",

View File

@ -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
/// ~~~~

View File

@ -67,7 +67,7 @@ pub struct Paths {
///
/// The above code will print:
///
/// ```
/// ```ignore
/// /media/pictures/kittens.jpg
/// /media/pictures/puppies.jpg
/// ```

View File

@ -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);
})
}
}

View File

@ -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);
@ -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));
}
}
}
@ -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;
@ -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);
}),
});
}

View File

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

View File

@ -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
```
@ -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}
```
@ -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}
```
@ -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{...}}
```
@ -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{...}}
```
@ -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

View File

@ -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 {
@ -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 {

View File

@ -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| {

View File

@ -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 {
@ -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 {
@ -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

View File

@ -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
```
@ -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'

View File

@ -119,6 +119,8 @@ impl Rem<$T,$T> for $T {
/// Returns the integer remainder after division, satisfying:
///
/// ```
/// # let n = 1;
/// # let d = 2;
/// assert!((n / d) * d + (n % d) == n)
/// ```
///
@ -194,15 +196,15 @@ impl Integer for $T {
/// # Examples
///
/// ```
/// assert!(( 8).div_floor( 3) == 2);
/// assert!(( 8).div_floor(-3) == -3);
/// assert!((-8).div_floor( 3) == -3);
/// assert!((-8).div_floor(-3) == 2);
/// assert!(( 8i).div_floor(& 3) == 2);
/// assert!(( 8i).div_floor(&-3) == -3);
/// assert!((-8i).div_floor(& 3) == -3);
/// assert!((-8i).div_floor(&-3) == 2);
///
/// assert!(( 1).div_floor( 2) == 0);
/// assert!(( 1).div_floor(-2) == -1);
/// assert!((-1).div_floor( 2) == -1);
/// assert!((-1).div_floor(-2) == 0);
/// assert!(( 1i).div_floor(& 2) == 0);
/// assert!(( 1i).div_floor(&-2) == -1);
/// assert!((-1i).div_floor(& 2) == -1);
/// assert!((-1i).div_floor(&-2) == 0);
/// ```
///
#[inline]
@ -220,21 +222,22 @@ impl Integer for $T {
/// Integer modulo, satisfying:
///
/// ```
/// assert!(n.div_floor(d) * d + n.mod_floor(d) == n)
/// # let n = 1i; let d = 1i;
/// assert!(n.div_floor(&d) * d + n.mod_floor(&d) == n)
/// ```
///
/// # Examples
///
/// ```
/// assert!(( 8).mod_floor( 3) == 2);
/// assert!(( 8).mod_floor(-3) == -1);
/// assert!((-8).mod_floor( 3) == 1);
/// assert!((-8).mod_floor(-3) == -2);
/// assert!(( 8i).mod_floor(& 3) == 2);
/// assert!(( 8i).mod_floor(&-3) == -1);
/// assert!((-8i).mod_floor(& 3) == 1);
/// assert!((-8i).mod_floor(&-3) == -2);
///
/// assert!(( 1).mod_floor( 2) == 1);
/// assert!(( 1).mod_floor(-2) == -1);
/// assert!((-1).mod_floor( 2) == 1);
/// assert!((-1).mod_floor(-2) == -1);
/// assert!(( 1i).mod_floor(& 2) == 1);
/// assert!(( 1i).mod_floor(&-2) == -1);
/// assert!((-1i).mod_floor(& 2) == 1);
/// assert!((-1i).mod_floor(&-2) == -1);
/// ```
///
#[inline]

View File

@ -45,7 +45,7 @@ pub trait Zero: Add<Self, Self> {
///
/// # Laws
///
/// ~~~
/// ~~~ignore
/// a + 0 = a ∀ a ∈ Self
/// 0 + a = a ∀ a ∈ Self
/// ~~~
@ -71,7 +71,7 @@ pub trait One: Mul<Self, Self> {
///
/// # Laws
///
/// ~~~
/// ~~~ignore
/// a * 1 = a ∀ a ∈ Self
/// 1 * a = a ∀ a ∈ Self
/// ~~~
@ -964,6 +964,8 @@ impl_from_primitive!(f64, n.to_f64())
/// # Example
///
/// ```
/// use std::num;
///
/// let twenty: f32 = num::cast(0x14).unwrap();
/// assert_eq!(twenty, 20f32);
/// ```

View File

@ -20,7 +20,7 @@ use super::{IndependentSample, Sample, Exp};
///
/// The density function of this distribution is
///
/// ```
/// ```ignore
/// f(x) = x^(k - 1) * exp(-x / θ) / (Γ(k) * θ^k)
/// ```
///

View File

@ -2011,7 +2011,7 @@ pub trait StrSlice<'a> {
///
/// ## Output
///
/// ```
/// ```ignore
/// 0: 中
/// 3: 华
/// 6: V

View File

@ -46,7 +46,7 @@
*
* ```
* spawn(proc() {
* log(error, "Hello, World!");
* println!("Hello, World!");
* })
* ```
*/

View File

@ -19,13 +19,16 @@ also be used. See that function for more details.
# Example
```
```
use std::unstable::finally::Finally;
# fn always_run_this() {}
(|| {
...
// ...
}).finally(|| {
always_run_this();
})
```
```
*/
use ops::Drop;
@ -69,13 +72,16 @@ impl<T> Finally<T> for fn() -> T {
* # Example
*
* ```
* use std::unstable::finally::try_finally;
*
* struct State<'a> { buffer: &'a mut [u8], len: uint }
* # let mut buf = [];
* let mut state = State { buffer: buf, len: 0 };
* try_finally(
* &mut state, (),
* |state, ()| {
* // use state.buffer, state.len
* }
* },
* |state| {
* // use state.buffer, state.len to cleanup
* })

View File

@ -955,7 +955,7 @@ pub trait ImmutableVector<'a, T> {
*
* Equivalent to:
*
* ```
* ```ignore
* if self.len() == 0 { return None }
* let head = &self[0];
* *self = self.slice_from(1);
@ -973,7 +973,7 @@ pub trait ImmutableVector<'a, T> {
*
* Equivalent to:
*
* ```
* ```ignore
* if self.len() == 0 { return None; }
* let tail = &self[self.len() - 1];
* *self = self.slice_to(self.len() - 1);
@ -2075,7 +2075,7 @@ pub trait MutableVector<'a, T> {
*
* Equivalent to:
*
* ```
* ```ignore
* if self.len() == 0 { return None; }
* let head = &mut self[0];
* *self = self.mut_slice_from(1);
@ -2093,7 +2093,7 @@ pub trait MutableVector<'a, T> {
*
* Equivalent to:
*
* ```
* ```ignore
* if self.len() == 0 { return None; }
* let tail = &mut self[self.len() - 1];
* *self = self.mut_slice_to(self.len() - 1);

View File

@ -17,8 +17,10 @@ Decodable)].
For example, a type like:
```ignore
#[deriving(Encodable, Decodable)]
struct Node {id: uint}
```
would generate two implementations like:
@ -43,11 +45,14 @@ impl<D:Decoder> Decodable for node_id {
Other interesting scenarios are whe the item has type parameters or
references other non-built-in types. A type definition like:
```ignore
#[deriving(Encodable, Decodable)]
struct spanned<T> {node: T, span: Span}
```
would yield functions like:
```ignore
impl<
S: Encoder,
T: Encodable<S>
@ -73,6 +78,7 @@ would yield functions like:
})
}
}
```
*/
use ast::{MetaItem, Item, Expr, MutMutable};

View File

@ -59,7 +59,7 @@ associated with. It is only not `None` when the associated field has
an identifier in the source code. For example, the `x`s in the
following snippet
~~~
~~~ignore
struct A { x : int }
struct B(int);
@ -83,7 +83,7 @@ variants, it is represented as a count of 0.
The following simplified `Eq` is used for in-code examples:
~~~
~~~ignore
trait Eq {
fn eq(&self, other: &Self);
}
@ -101,7 +101,7 @@ above `Eq`, `A`, `B` and `C`.
When generating the `expr` for the `A` impl, the `SubstructureFields` is
~~~
~~~ignore
Struct(~[FieldInfo {
span: <span of x>
name: Some(<ident of x>),
@ -112,7 +112,7 @@ Struct(~[FieldInfo {
For the `B` impl, called with `B(a)` and `B(b)`,
~~~
~~~ignore
Struct(~[FieldInfo {
span: <span of `int`>,
name: None,
@ -126,7 +126,7 @@ Struct(~[FieldInfo {
When generating the `expr` for a call with `self == C0(a)` and `other
== C0(b)`, the SubstructureFields is
~~~
~~~ignore
EnumMatching(0, <ast::Variant for C0>,
~[FieldInfo {
span: <span of int>
@ -138,7 +138,7 @@ EnumMatching(0, <ast::Variant for C0>,
For `C1 {x}` and `C1 {x}`,
~~~
~~~ignore
EnumMatching(1, <ast::Variant for C1>,
~[FieldInfo {
span: <span of x>
@ -150,7 +150,7 @@ EnumMatching(1, <ast::Variant for C1>,
For `C0(a)` and `C1 {x}` ,
~~~
~~~ignore
EnumNonMatching(~[(0, <ast::Variant for B0>,
~[(<span of int>, None, <expr for &a>)]),
(1, <ast::Variant for B1>,
@ -164,7 +164,7 @@ EnumNonMatching(~[(0, <ast::Variant for B0>,
A static method on the above would result in,
~~~~
~~~~ignore
StaticStruct(<ast::StructDef of A>, Named(~[(<ident of x>, <span of x>)]))
StaticStruct(<ast::StructDef of B>, Unnamed(~[<span of x>]))
@ -346,7 +346,9 @@ impl<'a> TraitDef<'a> {
* Given that we are deriving a trait `Tr` for a type `T<'a, ...,
* 'z, A, ..., Z>`, creates an impl like:
*
* ```ignore
* impl<'a, ..., 'z, A:Tr B1 B2, ..., Z: Tr B1 B2> Tr for T<A, ..., Z> { ... }
* ```
*
* where B1, B2, ... are the bounds given by `bounds_paths`.'
*
@ -620,7 +622,7 @@ impl<'a> MethodDef<'a> {
}
/**
~~~
~~~ignore
#[deriving(Eq)]
struct A { x: int, y: int }
@ -719,7 +721,7 @@ impl<'a> MethodDef<'a> {
}
/**
~~~
~~~ignore
#[deriving(Eq)]
enum A {
A1
@ -762,7 +764,7 @@ impl<'a> MethodDef<'a> {
/**
Creates the nested matches for an enum definition recursively, i.e.
~~~
~~~ignore
match self {
Variant1 => match other { Variant1 => matching, Variant2 => nonmatching, ... },
Variant2 => match other { Variant1 => nonmatching, Variant2 => matching, ... },
@ -1166,7 +1168,7 @@ pub fn cs_fold(use_foldl: bool,
Call the method that is being derived on all the fields, and then
process the collected results. i.e.
~~~
~~~ignore
f(cx, span, ~[self_1.method(__arg_1_1, __arg_2_1),
self_2.method(__arg_1_2, __arg_2_2)])
~~~