test.js 46.9 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632
const fs = require('fs')
const test = require('ava')
const {
  execFilePromise, matchOutput, reorderings, updateExpectedPaths, updatePath
} = require('./util')

// We are going to run the server directly, not through npm
const {INIT_CWD, ...GREP_ENV} = process.env
process.chdir(__dirname)

const RUST_MUTABLE_EXPECTED = updateExpectedPaths([
  [
    'files/rust-book/ch10-03-lifetime-syntax.md:reference to an `i32` that has a lifetime parameter named `\'a`, and a mutable',
    'files/rust-book/ch10-03-lifetime-syntax.md:&\'a mut i32 // a mutable reference with an explicit lifetime'
  ],
  ['files/rust-book/ch15-00-smart-pointers.md:In addition, we’ll cover the *interior mutability* pattern where an immutable'],
  ['files/rust-book/ch15-03-drop.md:`drop` that takes a mutable reference to `self`. To see when Rust calls `drop`,'],
  [
    'files/rust-book/ch04-01-what-is-ownership.md:immutable. Another is that not every string value can be known when we write',
    'files/rust-book/ch04-01-what-is-ownership.md:With the `String` type, in order to support a mutable, growable piece of text,'
  ],
  [
    'files/rust-book/ch15-04-rc.md:Via immutable references, `Rc<T>` allows you to share data between multiple',
    'files/rust-book/ch15-04-rc.md:mutable references too, you might violate one of the borrowing rules discussed',
    'files/rust-book/ch15-04-rc.md:in Chapter 4: multiple mutable borrows to the same place can cause data races'
  ],
  [
    'files/rust-book/ch20-03-graceful-shutdown-and-cleanup.md:this because `self` is a mutable reference, and we also need to be able to',
    'files/rust-book/ch20-03-graceful-shutdown-and-cleanup.md:The error tells us we can’t call `join` because we only have a mutable borrow'
  ],
  ['files/rust-book/ch13-01-closures.md:captured variables also implement `FnMut`, and closures that don’t need mutable'],
  ['files/rust-book/ch20-01-single-threaded.md:In the `handle_connection` function, we’ve made the `stream` parameter mutable.'],
  ['files/rust-book/ch08-02-strings.md:coded into the core language, is a growable, mutable, owned, UTF-8 encoded'],
  [
    'files/rust-book/ch08-01-vectors.md:make it mutable using the `mut` keyword, as discussed in Chapter 3. The numbers',
    'files/rust-book/ch08-01-vectors.md:rule that states you can’t have mutable and immutable references in the same',
    'files/rust-book/ch08-01-vectors.md:scope. That rule applies in Listing 8-7, where we hold an immutable reference to',
    'files/rust-book/ch08-01-vectors.md:8-8 shows how to use a `for` loop to get immutable references to each element',
    'files/rust-book/ch08-01-vectors.md:We can also iterate over mutable references to each element in a mutable vector',
    'files/rust-book/ch08-01-vectors.md:<span class="caption">Listing 8-9: Iterating over mutable references to',
    'files/rust-book/ch08-01-vectors.md:To change the value that the mutable reference refers to, we have to use the'
  ],
  [
    'files/rust-book/ch15-02-deref.md:immutable references, you can use the `DerefMut` trait to override the `*`',
    'files/rust-book/ch15-02-deref.md:operator on mutable references.',
    'files/rust-book/ch15-02-deref.md:happens for mutable references.',
    'files/rust-book/ch15-02-deref.md:The third case is trickier: Rust will also coerce a mutable reference to an',
    'files/rust-book/ch15-02-deref.md:immutable one. But the reverse is *not* possible: immutable references will',
    'files/rust-book/ch15-02-deref.md:never coerce to mutable references. Because of the borrowing rules, if you have',
    'files/rust-book/ch15-02-deref.md:a mutable reference, that mutable reference must be the only reference to that',
    'files/rust-book/ch15-02-deref.md:data (otherwise, the program wouldn’t compile). Converting one mutable',
    'files/rust-book/ch15-02-deref.md:reference to one immutable reference will never break the borrowing rules.',
    'files/rust-book/ch15-02-deref.md:Converting an immutable reference to a mutable reference would require that the',
    'files/rust-book/ch15-02-deref.md:initial immutable reference is the only immutable reference to that data, but',
    'files/rust-book/ch15-02-deref.md:assumption that converting an immutable reference to a mutable reference is'
  ],
  [
    'files/rust-book/ch17-03-oo-design-patterns.md:The `add_text` method takes a mutable reference to `self`, because we’re',
    'files/rust-book/ch17-03-oo-design-patterns.md:We give `Post` a public method named `request_review` that will take a mutable'
  ],
  [
    'files/rust-book/ch15-05-interior-mutability.md:data even when there are immutable references to that data; normally, this',
    'files/rust-book/ch15-05-interior-mutability.md:safe API, and the outer type is still immutable.',
    'files/rust-book/ch15-05-interior-mutability.md:* At any given time, you can have *either* (but not both of) one mutable',
    'files/rust-book/ch15-05-interior-mutability.md:  reference or any number of immutable references.',
    'files/rust-book/ch15-05-interior-mutability.md:* `Box<T>` allows immutable or mutable borrows checked at compile time; `Rc<T>`',
    'files/rust-book/ch15-05-interior-mutability.md:  allows only immutable borrows checked at compile time; `RefCell<T>` allows',
    'files/rust-book/ch15-05-interior-mutability.md:  immutable or mutable borrows checked at runtime.',
    'files/rust-book/ch15-05-interior-mutability.md:* Because `RefCell<T>` allows mutable borrows checked at runtime, you can',
    'files/rust-book/ch15-05-interior-mutability.md:  immutable.',
    'files/rust-book/ch15-05-interior-mutability.md:Mutating the value inside an immutable value is the *interior mutability*',
    'files/rust-book/ch15-05-interior-mutability.md:### Interior Mutability: A Mutable Borrow to an Immutable Value',
    'files/rust-book/ch15-05-interior-mutability.md:A consequence of the borrowing rules is that when you have an immutable value,',
    'files/rust-book/ch15-05-interior-mutability.md:{{#rustdoc_include ../listings/ch15-smart-pointers/no-listing-01-cant-borrow-immutable-as-mutable/src/main.rs}}',
    'files/rust-book/ch15-05-interior-mutability.md:{{#include ../listings/ch15-smart-pointers/no-listing-01-cant-borrow-immutable-as-mutable/output.txt}}',
    'files/rust-book/ch15-05-interior-mutability.md:itself in its methods but appear immutable to other code. Code outside the',
    'files/rust-book/ch15-05-interior-mutability.md:an immutable value and see why that is useful.',
    'files/rust-book/ch15-05-interior-mutability.md:called `send` that takes an immutable reference to `self` and the text of the',
    'files/rust-book/ch15-05-interior-mutability.md:`send` method takes an immutable reference to `self`. We also can’t take the',
    'files/rust-book/ch15-05-interior-mutability.md:value while the outer value is considered immutable</span>',
    'files/rust-book/ch15-05-interior-mutability.md:immutable borrow of `self`, which matches the trait definition. We call',
    'files/rust-book/ch15-05-interior-mutability.md:mutable reference to the value inside the `RefCell<Vec<String>>`, which is',
    'files/rust-book/ch15-05-interior-mutability.md:the vector. Then we can call `push` on the mutable reference to the vector to',
    'files/rust-book/ch15-05-interior-mutability.md:immutable reference to the vector.',
    'files/rust-book/ch15-05-interior-mutability.md:When creating immutable and mutable references, we use the `&` and `&mut`',
    'files/rust-book/ch15-05-interior-mutability.md:increases its count of how many immutable borrows are active. When a `Ref<T>`',
    'files/rust-book/ch15-05-interior-mutability.md:value goes out of scope, the count of immutable borrows goes down by one. Just',
    'files/rust-book/ch15-05-interior-mutability.md:like the compile-time borrowing rules, `RefCell<T>` lets us have many immutable',
    'files/rust-book/ch15-05-interior-mutability.md:borrows or one mutable borrow at any point in time.',
    'files/rust-book/ch15-05-interior-mutability.md:Listing 15-22. We’re deliberately trying to create two mutable borrows active',
    'files/rust-book/ch15-05-interior-mutability.md:<span class="caption">Listing 15-23: Creating two mutable references in the',
    'files/rust-book/ch15-05-interior-mutability.md:from `borrow_mut`. Then we create another mutable borrow in the same way in the',
    'files/rust-book/ch15-05-interior-mutability.md:variable `two_borrow`. This makes two mutable references in the same scope,',
    'files/rust-book/ch15-05-interior-mutability.md:messages it has seen while you’re using it in a context where only immutable',
    'files/rust-book/ch15-05-interior-mutability.md:`Rc<T>` lets you have multiple owners of some data, but it only gives immutable',
    'files/rust-book/ch15-05-interior-mutability.md:`Rc<T>` holds only immutable values, we can’t change any of the values in the',
    'files/rust-book/ch15-05-interior-mutability.md:immutable `List` value. But we can use the methods on `RefCell<T>` that provide'
  ],
  [
    'files/rust-book/ch13-02-iterators.md:Note that we needed to make `v1_iter` mutable: calling the `next` method on an',
    'files/rust-book/ch13-02-iterators.md:to make `v1_iter` mutable when we used a `for` loop because the loop took',
    'files/rust-book/ch13-02-iterators.md:ownership of `v1_iter` and made it mutable behind the scenes.',
    'files/rust-book/ch13-02-iterators.md:Also note that the values we get from the calls to `next` are immutable',
    'files/rust-book/ch13-02-iterators.md:over immutable references. If we want to create an iterator that takes',
    'files/rust-book/ch13-02-iterators.md:`iter`. Similarly, if we want to iterate over mutable references, we can call'
  ],
  [
    'files/rust-book/ch03-01-variables-and-mutability.md:As mentioned in Chapter 2, by default variables are immutable. This is one of',
    'files/rust-book/ch03-01-variables-and-mutability.md:option to make your variables mutable. Let’s explore how and why Rust',
    'files/rust-book/ch03-01-variables-and-mutability.md:When a variable is immutable, once a value is bound to a name, you can’t change',
    'files/rust-book/ch03-01-variables-and-mutability.md:{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-01-variables-are-immutable/src/main.rs}}',
    'files/rust-book/ch03-01-variables-and-mutability.md:{{#include ../listings/ch03-common-programming-concepts/no-listing-01-variables-are-immutable/output.txt}}',
    'files/rust-book/ch03-01-variables-and-mutability.md:assign twice to immutable variable x`, because you tried to assign a second',
    'files/rust-book/ch03-01-variables-and-mutability.md:value to the immutable `x` variable.',
    'files/rust-book/ch03-01-variables-and-mutability.md:value that we previously designated as immutable because this very situation',
    'files/rust-book/ch03-01-variables-and-mutability.md:But mutability can be very useful. Variables are immutable only by default; as',
    'files/rust-book/ch03-01-variables-and-mutability.md:you did in Chapter 2, you can make them mutable by adding `mut` in front of the',
    'files/rust-book/ch03-01-variables-and-mutability.md:is used. In some cases, you’ll want to make a variable mutable because it makes',
    'files/rust-book/ch03-01-variables-and-mutability.md:the code more convenient to write than if it had only immutable variables.',
    'files/rust-book/ch03-01-variables-and-mutability.md:immutable variables, constants are values that are bound to a name and are not',
    'files/rust-book/ch03-01-variables-and-mutability.md:immutable by default—they’re always immutable.',
    'files/rust-book/ch03-01-variables-and-mutability.md:on a value but have the variable be immutable after those transformations have'
  ],
  [
    'files/rust-book/ch08-03-hash-maps.md:The `or_insert` method on `Entry` is defined to return a mutable reference to',
    'files/rust-book/ch08-03-hash-maps.md:inserts the parameter as the new value for this key and returns a mutable',
    'files/rust-book/ch08-03-hash-maps.md:`or_insert` method actually returns a mutable reference (`&mut V`) to the value',
    'files/rust-book/ch08-03-hash-maps.md:for this key. Here we store that mutable reference in the `count` variable, so',
    'files/rust-book/ch08-03-hash-maps.md:asterisk (`*`). The mutable reference goes out of scope at the end of the `for`'
  ],
  [
    'files/rust-book/ch04-02-references-and-borrowing.md:Just as variables are immutable by default, so are references. We’re not',
    'files/rust-book/ch04-02-references-and-borrowing.md:First, we had to change `s` to be `mut`. Then we had to create a mutable',
    'files/rust-book/ch04-02-references-and-borrowing.md:reference with `&mut s` and accept a mutable reference with `some_string: &mut',
    'files/rust-book/ch04-02-references-and-borrowing.md:But mutable references have one big restriction: you can have only one mutable',
    'files/rust-book/ch04-02-references-and-borrowing.md:multiple mutable references, just not *simultaneous* ones:',
    'files/rust-book/ch04-02-references-and-borrowing.md:A similar rule exists for combining mutable and immutable references. This code',
    'files/rust-book/ch04-02-references-and-borrowing.md:{{#rustdoc_include ../listings/ch04-understanding-ownership/no-listing-12-immutable-and-mutable-not-allowed/src/main.rs:here}}',
    'files/rust-book/ch04-02-references-and-borrowing.md:{{#include ../listings/ch04-understanding-ownership/no-listing-12-immutable-and-mutable-not-allowed/output.txt}}',
    'files/rust-book/ch04-02-references-and-borrowing.md:Whew! We *also* cannot have a mutable reference while we have an immutable one.',
    'files/rust-book/ch04-02-references-and-borrowing.md:Users of an immutable reference don’t expect the values to suddenly change out',
    'files/rust-book/ch04-02-references-and-borrowing.md:from under them! However, multiple immutable references are okay because no one',
    'files/rust-book/ch04-02-references-and-borrowing.md:compile because the last usage of the immutable references occurs before the',
    'files/rust-book/ch04-02-references-and-borrowing.md:mutable reference is introduced:',
    'files/rust-book/ch04-02-references-and-borrowing.md:The scopes of the immutable references `r1` and `r2` end after the `println!`',
    'files/rust-book/ch04-02-references-and-borrowing.md:where they are last used, which is before the mutable reference `r3` is',
    'files/rust-book/ch04-02-references-and-borrowing.md:* At any given time, you can have *either* one mutable reference *or* any',
    'files/rust-book/ch04-02-references-and-borrowing.md:  number of immutable references.'
  ],
  ['files/rust-book/ch05-02-example-structs.md:`rectangle`, whose type is an immutable borrow of a struct `Rectangle`'],
  [
    'files/rust-book/ch19-01-unsafe-rust.md:* Access or modify a mutable static variable',
    'files/rust-book/ch19-01-unsafe-rust.md:references. As with references, raw pointers can be immutable or mutable and',
    'files/rust-book/ch19-01-unsafe-rust.md:pointers, *immutable* means that the pointer can’t be directly assigned to',
    'files/rust-book/ch19-01-unsafe-rust.md:* Are allowed to ignore the borrowing rules by having both immutable and',
    'files/rust-book/ch19-01-unsafe-rust.md:  mutable pointers or multiple mutable pointers to the same location',
    'files/rust-book/ch19-01-unsafe-rust.md:Listing 19-1 shows how to create an immutable and a mutable raw pointer from',
    'files/rust-book/ch19-01-unsafe-rust.md:We’ve created raw pointers by using `as` to cast an immutable and a mutable',
    'files/rust-book/ch19-01-unsafe-rust.md:stored. If we instead tried to create an immutable and a mutable reference to',
    'files/rust-book/ch19-01-unsafe-rust.md:allow a mutable reference at the same time as any immutable references. With',
    'files/rust-book/ch19-01-unsafe-rust.md:raw pointers, we can create a mutable pointer and an immutable pointer to the',
    'files/rust-book/ch19-01-unsafe-rust.md:same location and change data through the mutable pointer, potentially creating',
    'files/rust-book/ch19-01-unsafe-rust.md:might implement it. This safe method is defined on mutable slices: it takes one',
    'files/rust-book/ch19-01-unsafe-rust.md:Then we return two mutable slices in a tuple: one from the start of the',
    'files/rust-book/ch19-01-unsafe-rust.md:mutable slice to `i32` values, `as_mut_ptr` returns a raw pointer with the type',
    'files/rust-book/ch19-01-unsafe-rust.md:accessing the same mutable global variable, it can cause a data race.',
    'files/rust-book/ch19-01-unsafe-rust.md:<span class="caption">Listing 19-9: Defining and using an immutable static',
    'files/rust-book/ch19-01-unsafe-rust.md:immutable static variable is safe.',
    'files/rust-book/ch19-01-unsafe-rust.md:Constants and immutable static variables might seem similar, but a subtle',
    'files/rust-book/ch19-01-unsafe-rust.md:variables can be mutable. Accessing and modifying mutable static variables is',
    'files/rust-book/ch19-01-unsafe-rust.md:*unsafe*. Listing 19-10 shows how to declare, access, and modify a mutable',
    'files/rust-book/ch19-01-unsafe-rust.md:<span class="caption">Listing 19-10: Reading from or writing to a mutable',
    'files/rust-book/ch19-01-unsafe-rust.md:With mutable data that is globally accessible, it’s difficult to ensure there',
    'files/rust-book/ch19-01-unsafe-rust.md:are no data races, which is why Rust considers mutable static variables to be'
  ],
  ['files/rust-book/ch15-06-reference-cycles.md:mutability gives us a type that we can use when we need an immutable type but'],
  [
    'files/rust-book/ch05-01-defining-structs.md:to use this value. If the instance is mutable, we can change a value by using',
    'files/rust-book/ch05-01-defining-structs.md:to change the value in the `email` field of a mutable `User` instance.',
    'files/rust-book/ch05-01-defining-structs.md:Note that the entire instance must be mutable; Rust doesn’t allow us to mark',
    'files/rust-book/ch05-01-defining-structs.md:only certain fields as mutable. As with any expression, we can construct a new'
  ],
  ['files/rust-book/ch12-04-testing-the-librarys-functionality.md:we can make a mutable vector before the `for` loop and call the `push` method'],
  [
    'files/rust-book/ch13-03-improving-our-io-project.md:keyword into the specification of the `args` parameter to make it mutable.',
    'files/rust-book/ch13-03-improving-our-io-project.md:Doing so also lets us avoid having a mutable intermediate `results` vector. The',
    'files/rust-book/ch13-03-improving-our-io-project.md:functional programming style prefers to minimize the amount of mutable state to',
    'files/rust-book/ch13-03-improving-our-io-project.md:make code clearer. Removing the mutable state might enable a future enhancement'
  ],
  [
    'files/rust-book/ch05-03-method-syntax.md:block. The method name will be `can_hold`, and it will take an immutable borrow',
    'files/rust-book/ch05-03-method-syntax.md:`rect1.can_hold(&rect2)` passes in `&rect2`, which is an immutable borrow to',
    'files/rust-book/ch05-03-method-syntax.md:read `rect2` (rather than write, which would mean we’d need a mutable borrow),'
  ],
  [
    'files/rust-book/ch02-00-guessing-game-tutorial.md:`bar` variable. In Rust, variables are immutable by default. We’ll be',
    'files/rust-book/ch02-00-guessing-game-tutorial.md:a variable mutable:',
    'files/rust-book/ch02-00-guessing-game-tutorial.md:let foo = 5; // immutable',
    'files/rust-book/ch02-00-guessing-game-tutorial.md:let mut bar = 5; // mutable',
    'files/rust-book/ch02-00-guessing-game-tutorial.md:will introduce a mutable variable named `guess`. On the other side of the equal',
    'files/rust-book/ch02-00-guessing-game-tutorial.md:To summarize, the `let mut guess = String::new();` line has created a mutable',
    'files/rust-book/ch02-00-guessing-game-tutorial.md:string argument needs to be mutable so the method can change the string’s',
    'files/rust-book/ch02-00-guessing-game-tutorial.md:immutable by default. Hence, you need to write `&mut guess` rather than',
    'files/rust-book/ch02-00-guessing-game-tutorial.md:`&guess` to make it mutable. (Chapter 4 will explain references more'
  ],
  [
    'files/rust-book/ch04-03-slices.md:Recall from the borrowing rules that if we have an immutable reference to',
    'files/rust-book/ch04-03-slices.md:something, we cannot also take a mutable reference. Because `clear` needs to',
    'files/rust-book/ch04-03-slices.md:truncate the `String`, it needs to get a mutable reference. Rust disallows',
    'files/rust-book/ch04-03-slices.md:the binary. This is also why string literals are immutable; `&str` is an',
    'files/rust-book/ch04-03-slices.md:immutable reference.'
  ],
  [
    'files/rust-book/ch16-03-shared-state.md:this case, as a mutable reference to the data inside. The type system ensures',
    'files/rust-book/ch16-03-shared-state.md:You might have noticed that `counter` is immutable but we could get a mutable'
  ]
])
const MULTIPLE_RUST_FILES = [
  'files/rust-book/ch04-01-what-is-ownership.md',
  'files/rust-book/ch08-03-hash-maps.md',
  'files/rust-book/ch17-00-oop.md',
  'files/rust-book/ch19-01-unsafe-rust.md',
  'files/rust-book/ch19-06-macros.md'
]

