• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

thetic / mutiny / 24436498593

15 Apr 2026 04:31AM UTC coverage: 98.749% (-0.2%) from 98.953%
24436498593

Pull #54

github

web-flow
Merge 9559f1b41 into cc6c1f755
Pull Request #54: Handle fixed-width types in mocking

137 of 137 new or added lines in 12 files covered. (100.0%)

5 existing lines in 2 files now uncovered.

5051 of 5115 relevant lines covered (98.75%)

4002.39 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.0
/include/mutiny/String.hpp
1
/**
2
 * @file
3
 * @brief Lightweight string class and string-conversion utilities for the
4
 *        mutiny test framework.
5
 *
6
 * When @ref MUTINY_USE_STD_STRING is defined, @ref mu::tiny::String is an
7
 * alias for `std::string` and the custom class body is omitted entirely.
8
 * Otherwise a self-contained `String` class is provided that avoids any
9
 * dependency on the C++ standard library, allowing the framework to be used
10
 * in bare-metal and other constrained environments.
11
 *
12
 * The free functions below (@ref mu::tiny::string_from,
13
 * @ref mu::tiny::hex_string_from,
14
 * @ref mu::tiny::brackets_formatted_hex_string_from, and related utilities)
15
 * are used
16
 * throughout the framework to convert arbitrary values to their printable
17
 * representations in assertion failure messages.
18
 */
19

20
#ifndef INCLUDED_MUTINY_TEST_STRING_HPP
21
#define INCLUDED_MUTINY_TEST_STRING_HPP
22

23
#include "mutiny/export.h"
24
#include "mutiny/features.hpp"
25

26
#include <stdarg.h>
27
#include <stddef.h>
28

29
#if MUTINY_USE_STD_CPP_LIB
30
#include <string>
31
#include <type_traits>
32
#endif
33

34
#ifndef __has_attribute
35
#define MUTINY_HAS_ATTRIBUTE(x) 0
36
#else
37
#define MUTINY_HAS_ATTRIBUTE(x) __has_attribute(x)
38
#endif
39

40
#if defined(__MINGW32__)
41
#define MUTINY_CHECK_FORMAT_TYPE __MINGW_PRINTF_FORMAT
42
#else
43
#define MUTINY_CHECK_FORMAT_TYPE printf
44
#endif
45

