/ tests / ftell_ungetc.c
ftell_ungetc.c
 1  /* Thanks to the originator of Feedback FB8165838 / Radar 66131999 for
 2   * writing the original version of this test!
 3   */
 4  
 5  #include <darwintest.h>
 6  
 7  #include <assert.h>
 8  #include <string.h>
 9  
10  #include <stdio.h>
11  
12  T_DECL(ftell_ungetc, "Test interactions of ftell and ungetc")
13  {
14  	FILE *fp = stdin;
15  	fp = fopen("assets/ftell_ungetc.txt", "rb");
16  	T_QUIET; T_ASSERT_NE(fp, (FILE*)NULL, "Open the file");
17  
18  	/* Test ftell without having done any reads/writes */
19  	T_ASSERT_EQ(ftell(fp), 0L, "ftell without having done any reads/writes");
20  
21  	/* Read one character */
22  	T_ASSERT_EQ(fgetc(fp), '/', "Read one charatcter");
23  
24  	/* Check ftell again after one read */
25  	T_ASSERT_EQ(ftell(fp), 1L, "ftell after one read");
26  
27  	/* Push back one character */
28  	T_ASSERT_EQ(ungetc('/', fp), '/', "push back one character");
29  
30  	/* Check ftell again after pushing back one char */
31  	T_ASSERT_EQ(ftell(fp), 0L, "ftell after pushing back one char");
32  
33  	/* Read it again */
34  	T_ASSERT_EQ(fgetc(fp), '/', "read pushed back character again");
35  	T_ASSERT_EQ(ftell(fp), 1L, "ftell after reading again");
36  
37  	/* Seek and test ftell again */
38  	T_ASSERT_EQ(fseek(fp, 2, SEEK_SET), 0, "seek");
39  	T_ASSERT_EQ(ftell(fp), 2L, "ftell after seeking");
40  
41  	/* Push back invalid char (EOF) */
42  	T_ASSERT_EQ(ungetc(EOF, fp), EOF, "push back invalid char");
43  	T_ASSERT_EQ(ftell(fp), 2L, "ftell after pushing invalid char, pos should not have changed");
44  
45  	/* Read, push back different char, read again
46  	 * and check ftell.
47  	 *
48  	 * Cppreference:
49  	 * A successful call to ungetc on a text stream modifies
50  	 * the stream position indicator in unspecified manner but
51  	 * guarantees that after all pushed-back characters are
52  	 * retrieved with a read operation, the stream position
53  	 * indicator is equal to its value before ungetc.
54  	 */
55  	T_ASSERT_EQ(fgetc(fp), '-', "read another character");
56  	T_ASSERT_EQ(ftell(fp), 3L, "ftell after read");
57  	T_ASSERT_EQ(ungetc('A', fp), 'A', "push back a different character");
58  	T_ASSERT_EQ(fgetc(fp), 'A', "read back the different character");
59  	T_ASSERT_EQ(ftell(fp), 3L, "ftell after pushback and read back");
60  
61  	/* Push back a non-read character and test ftell.
62  	 *
63  	 * According to POSIX:
64  	 * The file-position indicator is decremented by each
65  	 * successful call to ungetc();
66  	 *
67  	 * Cppreference:
68  	 * A successful call to ungetc on a binary stream decrements
69  	 * the stream position indicator by one
70  	 */
71  	T_ASSERT_EQ(fgetc(fp), '+', "read another character");
72  	T_ASSERT_EQ(ungetc('A', fp), 'A', "push back a different character");
73  	T_EXPECTFAIL; T_ASSERT_EQ(ftell(fp), 3L, "ftell after pushback - EXPECTED FAIL rdar://66131999");
74  }