stdio_test.cpp revision e77f38f14a01be7d0e1f2ca055047579ec42ffb7
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <gtest/gtest.h>
18
19#include <errno.h>
20#include <limits.h>
21#include <math.h>
22#include <stdio.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <unistd.h>
26#include <wchar.h>
27#include <locale.h>
28
29#include "TemporaryFile.h"
30
31TEST(stdio, tmpfile_fileno_fprintf_rewind_fgets) {
32  FILE* fp = tmpfile();
33  ASSERT_TRUE(fp != NULL);
34
35  int fd = fileno(fp);
36  ASSERT_NE(fd, -1);
37
38  struct stat sb;
39  int rc = fstat(fd, &sb);
40  ASSERT_NE(rc, -1);
41  ASSERT_EQ(sb.st_mode & 0777, 0600U);
42
43  rc = fprintf(fp, "hello\n");
44  ASSERT_EQ(rc, 6);
45
46  rewind(fp);
47
48  char buf[16];
49  char* s = fgets(buf, sizeof(buf), fp);
50  ASSERT_TRUE(s != NULL);
51  ASSERT_STREQ("hello\n", s);
52
53  fclose(fp);
54}
55
56TEST(stdio, getdelim) {
57  FILE* fp = tmpfile();
58  ASSERT_TRUE(fp != NULL);
59
60  const char* line_written = "This  is a test";
61  int rc = fprintf(fp, "%s", line_written);
62  ASSERT_EQ(rc, static_cast<int>(strlen(line_written)));
63
64  rewind(fp);
65
66  char* word_read = NULL;
67  size_t allocated_length = 0;
68
69  const char* expected[] = { "This ", " ", "is ", "a ", "test" };
70  for (size_t i = 0; i < 5; ++i) {
71    ASSERT_FALSE(feof(fp));
72    ASSERT_EQ(getdelim(&word_read, &allocated_length, ' ', fp), static_cast<int>(strlen(expected[i])));
73    ASSERT_GE(allocated_length, strlen(expected[i]));
74    ASSERT_STREQ(word_read, expected[i]);
75  }
76  // The last read should have set the end-of-file indicator for the stream.
77  ASSERT_TRUE(feof(fp));
78  clearerr(fp);
79
80  // getdelim returns -1 but doesn't set errno if we're already at EOF.
81  // It should set the end-of-file indicator for the stream, though.
82  errno = 0;
83  ASSERT_EQ(getdelim(&word_read, &allocated_length, ' ', fp), -1);
84  ASSERT_EQ(0, errno);
85  ASSERT_TRUE(feof(fp));
86
87  free(word_read);
88  fclose(fp);
89}
90
91TEST(stdio, getdelim_invalid) {
92  FILE* fp = tmpfile();
93  ASSERT_TRUE(fp != NULL);
94
95  char* buffer = NULL;
96  size_t buffer_length = 0;
97
98  // The first argument can't be NULL.
99  errno = 0;
100  ASSERT_EQ(getdelim(NULL, &buffer_length, ' ', fp), -1);
101  ASSERT_EQ(EINVAL, errno);
102
103  // The second argument can't be NULL.
104  errno = 0;
105  ASSERT_EQ(getdelim(&buffer, NULL, ' ', fp), -1);
106  ASSERT_EQ(EINVAL, errno);
107
108  // The underlying fd can't be closed.
109  ASSERT_EQ(0, close(fileno(fp)));
110  errno = 0;
111  ASSERT_EQ(getdelim(&buffer, &buffer_length, ' ', fp), -1);
112  ASSERT_EQ(EBADF, errno);
113  fclose(fp);
114}
115
116TEST(stdio, getline) {
117  FILE* fp = tmpfile();
118  ASSERT_TRUE(fp != NULL);
119
120  const char* line_written = "This is a test for getline\n";
121  const size_t line_count = 5;
122
123  for (size_t i = 0; i < line_count; ++i) {
124    int rc = fprintf(fp, "%s", line_written);
125    ASSERT_EQ(rc, static_cast<int>(strlen(line_written)));
126  }
127
128  rewind(fp);
129
130  char* line_read = NULL;
131  size_t allocated_length = 0;
132
133  size_t read_line_count = 0;
134  ssize_t read_char_count;
135  while ((read_char_count = getline(&line_read, &allocated_length, fp)) != -1) {
136    ASSERT_EQ(read_char_count, static_cast<int>(strlen(line_written)));
137    ASSERT_GE(allocated_length, strlen(line_written));
138    ASSERT_STREQ(line_read, line_written);
139    ++read_line_count;
140  }
141  ASSERT_EQ(read_line_count, line_count);
142
143  // The last read should have set the end-of-file indicator for the stream.
144  ASSERT_TRUE(feof(fp));
145  clearerr(fp);
146
147  // getline returns -1 but doesn't set errno if we're already at EOF.
148  // It should set the end-of-file indicator for the stream, though.
149  errno = 0;
150  ASSERT_EQ(getline(&line_read, &allocated_length, fp), -1);
151  ASSERT_EQ(0, errno);
152  ASSERT_TRUE(feof(fp));
153
154  free(line_read);
155  fclose(fp);
156}
157
158TEST(stdio, getline_invalid) {
159  FILE* fp = tmpfile();
160  ASSERT_TRUE(fp != NULL);
161
162  char* buffer = NULL;
163  size_t buffer_length = 0;
164
165  // The first argument can't be NULL.
166  errno = 0;
167  ASSERT_EQ(getline(NULL, &buffer_length, fp), -1);
168  ASSERT_EQ(EINVAL, errno);
169
170  // The second argument can't be NULL.
171  errno = 0;
172  ASSERT_EQ(getline(&buffer, NULL, fp), -1);
173  ASSERT_EQ(EINVAL, errno);
174
175  // The underlying fd can't be closed.
176  ASSERT_EQ(0, close(fileno(fp)));
177  errno = 0;
178  ASSERT_EQ(getline(&buffer, &buffer_length, fp), -1);
179  ASSERT_EQ(EBADF, errno);
180  fclose(fp);
181}
182
183TEST(stdio, printf_ssize_t) {
184  // http://b/8253769
185  ASSERT_EQ(sizeof(ssize_t), sizeof(long int));
186  ASSERT_EQ(sizeof(ssize_t), sizeof(size_t));
187  // For our 32-bit ABI, we had a ssize_t definition that confuses GCC into saying:
188  // error: format '%zd' expects argument of type 'signed size_t',
189  //     but argument 4 has type 'ssize_t {aka long int}' [-Werror=format]
190  ssize_t v = 1;
191  char buf[32];
192  snprintf(buf, sizeof(buf), "%zd", v);
193}
194
195// https://code.google.com/p/android/issues/detail?id=64886
196TEST(stdio, snprintf_a) {
197  char buf[BUFSIZ];
198  EXPECT_EQ(23, snprintf(buf, sizeof(buf), "<%a>", 9990.235));
199  EXPECT_STREQ("<0x1.3831e147ae148p+13>", buf);
200}
201
202TEST(stdio, snprintf_lc) {
203  char buf[BUFSIZ];
204  wint_t wc = L'a';
205  EXPECT_EQ(3, snprintf(buf, sizeof(buf), "<%lc>", wc));
206  EXPECT_STREQ("<a>", buf);
207}
208
209TEST(stdio, snprintf_ls) {
210  char buf[BUFSIZ];
211  wchar_t* ws = NULL;
212  EXPECT_EQ(8, snprintf(buf, sizeof(buf), "<%ls>", ws));
213  EXPECT_STREQ("<(null)>", buf);
214
215  wchar_t chars[] = { L'h', L'i', 0 };
216  ws = chars;
217  EXPECT_EQ(4, snprintf(buf, sizeof(buf), "<%ls>", ws));
218  EXPECT_STREQ("<hi>", buf);
219}
220
221TEST(stdio, snprintf_n) {
222#if defined(__BIONIC__)
223  // http://b/14492135
224  char buf[32];
225  int i = 1234;
226  EXPECT_EQ(5, snprintf(buf, sizeof(buf), "a %n b", &i));
227  EXPECT_EQ(1234, i);
228  EXPECT_STREQ("a n b", buf);
229#else
230  GTEST_LOG_(INFO) << "This test does nothing.\n";
231#endif
232}
233
234TEST(stdio, snprintf_smoke) {
235  char buf[BUFSIZ];
236
237  snprintf(buf, sizeof(buf), "a");
238  EXPECT_STREQ("a", buf);
239
240  snprintf(buf, sizeof(buf), "%%");
241  EXPECT_STREQ("%", buf);
242
243  snprintf(buf, sizeof(buf), "01234");
244  EXPECT_STREQ("01234", buf);
245
246  snprintf(buf, sizeof(buf), "a%sb", "01234");
247  EXPECT_STREQ("a01234b", buf);
248
249  char* s = NULL;
250  snprintf(buf, sizeof(buf), "a%sb", s);
251  EXPECT_STREQ("a(null)b", buf);
252
253  snprintf(buf, sizeof(buf), "aa%scc", "bb");
254  EXPECT_STREQ("aabbcc", buf);
255
256  snprintf(buf, sizeof(buf), "a%cc", 'b');
257  EXPECT_STREQ("abc", buf);
258
259  snprintf(buf, sizeof(buf), "a%db", 1234);
260  EXPECT_STREQ("a1234b", buf);
261
262  snprintf(buf, sizeof(buf), "a%db", -8123);
263  EXPECT_STREQ("a-8123b", buf);
264
265  snprintf(buf, sizeof(buf), "a%hdb", static_cast<short>(0x7fff0010));
266  EXPECT_STREQ("a16b", buf);
267
268  snprintf(buf, sizeof(buf), "a%hhdb", static_cast<char>(0x7fffff10));
269  EXPECT_STREQ("a16b", buf);
270
271  snprintf(buf, sizeof(buf), "a%lldb", 0x1000000000LL);
272  EXPECT_STREQ("a68719476736b", buf);
273
274  snprintf(buf, sizeof(buf), "a%ldb", 70000L);
275  EXPECT_STREQ("a70000b", buf);
276
277  snprintf(buf, sizeof(buf), "a%pb", reinterpret_cast<void*>(0xb0001234));
278  EXPECT_STREQ("a0xb0001234b", buf);
279
280  snprintf(buf, sizeof(buf), "a%xz", 0x12ab);
281  EXPECT_STREQ("a12abz", buf);
282
283  snprintf(buf, sizeof(buf), "a%Xz", 0x12ab);
284  EXPECT_STREQ("a12ABz", buf);
285
286  snprintf(buf, sizeof(buf), "a%08xz", 0x123456);
287  EXPECT_STREQ("a00123456z", buf);
288
289  snprintf(buf, sizeof(buf), "a%5dz", 1234);
290  EXPECT_STREQ("a 1234z", buf);
291
292  snprintf(buf, sizeof(buf), "a%05dz", 1234);
293  EXPECT_STREQ("a01234z", buf);
294
295  snprintf(buf, sizeof(buf), "a%8dz", 1234);
296  EXPECT_STREQ("a    1234z", buf);
297
298  snprintf(buf, sizeof(buf), "a%-8dz", 1234);
299  EXPECT_STREQ("a1234    z", buf);
300
301  snprintf(buf, sizeof(buf), "A%-11sZ", "abcdef");
302  EXPECT_STREQ("Aabcdef     Z", buf);
303
304  snprintf(buf, sizeof(buf), "A%s:%dZ", "hello", 1234);
305  EXPECT_STREQ("Ahello:1234Z", buf);
306
307  snprintf(buf, sizeof(buf), "a%03d:%d:%02dz", 5, 5, 5);
308  EXPECT_STREQ("a005:5:05z", buf);
309
310  void* p = NULL;
311  snprintf(buf, sizeof(buf), "a%d,%pz", 5, p);
312#if defined(__BIONIC__)
313  EXPECT_STREQ("a5,0x0z", buf);
314#else // __BIONIC__
315  EXPECT_STREQ("a5,(nil)z", buf);
316#endif // __BIONIC__
317
318  snprintf(buf, sizeof(buf), "a%lld,%d,%d,%dz", 0x1000000000LL, 6, 7, 8);
319  EXPECT_STREQ("a68719476736,6,7,8z", buf);
320
321  snprintf(buf, sizeof(buf), "a_%f_b", 1.23f);
322  EXPECT_STREQ("a_1.230000_b", buf);
323
324  snprintf(buf, sizeof(buf), "a_%g_b", 3.14);
325  EXPECT_STREQ("a_3.14_b", buf);
326
327  snprintf(buf, sizeof(buf), "%1$s %1$s", "print_me_twice");
328  EXPECT_STREQ("print_me_twice print_me_twice", buf);
329}
330
331TEST(stdio, snprintf_f_special) {
332  char buf[BUFSIZ];
333  snprintf(buf, sizeof(buf), "%f", nanf(""));
334  EXPECT_STRCASEEQ("NaN", buf);
335
336  snprintf(buf, sizeof(buf), "%f", HUGE_VALF);
337  EXPECT_STRCASEEQ("Inf", buf);
338}
339
340TEST(stdio, snprintf_g_special) {
341  char buf[BUFSIZ];
342  snprintf(buf, sizeof(buf), "%g", nan(""));
343  EXPECT_STRCASEEQ("NaN", buf);
344
345  snprintf(buf, sizeof(buf), "%g", HUGE_VAL);
346  EXPECT_STRCASEEQ("Inf", buf);
347}
348
349TEST(stdio, snprintf_d_INT_MAX) {
350  char buf[BUFSIZ];
351  snprintf(buf, sizeof(buf), "%d", INT_MAX);
352  EXPECT_STREQ("2147483647", buf);
353}
354
355TEST(stdio, snprintf_d_INT_MIN) {
356  char buf[BUFSIZ];
357  snprintf(buf, sizeof(buf), "%d", INT_MIN);
358  EXPECT_STREQ("-2147483648", buf);
359}
360
361TEST(stdio, snprintf_ld_LONG_MAX) {
362  char buf[BUFSIZ];
363  snprintf(buf, sizeof(buf), "%ld", LONG_MAX);
364#if __LP64__
365  EXPECT_STREQ("9223372036854775807", buf);
366#else
367  EXPECT_STREQ("2147483647", buf);
368#endif
369}
370
371TEST(stdio, snprintf_ld_LONG_MIN) {
372  char buf[BUFSIZ];
373  snprintf(buf, sizeof(buf), "%ld", LONG_MIN);
374#if __LP64__
375  EXPECT_STREQ("-9223372036854775808", buf);
376#else
377  EXPECT_STREQ("-2147483648", buf);
378#endif
379}
380
381TEST(stdio, snprintf_lld_LLONG_MAX) {
382  char buf[BUFSIZ];
383  snprintf(buf, sizeof(buf), "%lld", LLONG_MAX);
384  EXPECT_STREQ("9223372036854775807", buf);
385}
386
387TEST(stdio, snprintf_lld_LLONG_MIN) {
388  char buf[BUFSIZ];
389  snprintf(buf, sizeof(buf), "%lld", LLONG_MIN);
390  EXPECT_STREQ("-9223372036854775808", buf);
391}
392
393TEST(stdio, snprintf_e) {
394  char buf[BUFSIZ];
395
396  snprintf(buf, sizeof(buf), "%e", 1.5);
397  EXPECT_STREQ("1.500000e+00", buf);
398
399  snprintf(buf, sizeof(buf), "%Le", 1.5l);
400  EXPECT_STREQ("1.500000e+00", buf);
401}
402
403TEST(stdio, snprintf_negative_zero_5084292) {
404  char buf[BUFSIZ];
405
406  snprintf(buf, sizeof(buf), "%f", -0.0);
407  EXPECT_STREQ("-0.000000", buf);
408}
409
410TEST(stdio, popen) {
411  FILE* fp = popen("cat /proc/version", "r");
412  ASSERT_TRUE(fp != NULL);
413
414  char buf[16];
415  char* s = fgets(buf, sizeof(buf), fp);
416  buf[13] = '\0';
417  ASSERT_STREQ("Linux version", s);
418
419  ASSERT_EQ(0, pclose(fp));
420}
421
422TEST(stdio, getc) {
423  FILE* fp = fopen("/proc/version", "r");
424  ASSERT_TRUE(fp != NULL);
425  ASSERT_EQ('L', getc(fp));
426  ASSERT_EQ('i', getc(fp));
427  ASSERT_EQ('n', getc(fp));
428  ASSERT_EQ('u', getc(fp));
429  ASSERT_EQ('x', getc(fp));
430  fclose(fp);
431}
432
433TEST(stdio, putc) {
434  FILE* fp = fopen("/proc/version", "r");
435  ASSERT_TRUE(fp != NULL);
436  ASSERT_EQ(EOF, putc('x', fp));
437  fclose(fp);
438}
439
440TEST(stdio, sscanf) {
441  char s1[123];
442  int i1;
443  double d1;
444  char s2[123];
445  ASSERT_EQ(3, sscanf("  hello 123 1.23 ", "%s %i %lf %s", s1, &i1, &d1, s2));
446  ASSERT_STREQ("hello", s1);
447  ASSERT_EQ(123, i1);
448  ASSERT_DOUBLE_EQ(1.23, d1);
449}
450
451TEST(stdio, cantwrite_EBADF) {
452  // If we open a file read-only...
453  FILE* fp = fopen("/proc/version", "r");
454
455  // ...all attempts to write to that file should return failure.
456
457  // They should also set errno to EBADF. This isn't POSIX, but it's traditional.
458  // glibc gets the wide-character functions wrong.
459
460  errno = 0;
461  EXPECT_EQ(EOF, putc('x', fp));
462  EXPECT_EQ(EBADF, errno);
463
464  errno = 0;
465  EXPECT_EQ(EOF, fprintf(fp, "hello"));
466  EXPECT_EQ(EBADF, errno);
467
468  errno = 0;
469  EXPECT_EQ(EOF, fwprintf(fp, L"hello"));
470#if defined(__BIONIC__)
471  EXPECT_EQ(EBADF, errno);
472#endif
473
474  errno = 0;
475  EXPECT_EQ(EOF, putw(1234, fp));
476  EXPECT_EQ(EBADF, errno);
477
478  errno = 0;
479  EXPECT_EQ(0U, fwrite("hello", 1, 2, fp));
480  EXPECT_EQ(EBADF, errno);
481
482  errno = 0;
483  EXPECT_EQ(EOF, fputs("hello", fp));
484  EXPECT_EQ(EBADF, errno);
485
486  errno = 0;
487  EXPECT_EQ(WEOF, fputwc(L'x', fp));
488#if defined(__BIONIC__)
489  EXPECT_EQ(EBADF, errno);
490#endif
491}
492
493// Tests that we can only have a consistent and correct fpos_t when using
494// f*pos functions (i.e. fpos doesn't get inside a multi byte character).
495TEST(stdio, consistent_fpos_t) {
496  ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
497  uselocale(LC_GLOBAL_LOCALE);
498
499  FILE* fp = tmpfile();
500  ASSERT_TRUE(fp != NULL);
501
502  wchar_t mb_one_bytes = L'h';
503  wchar_t mb_two_bytes = 0x00a2;
504  wchar_t mb_three_bytes = 0x20ac;
505  wchar_t mb_four_bytes = 0x24b62;
506
507  // Write to file.
508  ASSERT_EQ(mb_one_bytes, static_cast<wchar_t>(fputwc(mb_one_bytes, fp)));
509  ASSERT_EQ(mb_two_bytes, static_cast<wchar_t>(fputwc(mb_two_bytes, fp)));
510  ASSERT_EQ(mb_three_bytes, static_cast<wchar_t>(fputwc(mb_three_bytes, fp)));
511  ASSERT_EQ(mb_four_bytes, static_cast<wchar_t>(fputwc(mb_four_bytes, fp)));
512
513  rewind(fp);
514
515  // Record each character position.
516  fpos_t pos1;
517  fpos_t pos2;
518  fpos_t pos3;
519  fpos_t pos4;
520  fpos_t pos5;
521  EXPECT_EQ(0, fgetpos(fp, &pos1));
522  ASSERT_EQ(mb_one_bytes, static_cast<wchar_t>(fgetwc(fp)));
523  EXPECT_EQ(0, fgetpos(fp, &pos2));
524  ASSERT_EQ(mb_two_bytes, static_cast<wchar_t>(fgetwc(fp)));
525  EXPECT_EQ(0, fgetpos(fp, &pos3));
526  ASSERT_EQ(mb_three_bytes, static_cast<wchar_t>(fgetwc(fp)));
527  EXPECT_EQ(0, fgetpos(fp, &pos4));
528  ASSERT_EQ(mb_four_bytes, static_cast<wchar_t>(fgetwc(fp)));
529  EXPECT_EQ(0, fgetpos(fp, &pos5));
530
531#if defined(__BIONIC__)
532  // Bionic's fpos_t is just an alias for off_t. This is inherited from OpenBSD
533  // upstream. Glibc differs by storing the mbstate_t inside its fpos_t. In
534  // Bionic (and upstream OpenBSD) the mbstate_t is stored inside the FILE
535  // structure.
536  ASSERT_EQ(0, static_cast<off_t>(pos1));
537  ASSERT_EQ(1, static_cast<off_t>(pos2));
538  ASSERT_EQ(3, static_cast<off_t>(pos3));
539  ASSERT_EQ(6, static_cast<off_t>(pos4));
540  ASSERT_EQ(10, static_cast<off_t>(pos5));
541#endif
542
543  // Exercise back and forth movements of the position.
544  ASSERT_EQ(0, fsetpos(fp, &pos2));
545  ASSERT_EQ(mb_two_bytes, static_cast<wchar_t>(fgetwc(fp)));
546  ASSERT_EQ(0, fsetpos(fp, &pos1));
547  ASSERT_EQ(mb_one_bytes, static_cast<wchar_t>(fgetwc(fp)));
548  ASSERT_EQ(0, fsetpos(fp, &pos4));
549  ASSERT_EQ(mb_four_bytes, static_cast<wchar_t>(fgetwc(fp)));
550  ASSERT_EQ(0, fsetpos(fp, &pos3));
551  ASSERT_EQ(mb_three_bytes, static_cast<wchar_t>(fgetwc(fp)));
552  ASSERT_EQ(0, fsetpos(fp, &pos5));
553  ASSERT_EQ(WEOF, fgetwc(fp));
554
555  fclose(fp);
556}
557
558// Exercise the interaction between fpos and seek.
559TEST(stdio, fpos_t_and_seek) {
560  ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
561  uselocale(LC_GLOBAL_LOCALE);
562
563  // For glibc we need to close and re-open the file in order for fseek to work
564  // after using setlocale(LC_CTYPE, "C.UTF-8") and fputwc.
565  // TODO: find out if this is expected or a bug in glibc.
566  TemporaryFile tf;
567  FILE* fp = fdopen(tf.fd, "w+");
568  ASSERT_TRUE(fp != NULL);
569
570  wchar_t mb_two_bytes = 0x00a2;
571  wchar_t mb_three_bytes = 0x20ac;
572  wchar_t mb_four_bytes = 0x24b62;
573
574  // Write to file.
575  ASSERT_EQ(mb_two_bytes, static_cast<wchar_t>(fputwc(mb_two_bytes, fp)));
576  ASSERT_EQ(mb_three_bytes, static_cast<wchar_t>(fputwc(mb_three_bytes, fp)));
577  ASSERT_EQ(mb_four_bytes, static_cast<wchar_t>(fputwc(mb_four_bytes, fp)));
578
579  fflush(fp);
580  fclose(fp);
581
582  fp = fopen(tf.filename, "r");
583  ASSERT_TRUE(fp != NULL);
584
585  // Store a valid position.
586  fpos_t mb_two_bytes_pos;
587  ASSERT_EQ(0, fgetpos(fp, &mb_two_bytes_pos));
588
589  // Move inside mb_four_bytes with fseek.
590  long offset_inside_mb = 6;
591  ASSERT_EQ(0, fseek(fp, offset_inside_mb, SEEK_SET));
592
593  // Store the "inside multi byte" position.
594  fpos_t pos_inside_mb;
595  ASSERT_EQ(0, fgetpos(fp, &pos_inside_mb));
596#if defined(__BIONIC__)
597  ASSERT_EQ(offset_inside_mb, static_cast<off_t>(pos_inside_mb));
598#endif
599
600  // Reading from within a byte should produce an error.
601  ASSERT_EQ(WEOF, fgetwc(fp));
602  ASSERT_EQ(EILSEQ, errno);
603
604  // Reverting to a valid position should work.
605  ASSERT_EQ(0, fsetpos(fp, &mb_two_bytes_pos));
606  ASSERT_EQ(mb_two_bytes, static_cast<wchar_t>(fgetwc(fp)));
607
608  // Moving withing a multi byte with fsetpos should work but reading should
609  // produce an error.
610  ASSERT_EQ(0, fsetpos(fp, &pos_inside_mb));
611  ASSERT_EQ(WEOF, fgetwc(fp));
612  ASSERT_EQ(EILSEQ, errno);
613
614  fclose(fp);
615}
616