const TESTS = [
  {
    // The example from the spec
    args: ['ss', 'files/independence.txt'],
    expected: [[
      'it becomes necessary for one people',
      'to dissolve the political bands',
      'and to assume among the powers of the earth,'
    ]]
  },
  {
    // Test that the pattern is treated as a regular expression.
    // This example is from the spec.
    args: ['the[a-z]', 'files/independence.txt'],
    expected: [[
      'which have connected them with another,',
      'the Laws of Nature and of Nature\'s God entitle them,',
      'that they should declare the causes',
      'which impel them to the separation.'
    ]]
  },
  {
    // Test on a larger file with multiple occurrences in some lines
    args: ['lock', 'files/rust-book/ch20-02-multithreaded.md'],
    expected: [[
      '`else if` after the `if` block to check for the request to */sleep*. When that',
      'Here, we first call `lock` on the `receiver` to acquire the mutex, and then we',
      'call `unwrap` to panic on any errors. Acquiring a lock might fail if the mutex',
      'holding the lock rather than releasing the lock. In this situation, calling',
      'If we get the lock on the mutex, we call `recv` to receive a `Job` from the',
      'The call to `recv` blocks, so if there is no job yet, the current thread will',
      '`unlock` method because the ownership of the lock is based on the lifetime of',
      'the `MutexGuard<T>` within the `LockResult<MutexGuard<T>>` that the `lock`',
      'lock. But this implementation can also result in the lock being held longer',
      'scope for the duration of the block, the lock remains held for the duration of',
      'By using `loop` instead and acquiring the lock without assigning to a variable,',
      'the temporary `MutexGuard` returned from the `lock` method is dropped as soon',
      'as the `let job` statement ends. This ensures that the lock is held during the'
    ]]
  },
  {
    // Test multiple input files
    args: ['mutable', ...MULTIPLE_RUST_FILES],
    expected: RUST_MUTABLE_EXPECTED.filter(([firstLine]) =>
      MULTIPLE_RUST_FILES.some(file => firstLine.startsWith(file))
    )
  },
  {
    // Test -v flag
    args: ['-v', 'ss', 'files/independence.txt'],
    expected: [[
      'When in the Course of human events,',
      'which have connected them with another,',
      'the separate and equal station to which',
      'the Laws of Nature and of Nature\'s God entitle them,',
      'a decent respect to the opinions of mankind requires',
      'that they should declare the causes',
      'which impel them to the separation.'
    ]]
  },
  {
    // Test -i flag
    args: ['-i', 'ZoUnDs', 'files/richard-iii/1/2.txt'],
    expected: [[
      'Zounds , he dies ! I had forgot the reward .',
      'Zounds , ’tis even now at my elbow , persuading me not to kill the Duke .'
    ]]
  },
  {
    // Test -r flag
    args: ['-r', 'mutable', 'files/rust-book'],
    expected: RUST_MUTABLE_EXPECTED
  },
  {
    // Test -r with omitted directory.
    // This also tests a more deeply-nested recursive structure.
    args: ['-r', 'crow' + 'n'],
    expected: updateExpectedPaths([
      [
        'files/richard-iii/1/1/3/2.txt:To fight on Edward’s party for the crow' + 'n ;',
        'files/richard-iii/1/1/3/2.txt:When thou didst crow' + 'n his warlike brows with paper ,'
      ],
      [
        'files/richard-iii/2.txt:Let him be crow' + 'ned . In him your comfort lives .',
        'files/richard-iii/2.txt:Hither to London , to be crow' + 'ned our king .',
        'files/richard-iii/2.txt:Was crow' + 'ned in Paris but at nine months old .'
      ],
      ['files/richard-iii/3/1/1/3.txt:I mean your voice for crow' + 'ning of the King .'],
      [
        'files/richard-iii/3/1/1/2.txt:How “ wear the garland ” ? Dost thou mean the crow' + 'n ?',
        'files/richard-iii/3/1/1/2.txt:I’ll have this crow' + 'n of mine cut from my shoulders',
        'files/richard-iii/3/1/1/2.txt:Before I’ll see the crow' + 'n so foul misplaced .'
      ],
      ['files/richard-iii/3/1/1/1.txt:My husband lost his life to get the crow' + 'n ,'],
      [
        'files/richard-iii/3/1/3/2.txt:Now by my George , my Garter , and my crow' + 'n —',
        'files/richard-iii/3/1/3/2.txt:Thy crow' + 'n , usurped , disgraced his kingly glory .',
        'files/richard-iii/3/1/3/2.txt:He makes for England , here to claim the crow' + 'n .'
      ],
      [
        'files/richard-iii/3/1/2/1/3.txt:Tomorrow may it please you to be crow' + 'ned ?',
        'files/richard-iii/3/1/2/1/3.txt:There to be crow' + 'nèd Richard’s royal queen .'
      ],
      ['files/richard-iii/3/1/2/1/2.txt:And that my path were even to the crow' + 'n'],
      [
        'files/richard-iii/3/1/2/3.txt:For queen , a very caitiff crow' + 'ned with care ;',
        'files/richard-iii/3/1/2/3.txt:Hid’st thou that forehead with a golden crow' + 'n',
        'files/richard-iii/3/1/2/3.txt:The slaughter of the prince that owed that crow' + 'n'
      ],
      ['files/richard-iii/3/1/2/2.txt:And by that knot looks proudly on the crow' + 'n ,'],
      ['files/richard-iii/3/2.txt:The first was I that helped thee to the crow' + 'n ;']
    ])
  },
  {
    // Test a more complicated regex
    args: ['-r', '[a-z]{3}\\d', 'files/rust-book'],
    expected: updateExpectedPaths([
      [
        'files/rust-book/ch10-03-lifetime-syntax.md:type stored in the variable `string1`) as well as string literals (which is',
        'files/rust-book/ch10-03-lifetime-syntax.md:what variable `string2` contains).',
        'files/rust-book/ch10-03-lifetime-syntax.md:In this example, `string1` is valid until the end of the outer scope, `string2`',
        'files/rust-book/ch10-03-lifetime-syntax.md:`string2`. Then we’ll move the `println!` that uses `result` outside the inner',
        'files/rust-book/ch10-03-lifetime-syntax.md:<span class="caption">Listing 10-24: Attempting to use `result` after `string2`',
        'files/rust-book/ch10-03-lifetime-syntax.md:`string2` would need to be valid until the end of the outer scope. Rust knows',
        'files/rust-book/ch10-03-lifetime-syntax.md:As humans, we can look at this code and see that `string1` is longer than',
        'files/rust-book/ch10-03-lifetime-syntax.md:`string2` and therefore `result` will contain a reference to `string1`.',
        'files/rust-book/ch10-03-lifetime-syntax.md:Because `string1` has not gone out of scope yet, a reference to `string1` will'
      ],
      [
        'files/rust-book/ch09-01-unrecoverable-errors-with-panic.md:             at /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/libunwind.rs:88',
        'files/rust-book/ch09-01-unrecoverable-errors-with-panic.md:             at /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/mod.rs:66'
      ],
      [
        'files/rust-book/ch04-01-what-is-ownership.md:<img alt="String in memory" src="img/trpl04-01.svg" class="center" style="width: 50%;" />',
        'files/rust-book/ch04-01-what-is-ownership.md:<img alt="s1 and s2 pointing to the same value" src="img/trpl04-02.svg" class="center" style="width: 50%;" />',
        'files/rust-book/ch04-01-what-is-ownership.md:<img alt="s1 and s2 to two places" src="img/trpl04-03.svg" class="center" style="width: 50%;" />',
        'files/rust-book/ch04-01-what-is-ownership.md:<img alt="s1 moved to s2" src="img/trpl04-04.svg" class="center" style="width: 50%;" />'
      ],
      ['files/rust-book/ch15-04-rc.md:<img alt="Two lists that share ownership of a third list" src="img/trpl15-03.svg" class="center" />'],
      ['files/rust-book/ch13-01-closures.md:parameter, we would separate them with commas, like `|param1, param2|`.'],
      ['files/rust-book/ch20-01-single-threaded.md:The `String::from_utf8_lossy` function takes a `&[u8]` and produces a `String`'],
      [
        'files/rust-book/appendix-06-translation.md:- [Cebuano](https://github.com/agentzero1/book)',
        'files/rust-book/appendix-06-translation.md:- [Tagalog](https://github.com/josephace135/book)'
      ],
      ['files/rust-book/ch20-00-final-project-a-web-server.md:![hello from rust](img/trpl20-01.png)'],
      ['files/rust-book/ch14-03-cargo-workspaces.md:     Running target/debug/deps/add_one-b3235fea9a156f74'],
      [
        'files/rust-book/ch04-02-references-and-borrowing.md:<img alt="&String s pointing at String s1" src="img/trpl04-05.svg" class="center" />',
        'files/rust-book/ch04-02-references-and-borrowing.md:```rust,edition2018',
      ],
      [
        'files/rust-book/ch05-02-example-structs.md:using `rect1`, which is the reason we use the `&` in the function signature and',
        'files/rust-book/ch05-02-example-structs.md:Let’s try it! The `println!` macro call will now look like `println!("rect1 is',
        'files/rust-book/ch05-02-example-structs.md:{:?}", rect1);`. Putting the specifier `:?` inside the curly brackets tells'
      ],
      ['files/rust-book/ch11-03-test-organization.md:target/debug/deps/integration_test-ce99bcc2479f4607` (the hash at the end of'],
      ['files/rust-book/ch15-06-reference-cycles.md:<img alt="Reference cycle of lists" src="img/trpl15-04.svg" class="center" />'],
      [
        'files/rust-book/ch14-02-publishing-to-crates-io.md:<img alt="Rendered HTML documentation for the `add_one` function of `my_crate`" src="img/trpl14-01.png" class="center" />',
        'files/rust-book/ch14-02-publishing-to-crates-io.md:<img alt="Rendered HTML documentation with a comment for the crate as a whole" src="img/trpl14-02.png" class="center" />',
        'files/rust-book/ch14-02-publishing-to-crates-io.md:<img alt="Rendered documentation for the `art` crate that lists the `kinds` and `utils` modules" src="img/trpl14-03.png" class="center" />',
        'files/rust-book/ch14-02-publishing-to-crates-io.md:<img alt="Rendered documentation for the `art` crate with the re-exports on the front page" src="img/trpl14-04.png" class="center" />',
        'files/rust-book/ch14-02-publishing-to-crates-io.md:$ cargo login abcdefghijklmnopqrstuvwxyz012345'
      ],
      [
        'files/rust-book/ch05-01-defining-structs.md:just this user’s email address, we could use `user1.email` wherever we wanted',
        'files/rust-book/ch05-01-defining-structs.md:First, Listing 5-6 shows how we create a new `User` instance in `user2` without',
        'files/rust-book/ch05-01-defining-structs.md:use the same values from `user1` that we created in Listing 5-2.',
        'files/rust-book/ch05-01-defining-structs.md:the values from `user1`</span>',
        'files/rust-book/ch05-01-defining-structs.md:values from the fields of the instance in the `user1` variable</span>',
        'files/rust-book/ch05-01-defining-structs.md:The code in Listing 5-7 also creates an instance in `user2` that has a',
        'files/rust-book/ch05-01-defining-structs.md:`active` and `sign_in_count` fields from `user1`.',
        'files/rust-book/ch05-01-defining-structs.md:>     let user1 = User {',
        'files/rust-book/ch05-01-defining-structs.md:>         username: "someusername123",'
      ],
      [
        'files/rust-book/ch05-03-method-syntax.md:called the `area` function and passed `rect1` as an argument, we can instead',
        'files/rust-book/ch05-03-method-syntax.md:of `rect2` are smaller than the dimensions of `rect1` but `rect3` is wider than',
        'files/rust-book/ch05-03-method-syntax.md:`rect1`:',
        'files/rust-book/ch05-03-method-syntax.md:Can rect1 hold rect2? true',
        'files/rust-book/ch05-03-method-syntax.md:Can rect1 hold rect3? false',
        'files/rust-book/ch05-03-method-syntax.md:`rect1.can_hold(&rect2)` passes in `&rect2`, which is an immutable borrow to',
        'files/rust-book/ch05-03-method-syntax.md:`rect2`, an instance of `Rectangle`. This makes sense because we only need to',
        'files/rust-book/ch05-03-method-syntax.md:read `rect2` (rather than write, which would mean we’d need a mutable borrow),',
        'files/rust-book/ch05-03-method-syntax.md:and we want `main` to retain ownership of `rect2` so we can use it again after'
      ],
      ['files/rust-book/ch04-03-slices.md:<img alt="world containing a pointer to the 6th byte of String s and a length 5" src="img/trpl04-06.svg" class="center" style="width: 50%;" />'],
      [
        'files/rust-book/ch10-02-traits.md:pub fn notify(item1: impl Summary, item2: impl Summary) {',
        'files/rust-book/ch10-02-traits.md:If we wanted this function to allow `item1` and `item2` to have different',
        'files/rust-book/ch10-02-traits.md:pub fn notify<T: Summary>(item1: T, item2: T) {',
        'files/rust-book/ch10-02-traits.md:The generic type `T` specified as the type of the `item1` and `item2`',
        'files/rust-book/ch10-02-traits.md:passed as an argument for `item1` and `item2` must be the same.'
      ],
      [
        'files/rust-book/ch15-01-box.md:<img alt="An infinite Cons list" src="img/trpl15-01.svg" class="center" style="width: 50%;" />',
        'files/rust-book/ch15-01-box.md:<img alt="A finite Cons list" src="img/trpl15-02.svg" class="center" />'
      ]
    ])
  },
  {
    // Test -i with regex
    args: ['-i', '-r', '[a-z]{3}\\d', 'files/rust-book'],
    expected: updateExpectedPaths([
      [
        'files/rust-book/ch10-03-lifetime-syntax.md:type stored in the variable `string1`) as well as string literals (which is',
        'files/rust-book/ch10-03-lifetime-syntax.md:what variable `string2` contains).',
        'files/rust-book/ch10-03-lifetime-syntax.md:In this example, `string1` is valid until the end of the outer scope, `string2`',
        'files/rust-book/ch10-03-lifetime-syntax.md:`string2`. Then we’ll move the `println!` that uses `result` outside the inner',
        'files/rust-book/ch10-03-lifetime-syntax.md:<span class="caption">Listing 10-24: Attempting to use `result` after `string2`',
        'files/rust-book/ch10-03-lifetime-syntax.md:`string2` would need to be valid until the end of the outer scope. Rust knows',
        'files/rust-book/ch10-03-lifetime-syntax.md:As humans, we can look at this code and see that `string1` is longer than',
        'files/rust-book/ch10-03-lifetime-syntax.md:`string2` and therefore `result` will contain a reference to `string1`.',
        'files/rust-book/ch10-03-lifetime-syntax.md:Because `string1` has not gone out of scope yet, a reference to `string1` will'
      ],
      [
        'files/rust-book/ch09-01-unrecoverable-errors-with-panic.md:             at /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/libunwind.rs:88',
        'files/rust-book/ch09-01-unrecoverable-errors-with-panic.md:             at /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/mod.rs:66',
        'files/rust-book/ch09-01-unrecoverable-errors-with-panic.md:   4: core::fmt::ArgumentV1::show_usize'
      ],
      [
        'files/rust-book/ch04-01-what-is-ownership.md:<img alt="String in memory" src="img/trpl04-01.svg" class="center" style="width: 50%;" />',
        'files/rust-book/ch04-01-what-is-ownership.md:<img alt="s1 and s2 pointing to the same value" src="img/trpl04-02.svg" class="center" style="width: 50%;" />',
        'files/rust-book/ch04-01-what-is-ownership.md:<img alt="s1 and s2 to two places" src="img/trpl04-03.svg" class="center" style="width: 50%;" />',
        'files/rust-book/ch04-01-what-is-ownership.md:<img alt="s1 moved to s2" src="img/trpl04-04.svg" class="center" style="width: 50%;" />'
      ],
      ['files/rust-book/ch15-04-rc.md:<img alt="Two lists that share ownership of a third list" src="img/trpl15-03.svg" class="center" />'],
      ['files/rust-book/ch13-01-closures.md:parameter, we would separate them with commas, like `|param1, param2|`.'],
      [
        'files/rust-book/ch20-01-single-threaded.md:The `String::from_utf8_lossy` function takes a `&[u8]` and produces a `String`',
        'files/rust-book/ch20-01-single-threaded.md:User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101',
        'files/rust-book/ch20-01-single-threaded.md:This is a minimal HTML5 document with a heading and some text. To return this'
      ],
      [
        'files/rust-book/appendix-06-translation.md:- [Cebuano](https://github.com/agentzero1/book)',
        'files/rust-book/appendix-06-translation.md:- [Tagalog](https://github.com/josephace135/book)'
      ],
      ['files/rust-book/ch20-00-final-project-a-web-server.md:![hello from rust](img/trpl20-01.png)'],
      ['files/rust-book/ch14-03-cargo-workspaces.md:     Running target/debug/deps/add_one-b3235fea9a156f74'],
      [
        'files/rust-book/ch04-02-references-and-borrowing.md:<img alt="&String s pointing at String s1" src="img/trpl04-05.svg" class="center" />',
        'files/rust-book/ch04-02-references-and-borrowing.md:```rust,edition2018'
      ],
      [
        'files/rust-book/ch05-02-example-structs.md:using `rect1`, which is the reason we use the `&` in the function signature and',
        'files/rust-book/ch05-02-example-structs.md:Let’s try it! The `println!` macro call will now look like `println!("rect1 is',
        'files/rust-book/ch05-02-example-structs.md:{:?}", rect1);`. Putting the specifier `:?` inside the curly brackets tells'
      ],
      [
        'files/rust-book/ch06-01-defining-an-enum.md:struct Ipv4Addr {',
        'files/rust-book/ch06-01-defining-an-enum.md:struct Ipv6Addr {',
        'files/rust-book/ch06-01-defining-an-enum.md:    V4(Ipv4Addr),',
        'files/rust-book/ch06-01-defining-an-enum.md:    V6(Ipv6Addr),'
      ],
      ['files/rust-book/ch11-03-test-organization.md:target/debug/deps/integration_test-ce99bcc2479f4607` (the hash at the end of'],
      ['files/rust-book/ch15-06-reference-cycles.md:<img alt="Reference cycle of lists" src="img/trpl15-04.svg" class="center" />'],
      [
        'files/rust-book/ch14-02-publishing-to-crates-io.md:<img alt="Rendered HTML documentation for the `add_one` function of `my_crate`" src="img/trpl14-01.png" class="center" />',
        'files/rust-book/ch14-02-publishing-to-crates-io.md:<img alt="Rendered HTML documentation with a comment for the crate as a whole" src="img/trpl14-02.png" class="center" />',
        'files/rust-book/ch14-02-publishing-to-crates-io.md:<img alt="Rendered documentation for the `art` crate that lists the `kinds` and `utils` modules" src="img/trpl14-03.png" class="center" />',
        'files/rust-book/ch14-02-publishing-to-crates-io.md:<img alt="Rendered documentation for the `art` crate with the re-exports on the front page" src="img/trpl14-04.png" class="center" />',
        'files/rust-book/ch14-02-publishing-to-crates-io.md:$ cargo login abcdefghijklmnopqrstuvwxyz012345'
      ],
      [
        'files/rust-book/ch05-01-defining-structs.md:just this user’s email address, we could use `user1.email` wherever we wanted',
        'files/rust-book/ch05-01-defining-structs.md:First, Listing 5-6 shows how we create a new `User` instance in `user2` without',
        'files/rust-book/ch05-01-defining-structs.md:use the same values from `user1` that we created in Listing 5-2.',
        'files/rust-book/ch05-01-defining-structs.md:the values from `user1`</span>',
        'files/rust-book/ch05-01-defining-structs.md:values from the fields of the instance in the `user1` variable</span>',
        'files/rust-book/ch05-01-defining-structs.md:The code in Listing 5-7 also creates an instance in `user2` that has a',
        'files/rust-book/ch05-01-defining-structs.md:`active` and `sign_in_count` fields from `user1`.',
        'files/rust-book/ch05-01-defining-structs.md:>     let user1 = User {',
        'files/rust-book/ch05-01-defining-structs.md:>         username: "someusername123",'
      ],
      [
        'files/rust-book/ch05-03-method-syntax.md:called the `area` function and passed `rect1` as an argument, we can instead',
        'files/rust-book/ch05-03-method-syntax.md:of `rect2` are smaller than the dimensions of `rect1` but `rect3` is wider than',
        'files/rust-book/ch05-03-method-syntax.md:`rect1`:',
        'files/rust-book/ch05-03-method-syntax.md:Can rect1 hold rect2? true',
        'files/rust-book/ch05-03-method-syntax.md:Can rect1 hold rect3? false',
        'files/rust-book/ch05-03-method-syntax.md:`rect1.can_hold(&rect2)` passes in `&rect2`, which is an immutable borrow to',
        'files/rust-book/ch05-03-method-syntax.md:`rect2`, an instance of `Rectangle`. This makes sense because we only need to',
        'files/rust-book/ch05-03-method-syntax.md:read `rect2` (rather than write, which would mean we’d need a mutable borrow),',
        'files/rust-book/ch05-03-method-syntax.md:and we want `main` to retain ownership of `rect2` so we can use it again after'
      ],
      ['files/rust-book/ch04-03-slices.md:<img alt="world containing a pointer to the 6th byte of String s and a length 5" src="img/trpl04-06.svg" class="center" style="width: 50%;" />'],
      [
        'files/rust-book/ch10-02-traits.md:pub fn notify(item1: impl Summary, item2: impl Summary) {',
        'files/rust-book/ch10-02-traits.md:If we wanted this function to allow `item1` and `item2` to have different',
        'files/rust-book/ch10-02-traits.md:pub fn notify<T: Summary>(item1: T, item2: T) {',
        'files/rust-book/ch10-02-traits.md:The generic type `T` specified as the type of the `item1` and `item2`',
        'files/rust-book/ch10-02-traits.md:passed as an argument for `item1` and `item2` must be the same.'
      ],
      [
        'files/rust-book/ch15-01-box.md:<img alt="An infinite Cons list" src="img/trpl15-01.svg" class="center" style="width: 50%;" />',
        'files/rust-book/ch15-01-box.md:<img alt="A finite Cons list" src="img/trpl15-02.svg" class="center" />'
      ]
    ])
  },
  {
    // Test -z flag,
    args: ['-z', 'function', 'files/rust-book-gz/ch02-00-guessing-game-tutorial.md.gz'],
    expected: [[
      'functions, using external crates, and more! The following chapters will explore',
      'As you saw in Chapter 1, the `main` function is the entry point into the',
      'The `fn` syntax declares a new function, the parentheses, `()`, indicate there',
      'are no parameters, and the curly bracket, `{`, starts the body of the function.',
      'calling `String::new`, a function that returns a new instance of a `String`.',
      'function* of the `String` type. An associated function is implemented on a type,',
      'This `new` function creates a new, empty string. You’ll find a `new` function',
      'on many types, because it’s a common name for a function that makes a new value',
      'Recall that we included the input/output functionality from the standard',
      'the `stdin` function from the `io` module:',
      'could have written this function call as `std::io::stdin`. The `stdin` function',
      'difficult. Rust doesn’t yet include random number functionality in its standard',
      'Next, we’re adding two lines in the middle. The `rand::thread_rng` function',
      '> Note: You won’t just know which traits to use and which methods and functions',
      '> other functionality in the `rand` crate, for example, run `cargo doc --open`',
      'do that by adding the following two lines to the `main` function body:',
      '`let`, `match`, methods, associated functions, the use of external crates, and',
      'variables, data types, and functions, and shows how to use them in Rust.'
    ]]
  },
  {
    // Test -z flag with -r
    args: ['-r', '-z', 'mutable', 'files/rust-book-gz'],
    expected: RUST_MUTABLE_EXPECTED.map(file => file.map(line =>
      line.replace('rust-book', 'rust-book-gz').replace('.md', '.md.gz')
    ))
  }
]

