5
5
#include < X11/Xatom.h>
6
6
#include < X11/Xlib.h>
7
7
#include < X11/Xutil.h>
8
+ #include < cstddef>
8
9
#include < cstdint>
9
10
#include < string>
10
11
#include < string_view>
12
+ #include < vector>
11
13
12
14
#include " mock.hh"
13
15
@@ -36,6 +38,9 @@ enum x11_property_type {
36
38
37
39
Atom name_to_atom (const char *name);
38
40
const std::string_view atom_to_name (Atom atom);
41
+ size_t format_size (std::size_t format);
42
+ void dump_x11_blob (const std::byte *data, std::size_t format,
43
+ std::size_t length);
39
44
40
45
// / Mutation produced by creating new `Atom`s.
41
46
struct x11_define_atom : public state_change {
@@ -62,29 +67,29 @@ class x11_change_property : public state_change {
62
67
Atom m_type;
63
68
std::size_t m_format;
64
69
set_property_mode m_mode;
65
- const unsigned char * m_data;
70
+ std::vector<std::byte> m_data;
66
71
std::size_t m_element_count;
67
72
68
73
public:
69
74
x11_change_property (Atom property, Atom type, std::size_t format,
70
- set_property_mode mode, const unsigned char *data,
75
+ set_property_mode mode, const std::byte *data,
71
76
std::size_t element_count)
72
77
: m_property(property),
73
78
m_type (type),
74
79
m_format(format),
75
80
m_mode(mode),
76
- m_data(data ),
77
- m_element_count( element_count) {}
81
+ m_element_count(element_count ),
82
+ m_data(std::vector(data, data + format_size(format) * element_count) ) {}
78
83
79
84
static std::string change_name () { return " x11_change_property" ; }
80
85
81
- Atom property () { return m_property; }
82
- std::string_view property_name () { return atom_to_name (m_property); }
83
- Atom type () { return m_type; }
84
- std::string_view type_name () { return atom_to_name (m_type); }
85
- std::size_t format () { return m_format; }
86
- set_property_mode mode () { return m_mode; }
87
- std::string_view mode_name () {
86
+ Atom property () const { return m_property; }
87
+ std::string_view property_name () const { return atom_to_name (m_property); }
88
+ Atom type () const { return m_type; }
89
+ std::string_view type_name () const { return atom_to_name (m_type); }
90
+ std::size_t format () const { return m_format; }
91
+ set_property_mode mode () const { return m_mode; }
92
+ std::string_view mode_name () const {
88
93
switch (m_mode) {
89
94
case mock::set_property_mode::REPLACE:
90
95
return " replace" ;
@@ -96,8 +101,8 @@ class x11_change_property : public state_change {
96
101
return " other" ;
97
102
}
98
103
}
99
- std::size_t element_count () { return m_element_count; }
100
- const unsigned char * const data () { return m_data; }
104
+ std::size_t element_count () const { return m_element_count; }
105
+ const std::byte * data () const { return m_data. data () ; }
101
106
102
107
std::string debug () {
103
108
return debug_format (
@@ -107,26 +112,24 @@ class x11_change_property : public state_change {
107
112
m_element_count);
108
113
}
109
114
};
110
-
111
- template <class T >
112
- struct always_false : std::false_type {};
113
115
} // namespace mock
114
116
117
+ #define REQUIRE_FORMAT_SIZE (format, T ) REQUIRE(format == (sizeof (T) * 8 ))
118
+
115
119
// These are only macros because including Catch2 from mocking causes spurious
116
- // errors.
120
+ // errors. I whish they weren't because they're such a pain to write this way.
117
121
118
122
// Originally a single templated function:
119
123
//
120
124
// template <typename D, const std::size_t Count>
121
125
// const D &expect_x11_data(
122
- // const unsigned char * const data, Atom type, std::size_t format,
126
+ // const std::byte* data, Atom type, std::size_t format,
123
127
// std::size_t element_count
124
128
// ) {...}
125
129
//
126
130
// It is a somewhat large blob, but most of it will be compiled away. The only
127
131
// downside is that lambdas must return owned values.
128
132
129
- #define REQUIRE_FORMAT_SIZE (format, T ) REQUIRE(format == (sizeof (T) * 8 ))
130
133
#define EXPECT_X11_VALUE (data, type, format, element_count, T ) \
131
134
[]() { \
132
135
if constexpr (std::is_same_v<XID, std::uint32_t > && \
@@ -225,6 +228,21 @@ struct always_false : std::false_type {};
225
228
} \
226
229
}()
227
230
231
+ #define _COPY_C_ARRAY_TO_CAST (BaseT, TargetT, Length, source ) \
232
+ [&]() { \
233
+ auto values = reinterpret_cast <const BaseT *>(source); \
234
+ auto result = std::array<TargetT, Length>{}; \
235
+ for (size_t i = 0 ; i < Length; i++) { \
236
+ if constexpr (std::numeric_limits<BaseT>::max () > \
237
+ std::numeric_limits<TargetT>::max ()) { \
238
+ CHECK (values[i] >= std::numeric_limits<TargetT>::min ()); \
239
+ CHECK (values[i] <= std::numeric_limits<TargetT>::max ()); \
240
+ } \
241
+ result[i] = static_cast <TargetT>(values[i]); \
242
+ } \
243
+ return result; \
244
+ }()
245
+
228
246
#define EXPECT_X11_ARRAY (data, type, format, element_count, T, Count ) \
229
247
[&]() { \
230
248
if constexpr (std::is_same_v<XID, std::uint32_t > && \
@@ -244,14 +262,14 @@ struct always_false : std::false_type {};
244
262
} \
245
263
REQUIRE_FORMAT_SIZE (format, std::uint32_t ); \
246
264
REQUIRE (element_count == Count); \
247
- return * reinterpret_cast < const std::array<T , Count> *>( data); \
265
+ return _COPY_C_ARRAY_TO_CAST ( long , std::uint32_t , Count, data); \
248
266
} else if constexpr (std::is_same_v<T, std::uint32_t >) { \
249
267
if (type != mock::x11_property_type::CARDINAL) { \
250
268
FAIL (" expected CARDINAL array; got: " << mock::atom_to_name (type)); \
251
269
} \
252
270
REQUIRE_FORMAT_SIZE (format, std::uint32_t ); \
253
271
REQUIRE (element_count == Count); \
254
- return * reinterpret_cast < const std::array<T , Count> *>( data); \
272
+ return _COPY_C_ARRAY_TO_CAST ( long , std::uint32_t , Count, data); \
255
273
} else if constexpr (std::is_same_v<T, XID>) { \
256
274
if (!(type == mock::x11_property_type::ATOM || \
257
275
type == mock::x11_property_type::BITMAP || \
@@ -266,68 +284,82 @@ struct always_false : std::false_type {};
266
284
} \
267
285
REQUIRE_FORMAT_SIZE (format, XID); \
268
286
REQUIRE (element_count == Count); \
269
- return * reinterpret_cast < const std::array< T, Count> *>( data); \
287
+ return _COPY_C_ARRAY_TO_CAST ( long , T, Count, data); \
270
288
} else if constexpr (std::is_same_v<T, std::int32_t >) { \
271
289
if (type != mock::x11_property_type::INTEGER) { \
272
290
FAIL (" expected INTEGER array; got: " << mock::atom_to_name (type)); \
273
291
} \
274
- REQUIRE_FORMAT_SIZE (format, std::uint32_t ); \
292
+ REQUIRE_FORMAT_SIZE (format, std::int32_t ); \
275
293
REQUIRE (element_count == Count); \
276
- return * reinterpret_cast < const std::array<T , Count> *>( data); \
294
+ return _COPY_C_ARRAY_TO_CAST ( long , std::int32_t , Count, data); \
277
295
} else { \
278
296
throw " unimplemented conversion" ; \
279
297
} \
280
298
}()
281
299
282
- #define EXPECT_X11_VEC (data, type, format, element_count, T ) \
283
- [&]() { \
284
- REQUIRE (sizeof (T) == format); \
285
- if constexpr (std::is_same_v<XID, std::uint32_t > && \
286
- std::is_same_v<T, std::uint32_t >) { \
287
- if (!(type == mock::x11_property_type::ATOM || \
288
- type == mock::x11_property_type::BITMAP || \
289
- type == mock::x11_property_type::CARDINAL || \
290
- type == mock::x11_property_type::PIXMAP || \
291
- type == mock::x11_property_type::COLORMAP || \
292
- type == mock::x11_property_type::CURSOR || \
293
- type == mock::x11_property_type::DRAWABLE || \
294
- type == mock::x11_property_type::FONT || \
295
- type == mock::x11_property_type::VISUALID || \
296
- type == mock::x11_property_type::WINDOW)) { \
297
- FAIL (" expected unsigned long array; got: " \
298
- << mock::atom_to_name (type)); \
299
- } \
300
- REQUIRE_FORMAT_SIZE (format, std::uint32_t ); \
301
- return std::vector<reinterpret_cast <const T *>(data), element_count>; \
302
- } else if constexpr (std::is_same_v<T, std::uint32_t >) { \
303
- if (type != mock::x11_property_type::CARDINAL) { \
304
- FAIL (" expected CARDINAL array; got: " << mock::atom_to_name (type)); \
305
- } \
306
- REQUIRE_FORMAT_SIZE (format, std::uint32_t ); \
307
- return std::vector<reinterpret_cast <const T *>(data), element_count>; \
308
- } else if constexpr (std::is_same_v<T, XID>) { \
309
- if (!(type == mock::x11_property_type::ATOM || \
310
- type == mock::x11_property_type::BITMAP || \
311
- type == mock::x11_property_type::PIXMAP || \
312
- type == mock::x11_property_type::COLORMAP || \
313
- type == mock::x11_property_type::CURSOR || \
314
- type == mock::x11_property_type::DRAWABLE || \
315
- type == mock::x11_property_type::FONT || \
316
- type == mock::x11_property_type::VISUALID || \
317
- type == mock::x11_property_type::WINDOW)) { \
318
- FAIL (" expected XID data; got: " << mock::atom_to_name (type)); \
319
- } \
320
- REQUIRE_FORMAT_SIZE (format, XID); \
321
- return std::vector<reinterpret_cast <const T *>(data), element_count>; \
322
- } else if constexpr (std::is_same_v<T, std::int32_t >) { \
323
- if (type != mock::x11_property_type::INTEGER) { \
324
- FAIL (" expected INTEGER array; got: " << mock::atom_to_name (type)); \
325
- } \
326
- REQUIRE_FORMAT_SIZE (format, std::int32_t ); \
327
- return std::vector<reinterpret_cast <const T *>(data), element_count>; \
328
- } else { \
329
- throw " unimplemented conversion" ; \
330
- } \
300
+ #define _COPY_C_ARRAY_TO_VEC (BaseT, TargetT, source, length ) \
301
+ [&]() { \
302
+ auto values = reinterpret_cast <const BaseT *>(source); \
303
+ auto result = std::vector<TargetT>(length); \
304
+ for (const BaseT *it = values; it < values + length; it++) { \
305
+ if constexpr (std::numeric_limits<BaseT>::max () > \
306
+ std::numeric_limits<TargetT>::max ()) { \
307
+ CHECK (*it >= std::numeric_limits<TargetT>::min ()); \
308
+ CHECK (*it <= std::numeric_limits<TargetT>::max ()); \
309
+ } \
310
+ result.push_back (*it); \
311
+ } \
312
+ return result; \
313
+ }()
314
+
315
+ #define EXPECT_X11_VEC (data, type, format, element_count, T ) \
316
+ [&]() { \
317
+ if constexpr (std::is_same_v<XID, std::uint32_t > && \
318
+ std::is_same_v<T, std::uint32_t >) { \
319
+ if (!(type == mock::x11_property_type::ATOM || \
320
+ type == mock::x11_property_type::BITMAP || \
321
+ type == mock::x11_property_type::CARDINAL || \
322
+ type == mock::x11_property_type::PIXMAP || \
323
+ type == mock::x11_property_type::COLORMAP || \
324
+ type == mock::x11_property_type::CURSOR || \
325
+ type == mock::x11_property_type::DRAWABLE || \
326
+ type == mock::x11_property_type::FONT || \
327
+ type == mock::x11_property_type::VISUALID || \
328
+ type == mock::x11_property_type::WINDOW)) { \
329
+ FAIL (" expected unsigned long array; got: " \
330
+ << mock::atom_to_name (type)); \
331
+ } \
332
+ REQUIRE_FORMAT_SIZE (format, std::uint32_t ); \
333
+ return _COPY_C_ARRAY_TO_VEC (long , std::uint32_t , data, element_count); \
334
+ } else if constexpr (std::is_same_v<T, std::uint32_t >) { \
335
+ if (type != mock::x11_property_type::CARDINAL) { \
336
+ FAIL (" expected CARDINAL array; got: " << mock::atom_to_name (type)); \
337
+ } \
338
+ REQUIRE_FORMAT_SIZE (format, std::uint32_t ); \
339
+ return _COPY_C_ARRAY_TO_VEC (long , std::uint32_t , data, element_count); \
340
+ } else if constexpr (std::is_same_v<T, XID>) { \
341
+ if (!(type == mock::x11_property_type::ATOM || \
342
+ type == mock::x11_property_type::BITMAP || \
343
+ type == mock::x11_property_type::PIXMAP || \
344
+ type == mock::x11_property_type::COLORMAP || \
345
+ type == mock::x11_property_type::CURSOR || \
346
+ type == mock::x11_property_type::DRAWABLE || \
347
+ type == mock::x11_property_type::FONT || \
348
+ type == mock::x11_property_type::VISUALID || \
349
+ type == mock::x11_property_type::WINDOW)) { \
350
+ FAIL (" expected XID data; got: " << mock::atom_to_name (type)); \
351
+ } \
352
+ REQUIRE_FORMAT_SIZE (format, XID); \
353
+ return _COPY_C_ARRAY_TO_VEC (long , XID, data, element_count); \
354
+ } else if constexpr (std::is_same_v<T, std::int32_t >) { \
355
+ if (type != mock::x11_property_type::INTEGER) { \
356
+ FAIL (" expected INTEGER array; got: " << mock::atom_to_name (type)); \
357
+ } \
358
+ REQUIRE_FORMAT_SIZE (format, std::int32_t ); \
359
+ return _COPY_C_ARRAY_TO_VEC (long , std::int32_t , data, element_count); \
360
+ } else { \
361
+ throw " unimplemented conversion" ; \
362
+ } \
331
363
}()
332
364
333
365
#endif /* X11_MOCK_HH */
0 commit comments