# 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)