Branch data Line data Source code
1 : : /* GLib testing framework examples and tests
2 : : *
3 : : * Copyright © 2001 Hidetoshi Tajima
4 : : * Copyright © 2001 Ron Steinke
5 : : * Copyright © 2001 Owen Taylor
6 : : * Copyright © 2002 Manish Singh
7 : : * Copyright © 2011 Sjoerd Simons
8 : : * Copyright © 2012 Simon McVittie
9 : : * Copyright © 2013 Stef Walter
10 : : * Copyright © 2005, 2006, 2008, 2012, 2013 Matthias Clasen
11 : : * Copyright © 2020 Endless Mobile, Inc.
12 : : *
13 : : * SPDX-License-Identifier: LGPL-2.1-or-later
14 : : *
15 : : * This library is free software; you can redistribute it and/or
16 : : * modify it under the terms of the GNU Lesser General Public
17 : : * License as published by the Free Software Foundation; either
18 : : * version 2.1 of the License, or (at your option) any later version.
19 : : *
20 : : * This library is distributed in the hope that it will be useful,
21 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 : : * Lesser General Public License for more details.
24 : : *
25 : : * You should have received a copy of the GNU Lesser General
26 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
27 : : *
28 : : * Author: Philip Withnall <withnall@endlessm.com>
29 : : */
30 : :
31 : : #include <glib.h>
32 : : #include <glib/gstdio.h>
33 : :
34 : : static void
35 : 1 : test_small_writes (void)
36 : : {
37 : : GIOChannel *io;
38 : 1 : GIOStatus status = G_IO_STATUS_ERROR;
39 : : guint bytes_remaining;
40 : : gchar tmp;
41 : 1 : GError *local_error = NULL;
42 : :
43 : 1 : io = g_io_channel_new_file ("iochannel-test-outfile", "w", &local_error);
44 : 1 : g_assert_no_error (local_error);
45 : :
46 : 1 : g_io_channel_set_encoding (io, NULL, NULL);
47 : 1 : g_io_channel_set_buffer_size (io, 1022);
48 : :
49 : 1 : bytes_remaining = 2 * g_io_channel_get_buffer_size (io);
50 : 1 : tmp = 0;
51 : :
52 [ + + ]: 2045 : while (bytes_remaining)
53 : : {
54 : 2044 : status = g_io_channel_write_chars (io, &tmp, 1, NULL, NULL);
55 [ - + ]: 2044 : if (status == G_IO_STATUS_ERROR)
56 : 0 : break;
57 [ + - ]: 2044 : if (status == G_IO_STATUS_NORMAL)
58 : 2044 : bytes_remaining--;
59 : : }
60 : :
61 : 1 : g_assert_cmpint (status, ==, G_IO_STATUS_NORMAL);
62 : :
63 : 1 : g_io_channel_unref (io);
64 : 1 : g_remove ("iochannel-test-outfile");
65 : 1 : }
66 : :
67 : : static void
68 : 1 : test_read_write (void)
69 : : {
70 : : GIOChannel *gio_r, *gio_w ;
71 : 1 : GError *local_error = NULL;
72 : : GString *buffer;
73 : : char *filename;
74 : 1 : gint rlength = 0;
75 : 1 : glong wlength = 0;
76 : : gsize length_out;
77 : 1 : const gchar *encoding = "EUC-JP";
78 : : GIOStatus status;
79 : 1 : const gsize buffer_size_bytes = 1024;
80 : :
81 : 1 : filename = g_test_build_filename (G_TEST_DIST, "iochannel-test-infile", NULL);
82 : :
83 : 1 : setbuf (stdout, NULL); /* For debugging */
84 : :
85 : 1 : gio_r = g_io_channel_new_file (filename, "r", &local_error);
86 : 1 : g_assert_no_error (local_error);
87 : :
88 : 1 : gio_w = g_io_channel_new_file ("iochannel-test-outfile", "w", &local_error);
89 : 1 : g_assert_no_error (local_error);
90 : :
91 : 1 : g_io_channel_set_encoding (gio_r, encoding, &local_error);
92 : 1 : g_assert_no_error (local_error);
93 : :
94 : 1 : g_io_channel_set_buffer_size (gio_r, buffer_size_bytes);
95 : :
96 : 1 : status = g_io_channel_set_flags (gio_r, G_IO_FLAG_NONBLOCK, &local_error);
97 [ - + ]: 1 : if (status == G_IO_STATUS_ERROR)
98 : : {
99 : : #ifdef G_OS_WIN32
100 : : g_test_message ("FIXME: not implemented on win32");
101 : : #else
102 : : /* Errors should not happen */
103 : 0 : g_assert_no_error (local_error);
104 : : #endif
105 : 0 : g_clear_error (&local_error);
106 : : }
107 : 1 : buffer = g_string_sized_new (buffer_size_bytes);
108 : :
109 : 5 : while (TRUE)
110 : : {
111 : : do
112 : 6 : status = g_io_channel_read_line_string (gio_r, buffer, NULL, &local_error);
113 [ - + ]: 6 : while (status == G_IO_STATUS_AGAIN);
114 [ + + ]: 6 : if (status != G_IO_STATUS_NORMAL)
115 : 1 : break;
116 : :
117 : 5 : rlength += buffer->len;
118 : :
119 : : do
120 : 5 : status = g_io_channel_write_chars (gio_w, buffer->str, buffer->len,
121 : : &length_out, &local_error);
122 [ - + ]: 5 : while (status == G_IO_STATUS_AGAIN);
123 [ - + ]: 5 : if (status != G_IO_STATUS_NORMAL)
124 : 0 : break;
125 : :
126 : 5 : wlength += length_out;
127 : :
128 : : /* Ensure the whole line was written */
129 : 5 : g_assert_cmpuint (length_out, ==, buffer->len);
130 : :
131 : 5 : g_test_message ("%s", buffer->str);
132 : : g_string_truncate (buffer, 0);
133 : : }
134 : :
135 [ + - - ]: 1 : switch (status)
136 : : {
137 : 1 : case G_IO_STATUS_EOF:
138 : 1 : break;
139 : 0 : case G_IO_STATUS_ERROR:
140 : : /* Errors should not happen */
141 : 0 : g_assert_no_error (local_error);
142 : 0 : g_clear_error (&local_error);
143 : 0 : break;
144 : 0 : default:
145 : : g_assert_not_reached ();
146 : : break;
147 : : }
148 : :
149 : : do
150 : 1 : status = g_io_channel_flush (gio_w, &local_error);
151 [ - + ]: 1 : while (status == G_IO_STATUS_AGAIN);
152 : :
153 [ - + ]: 1 : if (status == G_IO_STATUS_ERROR)
154 : : {
155 : : /* Errors should not happen */
156 : 0 : g_assert_no_error (local_error);
157 : 0 : g_clear_error (&local_error);
158 : : }
159 : :
160 : 1 : g_test_message ("read %d bytes, wrote %ld bytes", rlength, wlength);
161 : :
162 : 1 : g_io_channel_unref (gio_r);
163 : 1 : g_io_channel_unref (gio_w);
164 : :
165 : 1 : test_small_writes ();
166 : :
167 : 1 : g_free (filename);
168 : 1 : g_string_free (buffer, TRUE);
169 : 1 : }
170 : :
171 : : static void
172 : 1 : test_read_line_embedded_nuls (void)
173 : : {
174 : 1 : const guint8 test_data[] = { 'H', 'i', '!', '\0', 'y', 'o', 'u', '\n', ':', ')', '\n' };
175 : : gint fd;
176 : 1 : gchar *filename = NULL;
177 : 1 : GIOChannel *channel = NULL;
178 : 1 : GError *local_error = NULL;
179 : 1 : gchar *line = NULL;
180 : : gsize line_length, terminator_pos;
181 : : GIOStatus status;
182 : :
183 : 1 : g_test_summary ("Test that reading a line containing embedded nuls works "
184 : : "when using non-standard line terminators.");
185 : :
186 : : /* Write out a temporary file. */
187 : 1 : fd = g_file_open_tmp ("glib-test-io-channel-XXXXXX", &filename, &local_error);
188 : 1 : g_assert_no_error (local_error);
189 : 1 : g_close (fd, NULL);
190 : 1 : fd = -1;
191 : :
192 : 1 : g_file_set_contents (filename, (const gchar *) test_data, sizeof (test_data), &local_error);
193 : 1 : g_assert_no_error (local_error);
194 : :
195 : : /* Create the channel. */
196 : 1 : channel = g_io_channel_new_file (filename, "r", &local_error);
197 : 1 : g_assert_no_error (local_error);
198 : :
199 : : /* Only break on newline characters, not nuls.
200 : : * Use length -1 here to exercise glib#2323; the case where length > 0
201 : : * is covered in glib/tests/protocol.c. */
202 : 1 : g_io_channel_set_line_term (channel, "\n", -1);
203 : 1 : g_io_channel_set_encoding (channel, NULL, &local_error);
204 : 1 : g_assert_no_error (local_error);
205 : :
206 : 1 : status = g_io_channel_read_line (channel, &line, &line_length,
207 : : &terminator_pos, &local_error);
208 : 1 : g_assert_no_error (local_error);
209 : 1 : g_assert_cmpint (status, ==, G_IO_STATUS_NORMAL);
210 : 1 : g_assert_cmpuint (line_length, ==, 8);
211 : 1 : g_assert_cmpuint (terminator_pos, ==, 7);
212 : 1 : g_assert_cmpmem (line, line_length, test_data, 8);
213 : :
214 : 1 : g_free (line);
215 : 1 : g_io_channel_unref (channel);
216 : 1 : g_free (filename);
217 : 1 : }
218 : :
219 : : int
220 : 1 : main (int argc,
221 : : char *argv[])
222 : : {
223 : 1 : g_test_init (&argc, &argv, NULL);
224 : :
225 : 1 : g_test_add_func ("/io-channel/read-write", test_read_write);
226 : 1 : g_test_add_func ("/io-channel/read-line/embedded-nuls", test_read_line_embedded_nuls);
227 : :
228 : 1 : return g_test_run ();
229 : : }
|