Mir

Merge lp:~alan-griffiths/mir/MirBlob into lp:mir

Proposed by Alan Griffiths on 2015-09-02
Status: Merged
Approved by: Alan Griffiths on 2015-09-18
Approved revision: 2907
Merged at revision: 2946
Proposed branch: lp:~alan-griffiths/mir/MirBlob
Merge into: lp:mir
Diff against target: 477 lines (+396/-0)
9 files modified
include/client/mir_toolkit/client_types.h (+1/-0)
include/client/mir_toolkit/mir_blob.h (+85/-0)
include/test/mir/test/display_config_matchers.h (+3/-0)
src/client/CMakeLists.txt (+1/-0)
src/client/mir_blob.cpp (+229/-0)
src/client/symbols.map (+10/-0)
tests/acceptance-tests/CMakeLists.txt (+1/-0)
tests/acceptance-tests/test_mirblob.cpp (+58/-0)
tests/mir_test/display_config_matchers.cpp (+8/-0)
To merge this branch: bzr merge lp:~alan-griffiths/mir/MirBlob
Reviewer Review Type Date Requested Status
Gerry Boland 2015-09-10 Approve on 2015-09-18
PS Jenkins bot continuous-integration Approve on 2015-09-16
Andreas Pokorny (community) Approve on 2015-09-14
Alexandros Frantzis (community) 2015-09-02 Abstain on 2015-09-10
Review via email: mp+269949@code.launchpad.net

Commit Message

client API: Add MirBlob - a tool for serializing and deserializing data. Initially just MirDisplayConfiguration

Description of the Change

client API: Add MirBlob - a tool for serializing and deserializing data. Initially just MirDisplayConfiguration

To post a comment you must log in.
Alexandros Frantzis (afrantzis) wrote :

Looks good code-wise, but I have a few concerns about the general approach. I think it should be up to the users to serialize the data in a way that's convenient for their use case.

By providing the serialization ourselves, we are burdening Mir with complexity and responsibilities that I am not convinced belong there. For example, we are effectively promising that mir_blob_to_display_configuration() will remain backwards compatible (i.e., it can decode blobs from previous versions) forever, since with our opaque serialization scheme there is no upgrade/transition path that doesn't break the system.

Furthermore, I don't like that we are enticing users to use a binary, opaque serialization scheme, instead of a textual/editable one. Of course, they can always choose to ignore our functions and do their own serialization, but the lure of the dark side may be difficult to resist :)

Bottom line: I understand that shells may find this useful, but I don't think the convenience is worth the extra burden on the Mir side.

review: Abstain
Alan Griffiths (alan-griffiths) wrote :

Well, we already have the burden of marshalling display configurations for IPC and the protobuf handlers we use are able to provide a lot of the compatibility support you mention.

While there are costs, the alternative is that the display configuration structs get locked in even more tightly to user code - making any changes there (scale anyone?) more risky.

Andreas Pokorny (andreas-pokorny) wrote :

Compared to our clients mirserver is better suited to keep the blob format compatible or even migrate it when versioned. I never looked how protobuf encodes it, is the current format suited for that? I would have expected some version info..

review: Needs Information
Alan Griffiths (alan-griffiths) wrote :

> Compared to our clients mirserver is better suited to keep the blob format
> compatible or even migrate it when versioned. I never looked how protobuf
> encodes it, is the current format suited for that? I would have expected some
> version info..

Protobuf allows us to mark fields as "optional" and test for their existence. When updating this buffer definition we already follow the guidelines for backwards compatibility[1], so I don't this code is a big overhead.

[1] https://developers.google.com/protocol-buffers/docs/cpptutorial?hl=en#extending-a-protocol-buffer

Alexandros Frantzis (afrantzis) wrote :

> Protobuf allows us to mark fields as "optional" and test for their existence. When updating this buffer definition we already follow the guidelines for backwards compatibility[1], so I don't this code is a big overhead.

This will work, as long as we stick to protobuf, which is a technology that we may want to replace in the future (at least on the IPC side). We can keep depending on it just for this use case, but perhaps that's an overkill.

Alan Griffiths (alan-griffiths) wrote :

> > Protobuf allows us to mark fields as "optional" and test for their
> existence. When updating this buffer definition we already follow the
> guidelines for backwards compatibility[1], so I don't this code is a big
> overhead.
>
> This will work, as long as we stick to protobuf, which is a technology that we
> may want to replace in the future (at least on the IPC side). We can keep
> depending on it just for this use case, but perhaps that's an overkill.

