Skip to content

Commit efd7d01

Browse files
committed
Update the documentation of Description to reflect recent changes.
The previous documentation was written when `Description` was just a helper. This new documentation is geared to its new, more central role. Also adjusts the trait bounds on some trait implementations for `Description` and `List` to allow iterators of string slices to be collected into a `Description`. Also fixes two examples in the `Matcher` documentation.
1 parent 7b58a69 commit efd7d01

File tree

4 files changed

+98
-47
lines changed

4 files changed

+98
-47
lines changed

googletest/src/description.rs

Lines changed: 86 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -19,33 +19,72 @@ use std::{
1919

2020
use crate::internal::description_renderer::{List, INDENTATION_SIZE};
2121

22-
/// Helper structure to build better output of
23-
/// [`Matcher::describe`][crate::matcher::Matcher::describe] and
24-
/// [`Matcher::explain_match`][crate::matcher::Matcher::explain_match]. This
25-
/// is especially useful with composed matchers and matchers over containers.
22+
/// A structured description, either of a (composed) matcher or of an
23+
/// assertion failure.
2624
///
27-
/// It provides simple operations to lazily format lists of strings.
25+
/// One can compose blocks of text into a `Description`. Each one appears on a
26+
/// new line. For example:
2827
///
29-
/// Usage:
30-
/// ```ignore
31-
/// let iter: impl Iterator<String> = ...
32-
/// format!("{}", iter.collect::<Description>().indent().bullet_list())
28+
/// ```
29+
/// # use googletest::prelude::*;
30+
/// # use googletest::description::Description;
31+
/// let description = Description::new()
32+
/// .text("A block")
33+
/// .text("Another block");
34+
/// verify_that!(description, displays_as(eq("A block\nAnother block")))
35+
/// # .unwrap();
3336
/// ```
3437
///
35-
/// To construct a [`Description`], use `Iterator<Item=String>::collect()`.
36-
/// Each element of the collected iterator will be separated by a
37-
/// newline when displayed. The elements may be multi-line, but they will
38-
/// nevertheless be indented consistently.
38+
/// One can embed nested descriptions into a `Description`. The resulting
39+
/// nested description is then rendered with an additional level of
40+
/// indentation. For example:
3941
///
40-
/// Note that a newline will only be added between each element, but not
41-
/// after the last element. This makes it simpler to keep
42-
/// [`Matcher::describe`][crate::matcher::Matcher::describe]
43-
/// and [`Matcher::explain_match`][crate::matcher::Matcher::explain_match]
44-
/// consistent with simpler [`Matchers`][crate::matcher::Matcher].
42+
/// ```
43+
/// # use googletest::prelude::*;
44+
/// # use googletest::description::Description;
45+
/// let inner_description = Description::new()
46+
/// .text("A block")
47+
/// .text("Another block");
48+
/// let outer_description = Description::new()
49+
/// .text("Header")
50+
/// .nested(inner_description);
51+
/// verify_that!(outer_description, displays_as(eq("\
52+
/// Header
53+
/// A block
54+
/// Another block")))
55+
/// # .unwrap();
56+
/// ```
4557
///
46-
/// They can also be indented, enumerated and or
47-
/// bullet listed if [`Description::indent`], [`Description::enumerate`], or
48-
/// respectively [`Description::bullet_list`] has been called.
58+
/// One can also enumerate or bullet list the elements of a `Description`:
59+
///
60+
/// ```
61+
/// # use googletest::prelude::*;
62+
/// # use googletest::description::Description;
63+
/// let description = Description::new()
64+
/// .text("First item")
65+
/// .text("Second item")
66+
/// .bullet_list();
67+
/// verify_that!(description, displays_as(eq("\
68+
/// * First item
69+
/// * Second item")))
70+
/// # .unwrap();
71+
/// ```
72+
///
73+
/// One can construct a `Description` from a [`String`] or a string slice, an
74+
/// iterator thereof, or from an iterator over other `Description`s:
75+
///
76+
/// ```
77+
/// # use googletest::description::Description;
78+
/// let single_element_description: Description =
79+
/// "A single block description".into();
80+
/// let two_element_description: Description =
81+
/// ["First item", "Second item"].into_iter().collect();
82+
/// let two_element_description_from_strings: Description =
83+
/// ["First item".to_string(), "Second item".to_string()].into_iter().collect();
84+
/// ```
85+
///
86+
/// No newline is added after the last element during rendering. This makes it
87+
/// easier to support single-line matcher descriptions and match explanations.
4988
#[derive(Debug, Default)]
5089
pub struct Description {
5190
elements: List,
@@ -101,40 +140,48 @@ impl Description {
101140
Self { initial_indentation: INDENTATION_SIZE, ..self }
102141
}
103142

104-
/// Bullet lists the elements of [`self`].
105-
///
106-
/// This operation will be performed lazily when [`self`] is displayed.
143+
/// Instructs this instance to render its elements as a bullet list.
107144
///
108-
/// Note that this will only bullet list each element, not each line
109-
/// in each element.
145+
/// Each element (from either [`Description::text`] or
146+
/// [`Description::nested`]) is rendered as a bullet point. If an element
147+
/// contains multiple lines, the following lines are aligned with the first
148+
/// one in the block.
110149
///
111150
/// For instance:
112151
///
113152
/// ```
114153
/// # use googletest::prelude::*;
115154
/// # use googletest::description::Description;
116-
/// let description = std::iter::once("A B C\nD E F".to_string()).collect::<Description>();
117-
/// verify_that!(description.bullet_list(), displays_as(eq("* A B C\n D E F")))
155+
/// let description = Description::new()
156+
/// .text("First line\nsecond line")
157+
/// .bullet_list();
158+
/// verify_that!(description, displays_as(eq("\
159+
/// * First line
160+
/// second line")))
118161
/// # .unwrap();
119162
/// ```
120163
pub fn bullet_list(self) -> Self {
121164
Self { elements: self.elements.bullet_list(), ..self }
122165
}
123166

124-
/// Enumerates the elements of [`self`].
125-
///
126-
/// This operation will be performed lazily when [`self`] is displayed.
167+
/// Instructs this instance to render its elements as an enumerated list.
127168
///
128-
/// Note that this will only enumerate each element, not each line in
129-
/// each element.
169+
/// Each element (from either [`Description::text`] or
170+
/// [`Description::nested`]) is rendered with its zero-based index. If an
171+
/// element contains multiple lines, the following lines are aligned with
172+
/// the first one in the block.
130173
///
131174
/// For instance:
132175
///
133176
/// ```
134177
/// # use googletest::prelude::*;
135178
/// # use googletest::description::Description;
136-
/// let description = std::iter::once("A B C\nD E F".to_string()).collect::<Description>();
137-
/// verify_that!(description.enumerate(), displays_as(eq("0. A B C\n D E F")))
179+
/// let description = Description::new()
180+
/// .text("First line\nsecond line")
181+
/// .enumerate();
182+
/// verify_that!(description, displays_as(eq("\
183+
/// 0. First line
184+
/// second line")))
138185
/// # .unwrap();
139186
/// ```
140187
pub fn enumerate(self) -> Self {
@@ -158,12 +205,12 @@ impl Display for Description {
158205
}
159206
}
160207

161-
impl FromIterator<String> for Description {
208+
impl<ElementT: Into<Cow<'static, str>>> FromIterator<ElementT> for Description {
162209
fn from_iter<T>(iter: T) -> Self
163210
where
164-
T: IntoIterator<Item = String>,
211+
T: IntoIterator<Item = ElementT>,
165212
{
166-
Self { elements: iter.into_iter().collect(), ..Default::default() }
213+
Self { elements: iter.into_iter().map(ElementT::into).collect(), ..Default::default() }
167214
}
168215
}
169216

@@ -176,7 +223,7 @@ impl FromIterator<Description> for Description {
176223
}
177224
}
178225

179-
impl<T: Into<String>> From<T> for Description {
226+
impl<T: Into<Cow<'static, str>>> From<T> for Description {
180227
fn from(value: T) -> Self {
181228
let mut elements = List::default();
182229
elements.push_literal(value.into().into());

googletest/src/internal/description_renderer.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,12 +226,12 @@ impl FromIterator<Block> for List {
226226
}
227227
}
228228

229-
impl FromIterator<String> for List {
229+
impl<ElementT: Into<Cow<'static, str>>> FromIterator<ElementT> for List {
230230
fn from_iter<T>(iter: T) -> Self
231231
where
232-
T: IntoIterator<Item = String>,
232+
T: IntoIterator<Item = ElementT>,
233233
{
234-
Self(iter.into_iter().map(|b| b.into()).collect(), Decoration::None)
234+
Self(iter.into_iter().map(|b| b.into().into()).collect(), Decoration::None)
235235
}
236236
}
237237

googletest/src/matcher.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,10 @@ pub trait Matcher {
6161
/// fn describe(&self, matcher_result: MatcherResult) -> Description {
6262
/// match matcher_result {
6363
/// MatcherResult::Matches => {
64-
/// format!("has a value which {}", self.inner.describe(MatcherResult::Matches))
65-
/// // Inner matcher invocation: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
64+
/// Description::new()
65+
/// .text("has a value which")
66+
/// .nested(self.inner.describe(MatcherResult::Matches))
67+
/// // Inner matcher: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6668
/// }
6769
/// MatcherResult::DoesNotMatch => {...} // Similar to the above
6870
/// }
@@ -126,7 +128,9 @@ pub trait Matcher {
126128
///
127129
/// ```ignore
128130
/// fn explain_match(&self, actual: &Self::ActualT) -> Description {
129-
/// format!("which points to a value {}", self.expected.explain_match(actual.deref()))
131+
/// Description::new()
132+
/// .text("which points to a value")
133+
/// .nested(self.expected.explain_match(actual.deref()))
130134
/// }
131135
/// ```
132136
fn explain_match(&self, actual: &Self::ActualT) -> Description {

googletest/src/matchers/predicate_matcher.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,13 @@ pub trait PredicateDescription {
100100

101101
impl PredicateDescription for &str {
102102
fn to_description(&self) -> Description {
103-
(*self).into()
103+
self.to_string().into()
104104
}
105105
}
106106

107107
impl PredicateDescription for String {
108108
fn to_description(&self) -> Description {
109-
self.into()
109+
self.to_string().into()
110110
}
111111
}
112112

0 commit comments

Comments
 (0)