for (const {args, expected} of TESTS) {
  const flags      = args.filter(arg =>  arg.startsWith('-'))
  const parameters = args.filter(arg => !arg.startsWith('-'))
  // Update all paths in the parameters to have correct separators
  for (let i = 1; i < parameters.length; i++) parameters[i] = updatePath(parameters[i])
  for (const args of reorderings(parameters, flags)) {
    test(`grep ${args.join(' ')}`, async t => {
      const {stdout} = await execFilePromise(
        'node', ['../grep.js', ...args],
        {env: GREP_ENV}
      )
      matchOutput(t, stdout, expected)
    })
  }
}

// grep.js is allowed to return a nonzero exit code if no matches were found
test('grep no matches', async t => {
  let stdout
  try {
    ({stdout} = await execFilePromise(
      'node', ['../grep.js', 'no-such-string', updatePath('files/independence.txt')],
      {env: GREP_ENV}
    ))
  }
  catch (e) { ({stdout} = e) }
  matchOutput(t, stdout, [])
})

// Test grepping the standard input
test('grep stdin', async t => {
  const grepPromise = execFilePromise('node', ['../grep.js', 'Rust'], {env: GREP_ENV})
  fs.createReadStream('files/rust-book/SUMMARY.md')
    .on('error', _ => t.fail('Failed to open file'))
    .pipe(grepPromise.child.stdin)
    .on('error', _ => t.fail('grep.js did not read stdin'))
  const {stdout} = await grepPromise
  matchOutput(t, stdout, [[
    '# The Rust Programming Language',
    '[The Rust Programming Language](title-page.md)',
    '## Basic Rust Literacy',
    '## Thinking in Rust',
    '- [Object Oriented Programming Features of Rust](ch17-00-oop.md)',
    '    - [Unsafe Rust](ch19-01-unsafe-rust.md)',
    '    - [G - How Rust is Made and “Nightly Rust”](appendix-07-nightly-rust.md)'
  ]])
})

// Ensure that the streams deal with lines spread across chunks correctly
test('multiple-chunk input file', async t => {
  const lines = new Array(1e5).fill().map((_, i) => `Line ${i + 1}`)
  for (let i = 0; i < 10; i++) {
    const search = `${i}`
    const {stdout} = await execFilePromise(
      'node', ['../grep.js', search, updatePath('files/long.txt')],
      {env: GREP_ENV}
    )
    const expectedLines = lines.filter(line => line.includes(search))
    t.deepEqual(stdout, expectedLines.map(line => `${line}\n`).join(''))
  }
})

// Ensure that the streams deal with lines containing multiple chunks
test('multiple-chunk lines', async t => {
  const contents = await fs.promises.readFile('files/long-lines.txt', 'utf8')
  const lines = contents.trim().split('\n')
  for (let i = 0; i < 10; i++) {
    const {stdout} = await execFilePromise(
      'node', ['../grep.js', `${i}`, updatePath('files/long-lines.txt')],
      {env: GREP_ENV}
    )
    t.deepEqual(stdout, lines[i] + '\n')
  }
})