That's true but, while we're speculating about hypothetical changes:

1. we could reinstate and move to the Binder based transport we used to have as Binder is now in all kernels we target.

2. we could drop the client API in favour of a Wayland based protocol.

In the first case we can stick with protobuf, in the second, the structure marshaled by this MP becomes irrelevant.

I suggest this is good enough for now and we can deal with "migration" if the need ever occurs.

Andreas Pokorny (andreas-pokorny) wrote :

ok

review: Approve
Gerry Boland (gerboland) wrote :

Does this need to be built into Mir directly? Could it be a helper library that is Mir data structure aware?

If it serializes settings, it is logical to expect that not just the shell would want to edit those settings.

I'm also interested in the human readability of this blob. I'd rather not see us introducing yet another binary format, especially one based on an internally-used library. It could be JSON or XML or something simple.

Alan Griffiths (alan-griffiths) wrote :

> Does this need to be built into Mir directly? Could it be a helper library
> that is Mir data structure aware?

What advantage would there be to separating this into a new helper library? It shares code with other functions in libmirclient.

> If it serializes settings, it is logical to expect that not just the shell
> would want to edit those settings.

It is logical that serialization is available to the same code that can (already) edit display configurations through the client API.

> I'm also interested in the human readability of this blob. I'd rather not see
> us introducing yet another binary format, especially one based on an
> internally-used library. It could be JSON or XML or something simple.

I'd not realised human readability was a requirement, OTOH parsing JSON or XML would introduce a new dependency.

Gerry Boland (gerboland) wrote :

> > Does this need to be built into Mir directly? Could it be a helper library
> > that is Mir data structure aware?
>
> What advantage would there be to separating this into a new helper library? It
> shares code with other functions in libmirclient.

You implying that this API will be available in libmirclient, so any client can serialize/deserialize?

> > If it serializes settings, it is logical to expect that not just the shell
> > would want to edit those settings.
>
> It is logical that serialization is available to the same code that can
> (already) edit display configurations through the client API.

Above question will clarify that for me.

> > I'm also interested in the human readability of this blob. I'd rather not
> see
> > us introducing yet another binary format, especially one based on an
> > internally-used library. It could be JSON or XML or something simple.
>
> I'd not realised human readability was a requirement, OTOH parsing JSON or XML
> would introduce a new dependency.

Interested, not requiring. There are advantages to human readability of configuration files. It's not my call to say if we should make that a requirement, but I would like it considered.

As the API consumer, I'm perfectly happy.

Alan Griffiths (alan-griffiths) wrote :

> > > Does this need to be built into Mir directly? Could it be a helper library
> > > that is Mir data structure aware?
> >
> > What advantage would there be to separating this into a new helper library?
> It
> > shares code with other functions in libmirclient.
>
> You implying that this API will be available in libmirclient, so any client
> can serialize/deserialize?

Yes. Were you wanting something different?

lp:~alan-griffiths/mir/MirBlob updated on 2015-09-16
2906. By Alan Griffiths on 2015-09-16

abort on bad data

2907. By Alan Griffiths on 2015-09-16

merge lp:mir

Gerry Boland (gerboland) wrote :

> > > > Does this need to be built into Mir directly? Could it be a helper
> library
> > > > that is Mir data structure aware?
> > >
> > > What advantage would there be to separating this into a new helper
> library?
> > It
> > > shares code with other functions in libmirclient.
> >
> > You implying that this API will be available in libmirclient, so any client
> > can serialize/deserialize?
>
> Yes. Were you wanting something different?

No, that's fine.

Gerry Boland (gerboland) wrote :

