1 /* GLib testing framework examples and tests
2 * Copyright (C) 2010-2012 Collabora Ltd.
3 * Authors: Xavier Claessens <xclaesse@gmail.com>
4 * Mike Ruprecht <mike.ruprecht@collabora.co.uk>
5 *
6 * SPDX-License-Identifier: LicenseRef-old-glib-tests
7 *
8 * This work is provided "as is"; redistribution and modification
9 * in whole or in part, in any medium, physical or electronic is
10 * permitted without restriction.
11 *
12 * This work is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 *
16 * In no event shall the authors or contributors be liable for any
17 * direct, indirect, incidental, special, exemplary, or consequential
18 * damages (including, but not limited to, procurement of substitute
19 * goods or services; loss of use, data, or profits; or business
20 * interruption) however caused and on any theory of liability, whether
21 * in contract, strict liability, or tort (including negligence or
22 * otherwise) arising in any way out of the use of this software, even
23 * if advised of the possibility of such damage.
24 */
25
26 #include <glib/glib.h>
27 #include <glib/gstdio.h>
28 #include <gio/gio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 typedef enum
33 {
34 TEST_THREADED_NONE = 0,
35 TEST_THREADED_ISTREAM = 1,
36 TEST_THREADED_OSTREAM = 2,
37 TEST_CANCEL = 4,
38 TEST_THREADED_BOTH = TEST_THREADED_ISTREAM | TEST_THREADED_OSTREAM,
39 } TestThreadedFlags;
40
41 typedef struct
42 {
43 GMainLoop *main_loop;
44 const gchar *data;
45 GInputStream *istream;
46 GOutputStream *ostream;
47 TestThreadedFlags flags;
48 gchar *input_path;
49 gchar *output_path;
50 } TestCopyChunksData;
51
52 static void
53 test_copy_chunks_splice_cb (GObject *source,
54 GAsyncResult *res,
55 gpointer user_data)
56 {
57 TestCopyChunksData *data = user_data;
58 gchar *received_data;
59 GError *error = NULL;
60 gssize bytes_spliced;
61
62 bytes_spliced = g_output_stream_splice_finish (G_OUTPUT_STREAM (source),
63 res, &error);
64
65 if (data->flags & TEST_CANCEL)
66 {
67 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
68 g_error_free (error);
69 g_main_loop_quit (data->main_loop);
70 return;
71 }
72
73 g_assert_no_error (error);
74 g_assert_cmpint (bytes_spliced, ==, strlen (data->data));
75
76 if (data->flags & TEST_THREADED_OSTREAM)
77 {
78 gsize length = 0;
79
80 g_file_get_contents (data->output_path, &received_data,
81 &length, &error);
82 g_assert_no_error (error);
83 g_assert_cmpstr (received_data, ==, data->data);
84 g_free (received_data);
85 }
86 else
87 {
88 received_data = g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (data->ostream));
89 g_assert_cmpstr (received_data, ==, data->data);
90 }
91
92 g_assert (g_input_stream_is_closed (data->istream));
93 g_assert (g_output_stream_is_closed (data->ostream));
94
95 if (data->flags & TEST_THREADED_ISTREAM)
96 {
97 g_unlink (data->input_path);
98 g_free (data->input_path);
99 }
100
101 if (data->flags & TEST_THREADED_OSTREAM)
102 {
103 g_unlink (data->output_path);
104 g_free (data->output_path);
105 }
106
107 g_main_loop_quit (data->main_loop);
108 }
109
110 static void
111 test_copy_chunks_start (TestThreadedFlags flags)
112 {
113 TestCopyChunksData data;
114 GError *error = NULL;
115 GCancellable *cancellable = NULL;
116
117 data.main_loop = g_main_loop_new (NULL, FALSE);
118 data.data = "abcdefghijklmnopqrstuvwxyz";
119 data.flags = flags;
120
121 if (data.flags & TEST_CANCEL)
122 {
123 cancellable = g_cancellable_new ();
124 g_cancellable_cancel (cancellable);
125 }
126
127 if (data.flags & TEST_THREADED_ISTREAM)
128 {
129 GFile *file;
130 GFileIOStream *stream;
131
132 file = g_file_new_tmp ("test-inputXXXXXX", &stream, &error);
133 g_assert_no_error (error);
134 g_object_unref (stream);
135 data.input_path = g_file_get_path (file);
136 g_file_set_contents (data.input_path,
137 data.data, strlen (data.data),
138 &error);
139 g_assert_no_error (error);
140 data.istream = G_INPUT_STREAM (g_file_read (file, NULL, &error));
141 g_assert_no_error (error);
142 g_object_unref (file);
143 }
144 else
145 {
146 data.istream = g_memory_input_stream_new_from_data (data.data, -1, NULL);
147 }
148
149 if (data.flags & TEST_THREADED_OSTREAM)
150 {
151 GFile *file;
152 GFileIOStream *stream;
153
154 file = g_file_new_tmp ("test-outputXXXXXX", &stream, &error);
155 g_assert_no_error (error);
156 g_object_unref (stream);
157 data.output_path = g_file_get_path (file);
158 data.ostream = G_OUTPUT_STREAM (g_file_replace (file, NULL, FALSE,
159 G_FILE_CREATE_NONE,
160 NULL, &error));
161 g_assert_no_error (error);
162 g_object_unref (file);
163 }
164 else
165 {
166 data.ostream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
167 }
168
169 g_output_stream_splice_async (data.ostream, data.istream,
170 G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
171 G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
172 G_PRIORITY_DEFAULT, cancellable,
173 test_copy_chunks_splice_cb, &data);
174
175 /* We do not hold a ref in data struct, this is to make sure the operation
176 * keeps the iostream objects alive until it finishes
177 */
178 g_object_unref (data.istream);
179 g_object_unref (data.ostream);
180 g_clear_object (&cancellable);
181
182 g_main_loop_run (data.main_loop);
183 g_main_loop_unref (data.main_loop);
184 }
185
186 static void
187 test_copy_chunks (void)
188 {
189 test_copy_chunks_start (TEST_THREADED_NONE);
190 }
191
192 static void
193 test_copy_chunks_threaded_input (void)
194 {
195 test_copy_chunks_start (TEST_THREADED_ISTREAM);
196 }
197
198 static void
199 test_copy_chunks_threaded_output (void)
200 {
201 test_copy_chunks_start (TEST_THREADED_OSTREAM);
202 }
203
204 static void
205 test_copy_chunks_threaded (void)
206 {
207 test_copy_chunks_start (TEST_THREADED_BOTH);
208 }
209
210 static void
211 test_cancelled (void)
212 {
213 test_copy_chunks_start (TEST_THREADED_NONE | TEST_CANCEL);
214 }
215
216 int
217 main (int argc,
218 char *argv[])
219 {
220 g_test_init (&argc, &argv, NULL);
221
222 g_test_add_func ("/async-splice/copy-chunks", test_copy_chunks);
223 g_test_add_func ("/async-splice/copy-chunks-threaded-input",
224 test_copy_chunks_threaded_input);
225 g_test_add_func ("/async-splice/copy-chunks-threaded-output",
226 test_copy_chunks_threaded_output);
227 g_test_add_func ("/async-splice/copy-chunks-threaded",
228 test_copy_chunks_threaded);
229 g_test_add_func ("/async-splice/cancelled",
230 test_cancelled);
231
232 return g_test_run();
233 }