|
6 | 6 |
|
7 | 7 | // SPDX-License-Identifier: BSL-1.0 |
8 | 8 |
|
| 9 | +#include <catch2/benchmark/catch_benchmark.hpp> |
| 10 | +#include <catch2/catch_template_test_macros.hpp> |
| 11 | +#include <catch2/catch_test_macros.hpp> |
| 12 | +#include <catch2/generators/catch_generators.hpp> |
9 | 13 | #include <catch2/internal/catch_enum_values_registry.hpp> |
10 | 14 | #include <catch2/matchers/catch_matchers_string.hpp> |
11 | 15 | #include <catch2/matchers/catch_matchers_vector.hpp> |
12 | | -#include <catch2/catch_test_macros.hpp> |
13 | | -#include <catch2/catch_template_test_macros.hpp> |
14 | 16 |
|
15 | 17 | #include <chrono> |
16 | 18 |
|
@@ -139,3 +141,70 @@ TEST_CASE( "Exception thrown inside stringify does not fail the test", "[toStrin |
139 | 141 | ThrowsOnStringification tos; |
140 | 142 | CHECK( tos == tos ); |
141 | 143 | } |
| 144 | + |
| 145 | +namespace { |
| 146 | + [[maybe_unused]] |
| 147 | + std::string convertIntoString( Catch::StringRef string, |
| 148 | + bool escapeInvisibles ) { |
| 149 | + std::string ret; |
| 150 | + // This is enough for the "don't escape invisibles" case, and a good |
| 151 | + // lower bound on the "escape invisibles" case. |
| 152 | + ret.reserve( string.size() + 2 ); |
| 153 | + |
| 154 | + if ( !escapeInvisibles ) { |
| 155 | + ret += '"'; |
| 156 | + ret += string; |
| 157 | + ret += '"'; |
| 158 | + return ret; |
| 159 | + } |
| 160 | + |
| 161 | + size_t last_start = 0; |
| 162 | + auto write_to = [&]( size_t idx ) { |
| 163 | + if ( last_start < idx ) { |
| 164 | + //ret.append( string.data() + last_start, idx - last_start ); |
| 165 | + ret += string.substr( last_start, idx - last_start ); |
| 166 | + } |
| 167 | + last_start = idx + 1; |
| 168 | + }; |
| 169 | + |
| 170 | + ret += '"'; |
| 171 | + for ( size_t i = 0; i < string.size(); ++i ) { |
| 172 | + const char c = string[i]; |
| 173 | + if (c == '\r' || c == '\n' || c == '\t' || c == '\f') { |
| 174 | + write_to( i ); |
| 175 | + if ( c == '\r' ) { ret.append( "\\r" ); } |
| 176 | + if ( c == '\n' ) { ret.append( "\\n" ); } |
| 177 | + if ( c == '\t' ) { ret.append( "\\t" ); } |
| 178 | + if ( c == '\f' ) { ret.append( "\\f" ); } |
| 179 | + } |
| 180 | + } |
| 181 | + write_to( string.size() ); |
| 182 | + ret += '"'; |
| 183 | + |
| 184 | + return ret; |
| 185 | + } |
| 186 | +} |
| 187 | + |
| 188 | + |
| 189 | +TEST_CASE( "string escaping benchmark", "[toString][!benchmark]" ) { |
| 190 | + const auto input_length = GENERATE( as<size_t>{}, 10, 100, 10'000, 100'000 ); |
| 191 | + std::string test_input( input_length, 'a' ); |
| 192 | + BENCHMARK( "no-escape string, no-escaping, len=" + |
| 193 | + std::to_string( input_length ) ) { |
| 194 | + return Catch::Detail::convertIntoString( test_input, false ); |
| 195 | + }; |
| 196 | + BENCHMARK( "no-escape string, escaping, len=" + |
| 197 | + std::to_string( input_length ) ) { |
| 198 | + return Catch::Detail::convertIntoString( test_input, true ); |
| 199 | + }; |
| 200 | + |
| 201 | + std::string escape_input( input_length, '\r' ); |
| 202 | + BENCHMARK( "full escape string, no-escaping, len=" + |
| 203 | + std::to_string( input_length ) ) { |
| 204 | + return Catch::Detail::convertIntoString( escape_input, false ); |
| 205 | + }; |
| 206 | + BENCHMARK( "full escape string, escaping, len=" + |
| 207 | + std::to_string( input_length ) ) { |
| 208 | + return Catch::Detail::convertIntoString( escape_input, true ); |
| 209 | + }; |
| 210 | +} |
0 commit comments