I'm ok with this. Still wary about the binary format, but can deal with that if we need to later

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/client/mir_toolkit/client_types.h'
2--- include/client/mir_toolkit/client_types.h 2015-07-25 08:10:48 +0000
3+++ include/client/mir_toolkit/client_types.h 2015-09-16 16:41:31 +0000
4@@ -44,6 +44,7 @@
5 typedef struct MirPromptSession MirPromptSession;
6 typedef struct MirBufferStream MirBufferStream;
7 typedef struct MirPersistentId MirPersistentId;
8+typedef struct MirBlob MirBlob;
9
10 /**
11 * Returned by asynchronous functions. Must not be free'd by
12
13=== added file 'include/client/mir_toolkit/mir_blob.h'
14--- include/client/mir_toolkit/mir_blob.h 1970-01-01 00:00:00 +0000
15+++ include/client/mir_toolkit/mir_blob.h 2015-09-16 16:41:31 +0000
16@@ -0,0 +1,85 @@
17+/*
18+ * Copyright © 2015 Canonical Ltd.
19+ *
20+ * This program is free software: you can redistribute it and/or modify it
21+ * under the terms of the GNU Lesser General Public License version 3,
22+ * as published by the Free Software Foundation.
23+ *
24+ * This program is distributed in the hope that it will be useful,
25+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
26+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27+ * GNU Lesser General Public License for more details.
28+ *
29+ * You should have received a copy of the GNU Lesser General Public License
30+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
31+ *
32+ */
33+
34+#ifndef MIR_TOOLKIT_MIR_BLOB_H_
35+#define MIR_TOOLKIT_MIR_BLOB_H_
36+
37+#include <mir_toolkit/client_types.h>
38+
39+#ifdef __cplusplus
40+/**
41+ * \addtogroup mir_toolkit
42+ * @{
43+ */
44+extern "C" {
45+#endif
46+
47+/**
48+ * Create a blob from a display configuration
49+ *
50+ * \param [in] configuration The display configuration
51+ * \return A blob
52+ */
53+MirBlob* mir_blob_from_display_configuration(MirDisplayConfiguration* configuration);
54+
55+/**
56+ * Create a blob from a buffer.
57+ * \note this does not copy the data, the buffer is assumed to be available
58+ * until the blob is released.
59+ *
60+ * \param [in] buffer the buffer
61+ * \param [in] buffer_size the buffer size
62+ * \return A blob
63+ */
64+MirBlob* mir_blob_onto_buffer(void const* buffer, size_t buffer_size);
65+
66+/**
67+ * Create a blob from a display configuration
68+ *
69+ * \warning will abort() if the blob doesn't represent a meaningful display configuration
70+ *
71+ * \param [in] blob The blob
72+ * \return A display configuration
73+ */
74+MirDisplayConfiguration* mir_blob_to_display_configuration(MirBlob* blob);
75+
76+/**
77+ * Get the size of a blob
78+ * \param [in] blob The blob
79+ * \return the size
80+ */
81+size_t mir_blob_size(MirBlob* blob);
82+
83+/**
84+ * Get the data of a blob
85+ * \param [in] blob The blob
86+ * \return the data
87+ */
88+void const* mir_blob_data(MirBlob* blob);
89+
90+/**
91+ * Release a blob object
92+ * \param [in] blob The blob
93+ */
94+void mir_blob_release(MirBlob* blob);
95+
96+#ifdef __cplusplus
97+}
98+/**@}*/
99+#endif
100+
101+#endif /* MIR_TOOLKIT_MIR_BLOB_H_ */
102
103=== modified file 'include/test/mir/test/display_config_matchers.h'
104--- include/test/mir/test/display_config_matchers.h 2015-09-08 03:25:06 +0000
105+++ include/test/mir/test/display_config_matchers.h 2015-09-16 16:41:31 +0000
106@@ -63,6 +63,9 @@
107 bool compare_display_configurations(protobuf::DisplayConfiguration const& protobuf_config,
108 graphics::DisplayConfiguration const& display_config);
109
110+bool compare_display_configurations(MirDisplayConfiguration const* client_config1,
111+ MirDisplayConfiguration const* client_config2);
112+
113 bool compare_display_configurations(MirDisplayConfiguration const& client_config,
114 protobuf::DisplayConfiguration const& protobuf_config);
115
116
117=== modified file 'src/client/CMakeLists.txt'
118--- src/client/CMakeLists.txt 2015-08-12 06:37:54 +0000
119+++ src/client/CMakeLists.txt 2015-09-16 16:41:31 +0000
120@@ -45,6 +45,7 @@
121 error_connections.cpp
122 event.cpp
123 event_printer.cpp
124+ mir_blob.cpp
125 mir_connection.cpp
126 mir_connection_api.cpp
127 mir_wait_handle.cpp
128
129=== added file 'src/client/mir_blob.cpp'
130--- src/client/mir_blob.cpp 1970-01-01 00:00:00 +0000
131+++ src/client/mir_blob.cpp 2015-09-16 16:41:31 +0000
132@@ -0,0 +1,229 @@
133+/*
134+ * Copyright © 2015 Canonical Ltd.
135+ *
136+ * This program is free software: you can redistribute it and/or modify it
137+ * under the terms of the GNU Lesser General Public License version 3,
138+ * as published by the Free Software Foundation.
139+ *
140+ * This program is distributed in the hope that it will be useful,
141+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
142+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
143+ * GNU Lesser General Public License for more details.
144+ *
145+ * You should have received a copy of the GNU Lesser General Public License
146+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
147+ *
148+ * Authored by: Alan Griffiths <alan@octopull.co.uk>
149+ */
150+
151+#include "mir_toolkit/mir_blob.h"
152+#include "mir_protobuf.pb.h"
153+
154+#include "mir/uncaught.h"
155+
156+namespace mp = mir::protobuf;
157+
158+struct MirBlob
159+{
160+ virtual size_t size() const = 0;
161+ virtual void const* data() const = 0;
162+
163+ virtual ~MirBlob() = default;
164+};
165+
166+namespace
167+{
168+struct MirManagedBlob : MirBlob
169+{
170+
171+ size_t size() const override { return size_; }
172+ void const* data() const override { return data_; }
173+ google::protobuf::uint8* data() { return data_; }
174+
175+ size_t const size_;
176+ google::protobuf::uint8* const data_;
177+
178+ MirManagedBlob(size_t const size) : size_{size}, data_{new google::protobuf::uint8[size]} {}
179+ ~MirManagedBlob() { delete[] data_; }
180+};
181+
182+struct MirUnmanagedBlob : MirBlob
183+{
184+ size_t size() const override { return size_; }
185+ void const* data() const override { return data_; }
186+
187+ size_t const size_;
188+ void const* const data_;
189+
190+ MirUnmanagedBlob(size_t const size, void const* data) : size_{size}, data_{data} {}
191+};
192+}
193+
194+
195+MirBlob* mir_blob_from_display_configuration(MirDisplayConfiguration* configuration)
196+try
197+{
198+ mp::DisplayConfiguration protobuf_config;
199+
200+ for (auto const* card = configuration->cards; card != configuration->cards+configuration->num_cards; ++card)
201+ {
202+ auto protobuf_card = protobuf_config.add_display_card();
203+ protobuf_card->set_card_id(card->card_id);
204+ protobuf_card->set_max_simultaneous_outputs(card->max_simultaneous_outputs);
205+ }
206+
207+ for (auto const* output = configuration->outputs;
208+ output != configuration->outputs+configuration->num_outputs;
209+ ++output)
210+ {
211+ auto protobuf_output = protobuf_config.add_display_output();
212+
213+ protobuf_output->set_output_id(output->output_id);
214+ protobuf_output->set_card_id(output->card_id);
215+ protobuf_output->set_type(output->type);
216+
217+ for (auto const* format = output->output_formats;
218+ format != output->output_formats+output->num_output_formats;
219+ ++format)
220+ {
221+ protobuf_output->add_pixel_format(*format);
222+ }
223+
224+ for (auto const* mode = output->modes;
225+ mode != output->modes+output->num_modes;
226+ ++mode)
227+ {
228+ auto protobuf_output_mode = protobuf_output->add_mode();
229+ protobuf_output_mode->set_horizontal_resolution(mode->horizontal_resolution);
230+ protobuf_output_mode->set_vertical_resolution(mode->vertical_resolution);
231+ protobuf_output_mode->set_refresh_rate(mode->refresh_rate);
232+ }
233+
234+ protobuf_output->set_preferred_mode(output->preferred_mode);
235+
236+ protobuf_output->set_physical_width_mm(output->physical_width_mm);
237+ protobuf_output->set_physical_height_mm(output->physical_height_mm);
238+
239+ protobuf_output->set_connected(output->connected);
240+ protobuf_output->set_used(output->used);
241+ protobuf_output->set_position_x(output->position_x);
242+ protobuf_output->set_position_y(output->position_y);
243+ protobuf_output->set_current_mode(output->current_mode);
244+ protobuf_output->set_current_format(output->current_format);
245+ protobuf_output->set_power_mode(output->power_mode);
246+ protobuf_output->set_orientation(output->orientation);
247+ }
248+
249+ auto blob = std::make_unique<MirManagedBlob>(static_cast<size_t>(protobuf_config.ByteSize()));
250+
251+ protobuf_config.SerializeWithCachedSizesToArray(blob->data());
252+
253+ return blob.release();
254+}
255+catch (std::exception const& x)
256+{
257+ MIR_LOG_UNCAUGHT_EXCEPTION(x);
258+ return nullptr;
259+}
260+
261+MirBlob* mir_blob_onto_buffer(void const* buffer, size_t buffer_size)
262+try
263+{
264+ return new MirUnmanagedBlob{buffer_size, buffer};
265+}
266+catch (std::exception const& x)
267+{
268+ MIR_LOG_UNCAUGHT_EXCEPTION(x);
269+ return nullptr;
270+}
271+
272+MirDisplayConfiguration* mir_blob_to_display_configuration(MirBlob* blob)
273+try
274+{
275+ mp::DisplayConfiguration protobuf_config;
276+
277+ protobuf_config.ParseFromArray(mir_blob_data(blob), mir_blob_size(blob));
278+
279+ auto new_config = new MirDisplayConfiguration;
280+
281+ new_config->num_cards = protobuf_config.display_card_size();
282+ new_config->cards = new MirDisplayCard[new_config->num_cards];
283+
284+ for (auto i = 0u; i != new_config->num_cards; ++i)
285+ {
286+ auto const& protobuf_card = protobuf_config.display_card(i);
287+ auto& card = new_config->cards[i];
288+ card.card_id = protobuf_card.card_id();
289+ card.max_simultaneous_outputs = protobuf_card.max_simultaneous_outputs();
290+ }
291+
292+ new_config->num_outputs = protobuf_config.display_output_size();
293+ new_config->outputs = new MirDisplayOutput[new_config->num_outputs];
294+
295+ for (auto i = 0u; i != new_config->num_outputs; ++i)
296+ {
297+ auto const& protobuf_output = protobuf_config.display_output(i);
298+ auto& output = new_config->outputs[i];
299+
300+ output.output_id = protobuf_output.output_id();
301+ output.card_id = protobuf_output.card_id();
302+ output.type = static_cast<MirDisplayOutputType>(protobuf_output.type());
303+
304+ output.num_output_formats = protobuf_output.pixel_format_size();
305+ output.output_formats = new MirPixelFormat[output.num_output_formats];
306+
307+ output.num_modes = protobuf_output.mode_size();
308+ output.modes = new MirDisplayMode[output.num_modes];
309+
310+ for (auto i = 0u; i != output.num_output_formats; ++i)
311+ {
312+ output.output_formats[i] = static_cast<MirPixelFormat>(protobuf_output.pixel_format(i));
313+ }
314+
315+ for (auto i = 0u; i != output.num_modes; ++i)
316+ {
317+ auto const& protobuf_mode = protobuf_output.mode(i);
318+ auto& mode = output.modes[i];
319+
320+ mode.horizontal_resolution = protobuf_mode.horizontal_resolution();
321+ mode.vertical_resolution = protobuf_mode.vertical_resolution();
322+ mode.refresh_rate = protobuf_mode.refresh_rate();
323+ }
324+
325+ output.preferred_mode = protobuf_output.preferred_mode();
326+
327+ output.physical_width_mm = protobuf_output.physical_width_mm();
328+ output.physical_height_mm = protobuf_output.physical_height_mm();
329+
330+ output.connected = protobuf_output.connected();
331+ output.used = protobuf_output.used();
332+ output.position_x = protobuf_output.position_x();
333+ output.position_y = protobuf_output.position_y();
334+ output.current_mode = protobuf_output.current_mode();
335+ output.current_format = static_cast<MirPixelFormat>(protobuf_output.current_format());
336+ output.orientation = static_cast<MirOrientation>(protobuf_output.orientation());
337+ output.power_mode = static_cast<MirPowerMode>(protobuf_output.power_mode());
338+ }
339+
340+ return new_config;
341+}
342+catch (std::exception const& x)
343+{
344+ MIR_LOG_UNCAUGHT_EXCEPTION(x);
345+ abort();
346+}
347+
348+size_t mir_blob_size(MirBlob* blob)
349+{
350+ return blob->size();
351+}
352+
353+void const* mir_blob_data(MirBlob* blob)
354+{
355+ return blob->data();
356+}
357+
358+void mir_blob_release(MirBlob* blob)
359+{
360+ delete blob;
361+}
362
363=== modified file 'src/client/symbols.map'
364--- src/client/symbols.map 2015-09-09 03:13:35 +0000
365+++ src/client/symbols.map 2015-09-16 16:41:31 +0000
366@@ -182,6 +182,16 @@
367 local: *;
368 } MIR_CLIENT_9.1;
369
370+MIR_CLIENT_9v17 {
371+ mir_blob_from_display_configuration;
372+ mir_blob_size;
373+ mir_blob_data;
374+ mir_blob_release;
375+ mir_blob_onto_buffer;
376+ mir_blob_to_display_configuration;
377+ mir_blob_release;
378+} MIR_CLIENT_9.2;
379+
380 MIR_CLIENT_DETAIL_9 {
381 global:
382 extern "C++" {
383
384=== modified file 'tests/acceptance-tests/CMakeLists.txt'
385--- tests/acceptance-tests/CMakeLists.txt 2015-09-09 18:59:38 +0000
386+++ tests/acceptance-tests/CMakeLists.txt 2015-09-16 16:41:31 +0000
387@@ -26,6 +26,7 @@
388 test_server_shutdown.cpp
389 test_client_focus_notification.cpp
390 test_client_authorization.cpp
391+ test_mirblob.cpp
392 test_nested_mir.cpp
393 test_nested_input.cpp
394 test_display_configuration.cpp
395
396=== added file 'tests/acceptance-tests/test_mirblob.cpp'
397--- tests/acceptance-tests/test_mirblob.cpp 1970-01-01 00:00:00 +0000
398+++ tests/acceptance-tests/test_mirblob.cpp 2015-09-16 16:41:31 +0000
399@@ -0,0 +1,58 @@
400+/*
401+ * Copyright © 2015 Canonical Ltd.
402+ *
403+ * This program is free software: you can redistribute it and/or modify it
404+ * under the terms of the GNU General Public License version 3,
405+ * as published by the Free Software Foundation.
406+ *
407+ * This program is distributed in the hope that it will be useful,
408+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
409+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
410+ * GNU General Public License for more details.
411+ *
412+ * You should have received a copy of the GNU General Public License
413+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
414+ *
415+ * Authored by: Alan Griffiths <alan@octopull.co.uk>
416+ */
417+
418+#include "mir_toolkit/mir_blob.h"
419+#include "mir_toolkit/mir_client_library.h"
420+
421+#include "mir_test_framework/connected_client_with_a_surface.h"
422+#include "mir/test/display_config_matchers.h"
423+
424+#include <gmock/gmock.h>
425+#include <gtest/gtest.h>
426+
427+#include <cstring>
428+
429+using MirBlobAPI = mir_test_framework::ConnectedClientWithASurface;
430+using mir::test::DisplayConfigMatches;
431+
432+TEST_F(MirBlobAPI, can_serialize_display_configuration)
433+{
434+ std::vector<uint8_t> buffer;
435+
436+ auto const save_display_config = mir_connection_create_display_config(connection);
437+
438+ {
439+ auto const save_blob = mir_blob_from_display_configuration(save_display_config);
440+
441+ buffer.resize(mir_blob_size(save_blob));
442+ memcpy(buffer.data(), mir_blob_data(save_blob), buffer.size());
443+ mir_blob_release(save_blob);
444+ }
445+
446+ MirDisplayConfiguration* restore_display_config;
447+ {
448+ auto const restore_blob = mir_blob_onto_buffer(buffer.data(), buffer.size());
449+ restore_display_config = mir_blob_to_display_configuration(restore_blob);
450+ mir_blob_release(restore_blob);
451+ }
452+
453+ EXPECT_THAT(save_display_config, DisplayConfigMatches(restore_display_config));
454+
455+ mir_display_config_destroy(restore_display_config);
456+ mir_display_config_destroy(save_display_config);
457+}
458\ No newline at end of file
459
460=== modified file 'tests/mir_test/display_config_matchers.cpp'
461--- tests/mir_test/display_config_matchers.cpp 2015-09-08 03:25:06 +0000
462+++ tests/mir_test/display_config_matchers.cpp 2015-09-16 16:41:31 +0000
463@@ -278,6 +278,14 @@
464 return compare_display_configurations(config1, display_config);
465 }
466
467+bool mt::compare_display_configurations(MirDisplayConfiguration const* client_config1,
468+ MirDisplayConfiguration const* client_config2)
469+{
470+ TestDisplayConfiguration config1{*client_config1};
471+ TestDisplayConfiguration config2{*client_config2};
472+ return compare_display_configurations(config1, config2);
473+}
474+
475 bool mt::compare_display_configurations(MirDisplayConfiguration const& client_config,
476 mp::DisplayConfiguration const& protobuf_config)
477 {

Subscribers

People subscribed via source and target branches