46
namespace mu {
47
namespace tiny {
48

49
#if MUTINY_USE_STD_STRING
50
/**
51
 * @brief String type used throughout the mutiny framework.
52
 *
53
 * When @ref MUTINY_USE_STD_STRING is enabled this is an alias for
54
 * `std::string`; otherwise it is the custom class defined below.
55
 */
56
using String = std::string;
57
#else
58
/**
59
 * @brief Minimal string class used throughout the mutiny framework.
60
 *
61
 * Provides just enough string functionality for assertion messages and
62
 * internal bookkeeping without depending on the C++ standard library.
63
 * The interface deliberately mirrors the subset of `std::string` that
64
 * the framework uses so that switching to `std::string` via
65
 * @ref MUTINY_USE_STD_STRING requires no call-site changes.
66
 */
67
class MUTINY_EXPORT String
68
{
69
  friend bool operator==(const String& left, const String& right);
70
  friend bool operator!=(const String& left, const String& right);
71

72
public:
73
  /** @brief Construct from a NUL-terminated C string (default: empty). */
74
  String(const char* value = "");
75
  /**
76
   * @brief Construct a string of @p count copies of character @p ch.
77
   *
78
   * @param count  Number of characters.
79
   * @param ch     Character to fill with.
80
   */
81
  String(size_t count, char ch);
82
  /** @brief Copy constructor. */
83
  String(const String& other);
84
  /** @brief Move constructor. */
85
  String(String&& other) noexcept;
86
  ~String();
87

88
  /** @brief Copy-assignment operator. */
89
  String& operator=(const String& other);
90
  /** @brief Move-assignment operator. */
91
  String& operator=(String&& other) noexcept;
92
  /** @brief Return the concatenation of this string and @p rhs. */
93
  String operator+(const String&) const;
94
  /** @brief Append @p rhs and return a reference to this string. */
95
  String& operator+=(const String&);
96
  /** @brief Append a C string and return a reference to this string. */
97
  String& operator+=(const char*);
98
  /** @brief Append a single character and return a reference to this string. */
99
  String& operator+=(char ch);
100

101
  /** @brief Sentinel value returned by `find()` when no match is found. */
102
  static constexpr size_t npos = static_cast<size_t>(-1);
103

104
  /** @return Reference to the character at position @p pos. */
105
  char& operator[](size_t pos) { return data()[pos]; }
10,256✔
106
  /** @return Const reference to the character at position @p pos. */
107
  const char& operator[](size_t pos) const { return c_str()[pos]; }
104✔
108

109
  /**
110
   * @brief Find the first occurrence of @p ch at or after @p pos.
111
   *
112
   * @param ch   Character to search for.
113
   * @param pos  Starting position for the search.
114
   * @return Index of the first match, or `npos` if not found.
115
   */
116
  size_t find(char ch, size_t pos = 0) const;
117
  /**
118
   * @brief Find the first occurrence of the substring @p s at or after @p pos.
119
   *
120
   * @param s    Substring to search for.
121
   * @param pos  Starting position for the search.
122
   * @return Index of the first match, or `npos` if not found.
123
   */
124
  size_t find(const char* s, size_t pos = 0) const;
125

126
  /** @return Substring from @p begin_pos to end-of-string. */
127
  String substr(size_t begin_pos) const;
128
  /**
129
   * @return Substring of at most @p amount characters starting at
130
   *         @p begin_pos.
131
   */
132
  String substr(size_t begin_pos, size_t amount) const;
133

134
  /** @return NUL-terminated pointer to the string's character data. */
135
  const char* c_str() const;
136
  /** @return Read-only pointer to the character data. */
137
  const char* data() const;
138
  /** @return Writable pointer to the character data. */
139
  char* data();
140
  /** @return Number of characters (not counting the NUL terminator). */
141
  size_t size() const;
142
  /** @return Number of characters; synonym for `size()`. */
143
  size_t length() const { return size(); }
144
  /** @return Number of characters that fit without reallocation. */
145
  size_t capacity() const { return buffer_size_ ? buffer_size_ - 1 : 0; }
146
  /** @return true if the string has zero characters. */
147
  bool empty() const;
148
  /** @brief Reset the string to empty without releasing the buffer. */
149
  void clear();
150
  /**
151
   * @brief Ensure at least @p new_capacity characters fit without
152
   *        reallocation.
153
   */
154
  void reserve(size_t new_capacity);
155
  /**
156
   * @brief Resize the string to exactly @p new_size characters, padding
157
   *        with NUL bytes if growing.
158
   */
159
  void resize(size_t new_size);
160

161
  friend bool operator<(const String& left, const String& right);
162

163
private:
164
  void deallocate_internal_buffer();
165
  void set_internal_buffer_as_empty_string();
166
  void copy_buffer_to_new_internal_buffer(const char* other_buffer);
167
  void copy_buffer_to_new_internal_buffer(
168
      const char* other_buffer,
169
      size_t buffer_size
170
  );
171
  void copy_buffer_to_new_internal_buffer(const String& other_buffer);
172

173
  char* buffer_;
174
  size_t buffer_size_;
175
  size_t size_;
176

177
  char* get_empty_string() const;
178
};
179
#endif
180

181
/** @brief Return true if @p str contains @p substr. */
182
MUTINY_EXPORT bool string_contains(const String& str, const String& substr);
183
/** @brief Return true if @p str starts with @p prefix. */
184
MUTINY_EXPORT bool string_starts_with(const String& str, const String& prefix);
185
/** @brief Return true if @p str ends with @p suffix. */
186
MUTINY_EXPORT bool string_ends_with(const String& str, const String& suffix);
187

188
/** @brief Replace every @p from character in @p str with @p to. */
189
MUTINY_EXPORT void string_replace(String& str, char from, char to);
190
/**
191
 * @brief Replace every occurrence of the substring @p from in @p str with
192
 *        @p to.
193
 */
194
MUTINY_EXPORT void string_replace(
195
    String& str,
196
    const char* from,
197
    const char* to
198
);
199

200
/**
201
 * @brief Wrappers for C standard library functions, placed in the
202
 *        @ref mu::tiny::test namespace to avoid polluting the global namespace
203
 *        when the standard library is unavailable.
204
 */
205
MUTINY_EXPORT bool iscntrl(char ch);
206
/** @brief Return the length of the NUL-terminated string @p str. */
207
MUTINY_EXPORT size_t strlen(const char* str);
208
/** @brief Return a pointer to the first @p s2 in @p s1, or null. */
209
MUTINY_EXPORT const char* strstr(const char* s1, const char* s2);
210

211
/** @brief Parse @p str as a signed long integer. */
212
MUTINY_EXPORT long strtol(const char* str);
213
/** @brief Parse @p str as an unsigned long integer. */
214
MUTINY_EXPORT unsigned long strtoul(const char* str);
215
/** @brief Compare @p s1 and @p s2; return negative, zero, or positive. */
216
MUTINY_EXPORT int strcmp(const char* s1, const char* s2);
217
/** @brief Compare at most @p n characters of @p s1 and @p s2. */
218
MUTINY_EXPORT int strncmp(const char* s1, const char* s2, size_t n);
219
/** @brief Convert @p ch to lowercase. */
220
MUTINY_EXPORT char tolower(char ch);
221
/** @brief Compare @p n bytes of @p s1 and @p s2; return <0, 0, or >0. */
222
MUTINY_EXPORT int memcmp(const void* s1, const void* s2, size_t n);
223

224
/** @brief Return the decimal string representation of @p value. */
225
MUTINY_EXPORT String string_from(bool value);
226

227
/** @brief Return the pointer address of @p value as a hex string. */
228
MUTINY_EXPORT String string_from(const void* value);
229

230
/** @brief Return the function pointer address of @p value as a hex string. */
231
MUTINY_EXPORT String string_from(void (*value)());
232

233
/** @brief Route any typed function pointer to the @c void(*)() overload. */
234
template<typename RET, typename... ARGS>
235
inline String string_from(RET (*value)(ARGS...))
236
{
237
  return string_from(reinterpret_cast<void (*)()>(value));
238
}
239

240
/** @brief Return the decimal string representation of @p value. */
241
MUTINY_EXPORT String string_from(char value);
242

243
/** @brief Return @p value, or "(null)" if @p value is null. */
244
MUTINY_EXPORT String string_from(const char* value);
245

246
/** @brief Return @p value as a string, or "(null)" if @p value is null. */
247
MUTINY_EXPORT String string_from_or_null(const char* value);
248

249
/** @brief Return the decimal string representation of @p value. */
250
MUTINY_EXPORT String string_from(int value);
251

252
/** @brief Return the decimal string representation of @p value. */
253
MUTINY_EXPORT String string_from(unsigned int value);
254

255
/** @brief Return the decimal string representation of @p value. */
256
MUTINY_EXPORT inline String string_from(signed char value)
1✔
257
{
258
  return string_from(static_cast<int>(value));
1✔
259
}
260

261
/** @brief Return the decimal string representation of @p value. */
UNCOV
262
MUTINY_EXPORT inline String string_from(unsigned char value)
×
263
{
UNCOV
264
  return string_from(static_cast<unsigned int>(value));
×
265
}
266

267
/** @brief Return the decimal string representation of @p value. */
268
MUTINY_EXPORT String string_from(long value);
269

270
/** @brief Return the decimal string representation of @p value. */
271
MUTINY_EXPORT String string_from(unsigned long value);
272

273
/** @brief Return the decimal string representation of @p value. */
274
MUTINY_EXPORT String string_from(long long value);
275

276
/** @brief Return the decimal string representation of @p value. */
277
MUTINY_EXPORT String string_from(unsigned long long value);
278

279
/**
280
 * @brief Return the decimal string representation of @p value with the given
281
 *        @p precision.
282
 */
283
MUTINY_EXPORT String string_from(float value, int precision = 6);
284

285
/** @brief Return @p value as a `0x`-prefixed hexadecimal string. */
286
MUTINY_EXPORT String hex_string_from(unsigned int value);
287

288
/** @brief Return @p value as a `0x`-prefixed hexadecimal string. */
289
MUTINY_EXPORT String hex_string_from(int value);
290

291
/** @brief Return @p value as a `0x`-prefixed hexadecimal string. */
292
MUTINY_EXPORT String hex_string_from(signed char value);
293

294
/** @brief Return @p value as a `0x`-prefixed hexadecimal string. */
295
MUTINY_EXPORT String hex_string_from(long value);
296

297
/** @brief Return @p value as a `0x`-prefixed hexadecimal string. */
298
MUTINY_EXPORT String hex_string_from(unsigned long value);
299

300
/** @brief Return @p value as a `0x`-prefixed hexadecimal string. */
301
MUTINY_EXPORT String hex_string_from(long long value);
302

303
/** @brief Return @p value as a `0x`-prefixed hexadecimal string. */
304
MUTINY_EXPORT String hex_string_from(unsigned long long value);
305

306
/** @brief Return the address of @p value as a `0x`-prefixed hex string. */
307
MUTINY_EXPORT String hex_string_from(const void* value);
308

309
/** @brief Return the address of @p value as a `0x`-prefixed hex string. */
310
MUTINY_EXPORT String hex_string_from(void (*value)());
311

312
/**
313
 * @brief Return the decimal string representation of @p value with the given
314
 *        @p precision.
315
 */
316
MUTINY_EXPORT String string_from(double value, int precision = 6);
317

318
/** @brief Return a copy of @p other as a String. */
319
MUTINY_EXPORT String string_from(const String& other);
320

321
/** @brief Return the string representation of a null pointer constant. */
322
MUTINY_EXPORT String string_from(decltype(nullptr) value);
323

324
#if MUTINY_USE_STD_CPP_LIB
325

326
#if !MUTINY_USE_STD_STRING
327
/** @brief Convert a `std::string` to a `String`. */
328
MUTINY_EXPORT String string_from(std::string const& str);
329
#endif
330
#endif
331

332
/** @brief Route a non-const void pointer to the `const void*` overload. */
333
MUTINY_EXPORT inline String string_from(void* value)
10✔
334
{
335
  return string_from(static_cast<const void*>(value));
10✔
336
}
337

338
// Catch any pointer type that lacks its own overload and route to const void*.
339
// This template is more specialised than the fallback below, so it wins
340
// in partial ordering when the argument is a non-void pointer.
341
template<typename T>
342
inline String string_from(T* value)
1✔
343
{
344
  return string_from(static_cast<const void*>(value));
1✔
345
}
346

347
// Fallback: fires only for class types (structs/classes) that have no
348
// string_from() overload.  Enums and arithmetic types are excluded so they
349
// continue to use their existing implicit-conversion overloads (e.g. enum→int).
350
// When the standard library is available we use std::is_class to express this
351
// constraint via SFINAE; without it the fallback is omitted and a missing
352
// overload surfaces as a linker error instead.
353
#if MUTINY_USE_STD_CPP_LIB
354
template<
355
    typename T,
356
    typename std::enable_if<std::is_class<T>::value, int>::type = 0>
357
String string_from(const T&)
358
{
359
  static_assert(
360
      sizeof(T) == 0,
361
      "No mu::tiny::string_from() overload for this type. "
362
      "Provide: mu::tiny::String mu::tiny::string_from(const "
363
      "YourType&);"
364
  );
365
  return String();
366
}
367
#endif
368

369
#if MUTINY_HAS_ATTRIBUTE(format)
370
#define MUTINY_CHECK_FORMAT(type, format_parameter, other_parameters)          \
371
  __attribute__((format(type, format_parameter, other_parameters)))
372
#else
373
#define MUTINY_CHECK_FORMAT(                                                   \
374
    type, format_parameter, other_parameters                                   \
375
) /* type, format_parameter, other_parameters */
376
#endif
377
/**
378
 * @brief Format a string using `printf`-style @p format and variadic
379
 *        arguments.
380
 */
381
MUTINY_EXPORT String string_from_format(
382
    const char* format,
383
    ...
384
) MUTINY_CHECK_FORMAT(MUTINY_CHECK_FORMAT_TYPE, 1, 2);
385

386
/** @brief Format a string using `printf`-style @p format and a `va_list`. */
387
MUTINY_EXPORT String v_string_from_format(const char* format, va_list args);
388

389
/** @brief Return a hex dump of @p size bytes starting at @p value. */
390
MUTINY_EXPORT String
391
string_from_binary(const unsigned char* value, size_t size);
392

393
/** @brief Return a hex dump of @p size bytes, or "(null)" if null. */
394
MUTINY_EXPORT String
395
string_from_binary_or_null(const unsigned char* value, size_t size);
396

397
/** @brief Return a hex dump of @p size bytes prefixed with the byte count. */
398
MUTINY_EXPORT String
399
string_from_binary_with_size(const unsigned char* value, size_t size);
400

401
/**
402
 * @brief Return a hex dump of @p size bytes prefixed with the byte count, or
403
 *        "(null)" if @p value is null.
404
 */
405
MUTINY_EXPORT String
406
string_from_binary_with_size_or_null(const unsigned char* value, size_t size);
407

408
/** @brief Return the ordinal string for @p number (e.g. "1st", "2nd"). */
409
MUTINY_EXPORT String string_from_ordinal_number(unsigned int number);
410

411
/** @brief Return @p value as a bracketed hex string, e.g. "(0x0000001f)". */
412
MUTINY_EXPORT String brackets_formatted_hex_string_from(int value);
413

414
/** @brief Return @p value as a bracketed hex string, e.g. "(0x0000001f)". */
415
MUTINY_EXPORT String brackets_formatted_hex_string_from(unsigned int value);
416

417
/** @brief Return @p value as a bracketed hex string, e.g. "(0x0000001f)". */
418
MUTINY_EXPORT String brackets_formatted_hex_string_from(long value);
419

420
/** @brief Return @p value as a bracketed hex string, e.g. "(0x0000001f)". */
421
MUTINY_EXPORT String brackets_formatted_hex_string_from(unsigned long value);
422

423
/** @brief Return @p value as a bracketed hex string, e.g. "(0x0000001f)". */
424
MUTINY_EXPORT String brackets_formatted_hex_string_from(long long value);
425

426
/** @brief Return @p value as a bracketed hex string, e.g. "(0x0000001f)". */
427
MUTINY_EXPORT String
428
brackets_formatted_hex_string_from(unsigned long long value);
429

430
/** @brief Return @p value as a bracketed hex string, e.g. "(0x0000001f)". */
431
MUTINY_EXPORT String brackets_formatted_hex_string_from(signed char value);
432

433
/**
434
 * @brief Wrap an already-formatted hex string in brackets
435
 *        (e.g. "(0x0000001f)").
436
 */
437
MUTINY_EXPORT String brackets_formatted_hex_string(const String& hex_string);
438
} // namespace tiny
439
} // namespace mu
440

441
#undef MUTINY_HAS_ATTRIBUTE
442
#undef MUTINY_CHECK_FORMAT_TYPE
443

444
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc