Skip to content

Commit 9dbfe43

Browse files
authored
Highlight regex capture groups in writer::Basic (#136, #42)
1 parent d953f1c commit 9dbfe43

26 files changed

+365
-230
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@ All user visible changes to `cucumber` crate will be documented in this file. Th
2727
### Added
2828

2929
- Ability to run `Scenario`s concurrently. ([#128])
30+
- Highlighting of regex capture groups in terminal output with __bold__ style. ([#136])
3031

3132
[#128]: /../../pull/128
33+
[#136]: /../../pull/136
3234
[#137]: /../../pull/137
3335

3436

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ name = "readme"
8888
harness = false # allows Cucumber to print output instead of libtest
8989
```
9090

91-
[![asciicast](https://asciinema.org/a/YP24WIM1PGr2I9znFYKfmbkyo.svg)](https://asciinema.org/a/YP24WIM1PGr2I9znFYKfmbkyo)
91+
[![asciicast](https://asciinema.org/a/6wN3uv8p98SgVznPUh9h50bFo.svg)](https://asciinema.org/a/6wN3uv8p98SgVznPUh9h50bFo)
9292

9393
For more examples check out the Book ([current][1] | [edge][2]).
9494

book/src/Features.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Feature: Animal feature
3030
Then the cat is not hungry
3131
```
3232

33-
<script id="asciicast-9wOF9rEgGUgWN9e49TWiS5Nh3" src="https://asciinema.org/a/9wOF9rEgGUgWN9e49TWiS5Nh3.js" async data-autoplay="true" data-rows="18"></script>
33+
<script id="asciicast-c8XFsr52VB8tuIJfIaofWAfyh" src="https://asciinema.org/a/c8XFsr52VB8tuIJfIaofWAfyh.js" async data-autoplay="true" data-rows="18"></script>
3434

3535

3636

@@ -63,7 +63,7 @@ Feature: Animal feature
6363
Then the cat is not hungry
6464
```
6565

66-
<script id="asciicast-Q8OmAVWU116ZzxYg6VjBDxjlt" src="https://asciinema.org/a/Q8OmAVWU116ZzxYg6VjBDxjlt.js" async data-autoplay="true" data-rows="18"></script>
66+
<script id="asciicast-ZQyfL8gVHD932rskDDESqlsD9" src="https://asciinema.org/a/ZQyfL8gVHD932rskDDESqlsD9.js" async data-autoplay="true" data-rows="18"></script>
6767

6868
`Background` `Step`s indicated by `>` sign in the output by default.
6969

@@ -168,7 +168,7 @@ async fn cat_is_fed(world: &mut AnimalWorld) {
168168
# }
169169
```
170170

171-
<script id="asciicast-15ZcRGFBUXubvcle34ZOLiLtO" src="https://asciinema.org/a/15ZcRGFBUXubvcle34ZOLiLtO.js" async data-autoplay="true" data-rows="18"></script>
171+
<script id="asciicast-o1s4mSMYkkVBy4WAsG8lhYtT8" src="https://asciinema.org/a/o1s4mSMYkkVBy4WAsG8lhYtT8.js" async data-autoplay="true" data-rows="18"></script>
172172

173173

174174
### Combining `regex` and `FromStr`
@@ -273,7 +273,7 @@ async fn cat_is_fed(world: &mut AnimalWorld) {
273273
# }
274274
```
275275

276-
<script id="asciicast-joMErjGUVegtXPJgL8fc5x6pt" src="https://asciinema.org/a/joMErjGUVegtXPJgL8fc5x6pt.js" async data-autoplay="true" data-rows="18"></script>
276+
<script id="asciicast-GeKTIuSZ61Q9Nzv5X4TyrNVVp" src="https://asciinema.org/a/GeKTIuSZ61Q9Nzv5X4TyrNVVp.js" async data-autoplay="true" data-rows="18"></script>
277277

278278

279279

@@ -297,7 +297,7 @@ Egenskap: Animal feature
297297
Så the cat is not hungry
298298
```
299299

300-
<script id="asciicast-sDt8aoo9ZVPZRgiTuy8pSNro2" src="https://asciinema.org/a/sDt8aoo9ZVPZRgiTuy8pSNro2.js" async data-autoplay="true" data-rows="18"></script>
300+
<script id="asciicast-DFtCqnpcnXpKbGxtxfedkW0Ga" src="https://asciinema.org/a/DFtCqnpcnXpKbGxtxfedkW0Ga.js" async data-autoplay="true" data-rows="18"></script>
301301

302302
In case most of your `.feature` files aren't written in English and you want to avoid endless `# language:` comments, use [`Cucumber::language()`](https://docs.rs/cucumber/*/cucumber/struct.Cucumber.html#method.language) method to override the default language.
303303

book/src/Getting_Started.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ fn cat_is_fed(world: &mut AnimalWorld) {
216216

217217
If you run the test now, you'll see that all steps are accounted for and the test succeeds:
218218

219-
<script id="asciicast-HaEZXiqUn0U1T8c5TaiMGX50i" src="https://asciinema.org/a/HaEZXiqUn0U1T8c5TaiMGX50i.js" async data-autoplay="true" data-rows="16"></script>
219+
<script id="asciicast-fHuIXkWrIk1AOFFqF0MYmY0m0" src="https://asciinema.org/a/fHuIXkWrIk1AOFFqF0MYmY0m0.js" async data-autoplay="true" data-rows="16"></script>
220220

221221
If you want to be assured that your validation is indeed happening, you can change the assertion for the cat being hungry from `true` to `false` temporarily:
222222
```rust,should_panic
@@ -274,7 +274,7 @@ fn cat_is_fed(world: &mut AnimalWorld) {
274274

275275
And you should see the test failing:
276276

277-
<script id="asciicast-KFNrNihA5ib9G7O22jwTSw0Lg" src="https://asciinema.org/a/KFNrNihA5ib9G7O22jwTSw0Lg.js" async data-autoplay="true" data-rows="24"></script>
277+
<script id="asciicast-XTikmqirO7mAFZ97MNfKvnD5p" src="https://asciinema.org/a/XTikmqirO7mAFZ97MNfKvnD5p.js" async data-autoplay="true" data-rows="24"></script>
278278

279279
What if we also wanted to validate that even if the cat was never hungry to begin with, it wouldn't end up hungry after it was fed? We can add another scenario that looks quite similar:
280280
```gherkin
@@ -354,7 +354,9 @@ We surround regex with `^..$` to ensure the __exact__ match. This is much more u
354354

355355
[Cucumber] will reuse these steps:
356356

357-
<script id="asciicast-RAteqk9p0zkvWrslK6kiOU5lc" src="https://asciinema.org/a/RAteqk9p0zkvWrslK6kiOU5lc.js" async data-autoplay="true" data-rows="18"></script>
357+
<script id="asciicast-ao6LdWsrtdsgg8tOi9cQgPfyz" src="https://asciinema.org/a/ao6LdWsrtdsgg8tOi9cQgPfyz.js" async data-autoplay="true" data-rows="18"></script>
358+
359+
Captured groups are __bold__ to indicate which part of step could be dynamically changed.
358360

359361
A contrived example, but this demonstrates that steps can be reused as long as they are sufficiently precise in both their description and implementation. If, for example, the wording for our `Then` step was `The cat is no longer hungry`, it'd imply something about the expected initial state, when that is not the purpose of a `Then` step, but rather of the `Given` step.
360362

@@ -506,7 +508,7 @@ async fn main() {
506508
}
507509
```
508510

509-
<script id="asciicast-vufDjDlrdm5TtH20WVpIGpEz6" src="https://asciinema.org/a/vufDjDlrdm5TtH20WVpIGpEz6.js" async data-autoplay="true" data-rows="18"></script>
511+
<script id="asciicast-tz9ApYZgsET9k8jjIa9HpnQ8p" src="https://asciinema.org/a/tz9ApYZgsET9k8jjIa9HpnQ8p.js" async data-autoplay="true" data-rows="18"></script>
510512

511513
Hm, it looks like the executor waited only for the first `Feature` 🤔, what's going on?
512514

@@ -530,7 +532,7 @@ Feature: Animal feature
530532
Then the cat is not hungry
531533
```
532534

533-
<script id="asciicast-KztYots1Jm6WijCmxZM1GZT1K" src="https://asciinema.org/a/KztYots1Jm6WijCmxZM1GZT1K.js" async data-autoplay="true" data-rows="18"></script>
535+
<script id="asciicast-MDXpZf8vcOTssmlU4rgSSfR0E" src="https://asciinema.org/a/MDXpZf8vcOTssmlU4rgSSfR0E.js" async data-autoplay="true" data-rows="18"></script>
534536

535537

536538

src/cucumber.rs

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@ where
143143
///
144144
/// Output with a regular [`Cucumber::run()`]:
145145
/// <script
146-
/// id="asciicast-hMyH3IYbHRFXT1yf84tXDNl2r"
147-
/// src="https://asciinema.org/a/hMyH3IYbHRFXT1yf84tXDNl2r.js"
146+
/// id="asciicast-0d92qlT8Mbc4WXyvRbHJmjsqN"
147+
/// src="https://asciinema.org/a/0d92qlT8Mbc4WXyvRbHJmjsqN.js"
148148
/// async data-autoplay="true" data-rows="17">
149149
/// </script>
150150
///
@@ -178,8 +178,8 @@ where
178178
/// # futures::executor::block_on(fut);
179179
/// ```
180180
/// <script
181-
/// id="asciicast-UsaG9kMnn40nW8y4vcmXOE2tT"
182-
/// src="https://asciinema.org/a/UsaG9kMnn40nW8y4vcmXOE2tT.js"
181+
/// id="asciicast-IHLxMEgku9BtBVkR4k2DtOjMd"
182+
/// src="https://asciinema.org/a/IHLxMEgku9BtBVkR4k2DtOjMd.js"
183183
/// async data-autoplay="true" data-rows="21">
184184
/// </script>
185185
///
@@ -223,8 +223,8 @@ where
223223
///
224224
/// Output with a regular [`Cucumber::run()`]:
225225
/// <script
226-
/// id="asciicast-hMyH3IYbHRFXT1yf84tXDNl2r"
227-
/// src="https://asciinema.org/a/hMyH3IYbHRFXT1yf84tXDNl2r.js"
226+
/// id="asciicast-0d92qlT8Mbc4WXyvRbHJmjsqN"
227+
/// src="https://asciinema.org/a/0d92qlT8Mbc4WXyvRbHJmjsqN.js"
228228
/// async data-autoplay="true" data-rows="17">
229229
/// </script>
230230
///
@@ -234,7 +234,6 @@ where
234234
/// # use std::convert::Infallible;
235235
/// #
236236
/// # use async_trait::async_trait;
237-
/// # use futures::FutureExt as _;
238237
/// # use cucumber::WorldInit;
239238
/// #
240239
/// # #[derive(Debug, WorldInit)]
@@ -272,8 +271,8 @@ where
272271
/// Then the dog is not hungry
273272
/// ```
274273
/// <script
275-
/// id="asciicast-UsaG9kMnn40nW8y4vcmXOE2tT"
276-
/// src="https://asciinema.org/a/UsaG9kMnn40nW8y4vcmXOE2tT.js"
274+
/// id="asciicast-IHLxMEgku9BtBVkR4k2DtOjMd"
275+
/// src="https://asciinema.org/a/IHLxMEgku9BtBVkR4k2DtOjMd.js"
277276
/// async data-autoplay="true" data-rows="21">
278277
/// </script>
279278
///
@@ -323,8 +322,8 @@ where
323322
///
324323
/// Output with a regular [`Cucumber::run()`]:
325324
/// <script
326-
/// id="asciicast-hMyH3IYbHRFXT1yf84tXDNl2r"
327-
/// src="https://asciinema.org/a/hMyH3IYbHRFXT1yf84tXDNl2r.js"
325+
/// id="asciicast-0d92qlT8Mbc4WXyvRbHJmjsqN"
326+
/// src="https://asciinema.org/a/0d92qlT8Mbc4WXyvRbHJmjsqN.js"
328327
/// async data-autoplay="true" data-rows="17">
329328
/// </script>
330329
///
@@ -358,8 +357,8 @@ where
358357
/// # futures::executor::block_on(fut);
359358
/// ```
360359
/// <script
361-
/// id="asciicast-BD1mPjYGELD6oWNKW8lTlyvDR"
362-
/// src="https://asciinema.org/a/BD1mPjYGELD6oWNKW8lTlyvDR.js"
360+
/// id="asciicast-ox14HynkBIw8atpfhyfvKrsO3"
361+
/// src="https://asciinema.org/a/ox14HynkBIw8atpfhyfvKrsO3.js"
363362
/// async data-autoplay="true" data-rows="19">
364363
/// </script>
365364
///
@@ -410,8 +409,8 @@ where
410409
/// # futures::executor::block_on(fut);
411410
/// ```
412411
/// <script
413-
/// id="asciicast-mDDqxWHzUaK19P0L2R2g4XRp2"
414-
/// src="https://asciinema.org/a/mDDqxWHzUaK19P0L2R2g4XRp2.js"
412+
/// id="asciicast-UcipuopO6IFEsIDty6vaJlCH9"
413+
/// src="https://asciinema.org/a/UcipuopO6IFEsIDty6vaJlCH9.js"
415414
/// async data-autoplay="true" data-rows="21">
416415
/// </script>
417416
///
@@ -446,8 +445,8 @@ where
446445
/// # futures::executor::block_on(fut);
447446
/// ```
448447
/// <script
449-
/// id="asciicast-qKp8Hevrb6732mMUT7VduvxJc"
450-
/// src="https://asciinema.org/a/qKp8Hevrb6732mMUT7VduvxJc.js"
448+
/// id="asciicast-ofOljvyEMb41OTLhE081QKv68"
449+
/// src="https://asciinema.org/a/ofOljvyEMb41OTLhE081QKv68.js"
451450
/// async data-autoplay="true" data-rows="24">
452451
/// </script>
453452
///
@@ -506,8 +505,8 @@ where
506505
/// # futures::executor::block_on(fut);
507506
/// ```
508507
/// <script
509-
/// id="asciicast-mDDqxWHzUaK19P0L2R2g4XRp2"
510-
/// src="https://asciinema.org/a/mDDqxWHzUaK19P0L2R2g4XRp2.js"
508+
/// id="asciicast-UcipuopO6IFEsIDty6vaJlCH9"
509+
/// src="https://asciinema.org/a/UcipuopO6IFEsIDty6vaJlCH9.js"
511510
/// async data-autoplay="true" data-rows="21">
512511
/// </script>
513512
///
@@ -564,8 +563,8 @@ where
564563
/// # futures::executor::block_on(fut);
565564
/// ```
566565
/// <script
567-
/// id="asciicast-qKp8Hevrb6732mMUT7VduvxJc"
568-
/// src="https://asciinema.org/a/qKp8Hevrb6732mMUT7VduvxJc.js"
566+
/// id="asciicast-ofOljvyEMb41OTLhE081QKv68"
567+
/// src="https://asciinema.org/a/ofOljvyEMb41OTLhE081QKv68.js"
569568
/// async data-autoplay="true" data-rows="24">
570569
/// </script>
571570
///
@@ -666,8 +665,8 @@ where
666665
/// Then the dog is not hungry
667666
/// ```
668667
/// <script
669-
/// id="asciicast-WbP3PIQR5M7Iznd7uLnjg2ytr"
670-
/// src="https://asciinema.org/a/WbP3PIQR5M7Iznd7uLnjg2ytr.js"
668+
/// id="asciicast-0KvTxnfaMRjsvsIKsalS611Ta"
669+
/// src="https://asciinema.org/a/0KvTxnfaMRjsvsIKsalS611Ta.js"
671670
/// async data-autoplay="true" data-rows="14">
672671
/// </script>
673672
///
@@ -1008,8 +1007,8 @@ where
10081007
/// Then the dog is not hungry
10091008
/// ```
10101009
/// <script
1011-
/// id="asciicast-WbP3PIQR5M7Iznd7uLnjg2ytr"
1012-
/// src="https://asciinema.org/a/WbP3PIQR5M7Iznd7uLnjg2ytr.js"
1010+
/// id="asciicast-0KvTxnfaMRjsvsIKsalS611Ta"
1011+
/// src="https://asciinema.org/a/0KvTxnfaMRjsvsIKsalS611Ta.js"
10131012
/// async data-autoplay="true" data-rows="14">
10141013
/// </script>
10151014
///

src/event.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -201,12 +201,12 @@ pub enum Step<World> {
201201
/// [`Step`] passed.
202202
///
203203
/// [`Step`]: gherkin::Step
204-
Passed,
204+
Passed(regex::CaptureLocations),
205205

206206
/// [`Step`] failed.
207207
///
208208
/// [`Step`]: gherkin::Step
209-
Failed(Option<Arc<World>>, Info),
209+
Failed(Option<regex::CaptureLocations>, Option<Arc<World>>, Info),
210210
}
211211

212212
// Manual implementation is required to omit the redundant `World: Clone` trait
@@ -216,8 +216,10 @@ impl<World> Clone for Step<World> {
216216
match self {
217217
Self::Started => Self::Started,
218218
Self::Skipped => Self::Skipped,
219-
Self::Passed => Self::Passed,
220-
Self::Failed(w, info) => Self::Failed(w.clone(), info.clone()),
219+
Self::Passed(captures) => Self::Passed(captures.clone()),
220+
Self::Failed(captures, w, info) => {
221+
Self::Failed(captures.clone(), w.clone(), info.clone())
222+
}
221223
}
222224
}
223225
}
@@ -283,17 +285,23 @@ impl<World> Scenario<World> {
283285
///
284286
/// [`Step`]: gherkin::Step
285287
#[must_use]
286-
pub fn step_passed(step: Arc<gherkin::Step>) -> Self {
287-
Self::Step(step, Step::Passed)
288+
pub fn step_passed(
289+
step: Arc<gherkin::Step>,
290+
captures: regex::CaptureLocations,
291+
) -> Self {
292+
Self::Step(step, Step::Passed(captures))
288293
}
289294

290295
/// Constructs an event of a passed [`Background`] [`Step`].
291296
///
292297
/// [`Background`]: gherkin::Background
293298
/// [`Step`]: gherkin::Step
294299
#[must_use]
295-
pub fn background_step_passed(step: Arc<gherkin::Step>) -> Self {
296-
Self::Background(step, Step::Passed)
300+
pub fn background_step_passed(
301+
step: Arc<gherkin::Step>,
302+
captures: regex::CaptureLocations,
303+
) -> Self {
304+
Self::Background(step, Step::Passed(captures))
297305
}
298306

299307
/// Constructs an event of a skipped [`Step`].
@@ -318,10 +326,11 @@ impl<World> Scenario<World> {
318326
#[must_use]
319327
pub fn step_failed(
320328
step: Arc<gherkin::Step>,
329+
captures: Option<regex::CaptureLocations>,
321330
world: Option<Arc<World>>,
322331
info: Info,
323332
) -> Self {
324-
Self::Step(step, Step::Failed(world, info))
333+
Self::Step(step, Step::Failed(captures, world, info))
325334
}
326335

327336
/// Constructs an event of a failed [`Background`] [`Step`].
@@ -331,9 +340,10 @@ impl<World> Scenario<World> {
331340
#[must_use]
332341
pub fn background_step_failed(
333342
step: Arc<gherkin::Step>,
343+
captures: Option<regex::CaptureLocations>,
334344
world: Option<Arc<World>>,
335345
info: Info,
336346
) -> Self {
337-
Self::Background(step, Step::Failed(world, info))
347+
Self::Background(step, Step::Failed(captures, world, info))
338348
}
339349
}

0 commit comments

Comments
 (0)