# Namers
## Contents
* [The Purpose of Namers](#the-purpose-of-namers)
* [The Parts of Namers](#the-parts-of-namers)
* [Converting Test Names to Valid FileNames](#converting-test-names-to-valid-filenames)
* [Registering a Custom Namer](#registering-a-custom-namer)
* [Locally](#locally)
* [Globally](#globally)
* [Alternative Namers](#alternative-namers)
* [TemplatedCustomNamer](#templatedcustomnamer)
* [Supported tags](#supported-tags)
* [Examples](#examples)
* [SeparateApprovedAndReceivedDirectoriesNamer](#separateapprovedandreceiveddirectoriesnamer)
* [Approving multiple files from one test](#approving-multiple-files-from-one-test)
## The Purpose of Namers
`Approvals::verify(text);`
could be written as:
`REQUIRE(text == (loadContentsFromFile("FileName.TestName.approved.txt"));`
Part of Approval Tests' "Convention over Configuration" is to remove this by automatically creating meaningful file names, and therefore it could be written as:
`REQUIRE(text == (loadContentsFromFile(namer.getApprovedFile()));`
"If you **always** have to do something, you should **never** have to do something."
Since all of your `REQUIRE`s would look like this, we can simplify it with the above `Approvals::verify(text);` - and this is enabled by the ApprovalNamers.
## The Parts of Namers
The conventional layout for files saved with `Approvals::verify()` and related functions is:
* `path_to_test_file/FileName.TestName.approved.txt`
* `path_to_test_file/FileName.TestName.received.txt`
The Approval Namer is responsible for creating these two names.
The interface for this
is [`ApprovalNamer`](https://github.com/approvals/ApprovalTests.cpp/blob/master/ApprovalTests/core/ApprovalNamer.h).
### Converting Test Names to Valid FileNames
Some C++ test frameworks allow test names to contain characters that are not valid in file or directory names on every operating system.
Therefore, by default, ApprovalTests will convert any non-valid filename character to an `_` (underscore). This can mean `"test <"` and `"test >"` would produce colliding `test__.approved.txt`.
This behavior is customizable, here's an example:
```cpp
TEST_CASE("Sanitizer <3 fileNames")
{
{
auto disposer =
ApprovalTests::Approvals::useFileNameSanitizer([](std::string incoming) {
return ApprovalTests::StringUtils::replaceAll(
incoming, " <3 ", "_loves_");
});
```
snippet source | anchor
## Registering a Custom Namer
### Locally
If you want to use a specific namer for a specific test, the easiest way is via Options:
```cpp
auto namer = ApprovalTests::TemplatedCustomNamer::create(
"{TestSourceDirectory}/{ApprovalsSubdirectory}/CustomName.{ApprovedOrReceived}.{FileExtension}");
ApprovalTests::Approvals::verify("Hello", ApprovalTests::Options().withNamer(namer));
```
snippet source | anchor
### Globally
If you ever want to create a custom namer, that's used in multiple places, Approval Tests has a mechanism to change
which namer it uses by default. Please note that you need to create a function that creates new namers.
```cpp
auto default_namer_disposer = ApprovalTests::Approvals::useAsDefaultNamer(
[]() { return std::make_shared(); });
```
snippet source | anchor
**Hint:** Many namer classes have a `useAsDefaultNamer()` convenience method to do this for you.
## Alternative Namers
### TemplatedCustomNamer
The easiest way to create a custom namer is to use a `TemplatedCustomNamer`.
As well as giving great flexibility, this introduces the ability to run Approval Tests
on machines that do not have the source code, such as when doing cross-compilation
Here is an example:
```cpp
ApprovalTests::TemplatedCustomNamer namer(
"/my/source/directory/{ApprovedOrReceived}/"
"{TestFileName}.{TestCaseName}.{FileExtension}");
```
snippet source | anchor
**Note:** The character `/` will be converted to `\` on Windows machines, at run-time.
#### Supported tags
```cpp
auto testSourceDirectory = "{TestSourceDirectory}";
auto relativeTestSourceDirectory = "{RelativeTestSourceDirectory}";
auto approvalsSubdirectory = "{ApprovalsSubdirectory}";
auto testFileName = "{TestFileName}";
auto testCaseName = "{TestCaseName}";
auto approvedOrReceived = "{ApprovedOrReceived}";
auto fileExtension = "{FileExtension}";
```
snippet source | anchor
Here is some output showing examples with these tags expanded:
```txt
For template: {RelativeTestSourceDirectory}/{ApprovalsSubdirectory}/{TestFileName}.{TestCaseName}.{ApprovedOrReceived}.{FileExtension}
Result: namers/approval_tests/TemplatedCustomNamerTests.Demo_all_namer_templates.approved.txt
With breakdown:
RelativeTestSourceDirectory = namers/
ApprovalsSubdirectory = approval_tests/
TestFileName = TemplatedCustomNamerTests
TestCaseName = Demo_all_namer_templates
ApprovedOrReceived = approved
FileExtension = txt
Also available:
{TestSourceDirectory} = /ApprovalTests.cpp/tests/DocTest_Tests/namers/
```
snippet source | anchor
#### Examples
If you would like to see an example of this running for scenarios where the execution is in a separate environment from the compilation, check out [our out_of_source example](https://github.com/approvals/ApprovalTests.cpp/blob/master/examples/out_of_source/out_of_source_main.cpp).
### SeparateApprovedAndReceivedDirectoriesNamer
The pattern used by this class for file names is:
```cpp
auto path = "{TestSourceDirectory}/{ApprovalsSubdirectory}/{ApprovedOrReceived}/{TestFileName}.{TestCaseName}.{FileExtension}";
```
snippet source | anchor
Which results in these file names:
- `./approved/{TestFileName}.{TestCaseName}.{FileExtension}`
- `./received/{TestFileName}.{TestCaseName}.{FileExtension}`
This layout enables you to use Beyond Compare 4 (or any other directory comparison tool) to do a folder/directory comparison, in order to compare pairs of files in the `approved/` and `received/` directories, and approve one or more files by copying them (without renaming) from `received/` to `approved/`.
The `approved/` and `received/` directories are created automatically.
To register this as your default namer, use:
```cpp
auto default_namer_disposer =
ApprovalTests::SeparateApprovedAndReceivedDirectoriesNamer::useAsDefaultNamer();
```
snippet source | anchor
When using this namer, you will want to add the following line to your `.gitignore` file:
```
**/received/
```
## Approving multiple files from one test
See [MultipleOutputFilesPerTest](/doc/MultipleOutputFilesPerTest.md#top).
---
[Back to User Guide](/doc/README.md#top)