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