| # How to write tests using FileCheck | 
 |  | 
 | ## What is FileCheck | 
 |  | 
 | FileCheck can be seen as an advanced version of grep. We use it for writing | 
 | small annotated unit tests for optimization passes. FileCheck used in PyTorch is | 
 | inspired by [LLVM FileCheck | 
 | Tool](https://llvm.org/docs/CommandGuide/FileCheck.html), but is not the same. | 
 | FileCheck is available for writing both C++ and python tests. | 
 |  | 
 | ## How does it work | 
 |  | 
 | Let's look at a test written with FileCheck. The following test verifies that | 
 | CSE pass removes one out of two similar `aten::mul` nodes. Here is how the test | 
 | looks like: | 
 |  | 
 | ```python | 
 | def test_cse(): | 
 |     input_str = """graph(%a : Tensor, %b : Tensor): | 
 |       # CHECK: aten::mul | 
 |       %x : Tensor = aten::mul(%a, %b) | 
 |       # Check that the second aten::mul is removed by CSE. | 
 |       # CHECK-NOT: aten::mul | 
 |       %y : Tensor = aten::mul(%a, %b) | 
 |       # CHECK: return | 
 |       return (%x, %y) | 
 |       """ | 
 |     parsed = parse_ir(input_str) | 
 |     optimized = run_cse(parsed) | 
 |     FileCheck().run(input_str, optimized) | 
 | ``` | 
 |  | 
 | Let's look in detail at how it works. First, the input string is parsed by | 
 | `parse_ir`. At that stage all annotations are ignored since they are written in | 
 | comments, so this is what parser essentially sees: | 
 |  | 
 | ``` | 
 | graph(%a : Tensor, %b : Tensor): | 
 |       %x : Tensor = aten::mul(%a, %b) | 
 |       %y : Tensor = aten::mul(%a, %b) | 
 |       return (%x, %y) | 
 | ``` | 
 |  | 
 | We then run CSE on the parsed IR and expect it to remove the second `aten::mul`, | 
 | which is redundant. After CSE our IR looks like this: | 
 |  | 
 | ``` | 
 | graph(%a : Tensor, %b : Tensor): | 
 |       %x : Tensor = aten::mul(%a, %b) | 
 |       return (%x, %x) | 
 | ``` | 
 |  | 
 | And now we run `FileCheck` passing to it both original input string and the | 
 | optimized IR. From the input string `FileCheck` ignores everything except `# | 
 | CHECK` pragmas and essentially it sees the input string like this: | 
 |  | 
 | ``` | 
 |       # CHECK: aten::mul       (1) | 
 |       # CHECK-NOT: aten::mul   (2) | 
 |       # CHECK: return          (3) | 
 | ``` | 
 |  | 
 | It then checks that the optimized IR satisfies the specified annotations. It | 
 | first finds string `%x : Tensor = aten::mul(%a, %b)` matching the annotation (1), | 
 | then it finds string `return (%x, %x)` matching the annotation (3), and since | 
 | there were no lines matching `aten::mul` after the match (1) and before the | 
 | match (3), the annotation (2) is also satisfied. | 
 |  | 
 | One could also register FileCheck annotations using a builder API. To generate | 
 | annotations from the example above one would write: | 
 | ```python | 
 |       FileCheck().check("aten::mul")     \ | 
 |                  .check_not("aten::mul") \ | 
 |                  .check("return")        \ | 
 |                  .run(optimized) | 
 | ``` | 
 |  | 
 | ## Supported pragmas | 
 |  | 
 | * `CHECK: <pattern>` | 
 |   Scans the input until `PATTERN` is found. Fails if the pattern is not found. | 
 | * `CHECK-NEXT: <pattern>` | 
 |   Scans the input on the line immediately following the previous CHECK until | 
 |   `PATTERN` is found. Fails if the pattern is not found on that line. | 
 | * `CHECK-NOT: <pattern>` | 
 |   Scans the input and fails if `PATTERN` is found on any line. The scan stops when | 
 |   a match for a next `CHECK` is found. | 
 | * `CHECK-SAME: <pattern>` | 
 |   Checks that PATTERN is found in the line of the last match. | 
 | * `CHECK-COUNT-<num>: <pattern>` | 
 |   Scans the input and succeeds when a line containing at least `NUM` entries of | 
 |   `PATTERN` is found. | 
 | * `CHECK-COUNT-EXACTLY-<num>: <pattern>` | 
 |   Scans the input and succeeds when a line containing exactly `NUM` entries of | 
 |   `PATTERN` is found. | 
 | * `CHECK-DAG: pattern` | 
 |   Works similar to the usual `CHECK` pragma, but also matches if there exists a | 
 |   way to reorder the CHECK-DAG pragmas to satisfy all patterns. | 
 |   For example the following pattern: | 
 |   ``` | 
 |   # CHECK: foo | 
 |   # CHECK-DAG: bar | 
 |   # CHECK-DAG: ham | 
 |   # CHECK: end | 
 |   ``` | 
 |   would match the following input (note that `ham` and `bar` are swapped): | 
 |   ``` | 
 |   foo | 
 |   ham | 
 |   bar | 
 |   end | 
 |   ``` |