source: tests/io/manipulatorsInput.cfa@ 33e4e8ef

Last change on this file since 33e4e8ef was 0860d9c, checked in by Michael Brooks <mlbrooks@…>, 2 years ago

Fix read-to-variable-length-string cases when internal buffer fills.

Also fix read-to-cstring ability to give no-exception cases when an entire buffer fills.

The added test cases run, and fail, when run against prior libcfa.
Doing so illustrates a CFA-string-level bug.
Doing so illustrates a C-string-level changed semantics.

At the CFA-string level, the bug was, when reading strings of just the right length,
what should be two reads ("abc" then "def") gets mashed into one ("abcdef").
These cases are clearly bugs because a test program that just echoes chuncks of delimeted input would do so inaccurately.
They're just hard to drive because the relevant chunk lengths are implementation-dependent, and sometimes big.

At the C-string level, the semantic change concerns when to throw the cstring_length exception.
By this change, make the original semantics,
"An exception means the maximum number of characters was read," into
"An exception means that if the buffer were larger, then more characters would have been read."

The added test cases cover the respective stop conditions for manipulator state "%s", include, exclude, getline, and getline/delimiter.

  • Property mode set to 100644
File size: 6.8 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
3//
4// manipulatorsInput.cfa --
5//
6// Author : Peter A. Buhr
7// Created On : Sat Jun 8 17:58:54 2019
8// Last Modified By : Peter A. Buhr
9// Last Modified On : Sat Sep 2 14:27:46 2023
10// Update Count : 65
11//
12
13#include <fstream.hfa>
14#include <stdio.h> // scanf
15
16int main() {
17 {
18 // Upfront checks to ensure buffer safety. Once these pass, the simpler `wdi(sizeof(s),s)`
19 // usage, as in the scanf alignment cases below, is justified.
20 struct {
21 char buf[8];
22 char canary;
23 } data;
24 static_assert( sizeof(data.buf) == 8 );
25 static_assert( &data.buf[8] == &data.canary ); // canary comes right after buf
26
27 void rep(const char* casename) {
28 data.canary = 42;
29 bool caught = false;
30 try {
31 sin | wdi( sizeof(data.buf), data.buf );
32 } catch (cstring_length*) {
33 caught = true;
34 }
35 printf( "%s \"%s\"", casename, data.buf );
36 if ( caught ) {
37 printf(", exception occurred");
38 }
39 if ( data.canary == 42 ) {
40 printf(", canary ok");
41 } else {
42 printf(", canary overwritten to %d", data.canary);
43 }
44 printf("\n");
45 }
46
47 rep("pre1"); // 123456 | 123456
48 rep("pre2"); // 1234567 | 1234567
49 rep("pre3a"); // 12345678 | 1234567
50 rep("pre3b"); // | 8
51 rep("pre4a"); // 123456789 | 1234567
52 rep("pre4b"); // | 89
53
54 scanf("\n"); // next test does not start with %s so does not tolerate leading whitespace
55 }
56 {
57 char s[] = "yyyyyyyyyyyyyyyyyyyy";
58 const char sk_fmt[] = "%*[abc]";
59 scanf( "abc " ); scanf( sk_fmt ); for ( 5 ) scanf( "%*c" ); printf( "1 %s\n", s );
60 scanf( "%s", s ); printf( "2 %s\n", s );
61 scanf( "%*s" ); printf( "3 %s\n", s );
62 scanf( "%8s", s ); printf( "4 %s\n", s );
63 scanf( "%*8s" ); printf( "5 %s\n", s );
64
65 scanf( "%[abc]", s ); printf( "6 %s\n", s );
66 scanf( "%[^abc]", s ); printf( "7 %s\n", s );
67 scanf( "%*[abc]" ); printf( "8 %s\n", s );
68 scanf( "%*[^abc]" ); printf( "9 %s\n", s );
69 scanf( "%8[abc]", s ); printf( "10 %s\n", s );
70 scanf( "%8[^abc]", s ); printf( "11 %s\n", s );
71 scanf( "%*8[abc]" ); printf( "12 %s\n", s );
72 scanf( "%*8[^abc]" ); printf( "13 %s\n", s );
73
74 int rc;
75 s[0] = 'q'; s[1] = '\0'; rc = 99;
76 rc = scanf( "%[abc]", s ); printf( "14 rc=%d, %s\n", rc, s );
77 s[0] = 'q'; s[1] = '\0'; rc = 99;
78 rc = scanf( "%[^u]", s ); printf( "15 rc=%d, %s\n", rc, s );
79 scanf( "%*[u]" );
80 scanf("\n");
81 }
82 {
83 char s[] = "yyyyyyyyyyyyyyyyyyyy";
84 char sk[] = "abc";
85 sin | "abc " | skip( sk ) | skip( 5 ); sout | "1" | s;
86 sin | wdi( sizeof(s), s ); sout | "2" | s;
87 sin | ignore( s ); sout | "3" | s;
88 sin | wdi( sizeof(s), 8, s ); sout | "4" | s;
89 sin | ignore( wdi( sizeof(s), 8, s ) ); sout | "5" | s;
90
91 sin | incl( "abc", wdi( sizeof(s), s ) ); sout | "6" | s;
92 sin | excl( "abc", wdi( sizeof(s), s ) ); sout | "7" | s;
93 sin | ignore( incl( "abc", wdi( sizeof(s), s ) ) ); sout | "8" | s;
94 sin | ignore( excl( "abc", wdi( sizeof(s), s ) ) ); sout | "9" | s;
95 sin | incl( "abc", wdi( sizeof(s), 8, s ) ); sout | "10" | s;
96 sin | excl( "abc", wdi( sizeof(s), 8, s ) ); sout | "11" | s;
97 sin | ignore( incl( "abc", wdi( sizeof(s), 8, s ) ) ); sout | "12" | s;
98 sin | ignore( excl( "abc", wdi( sizeof(s), 8, s ) ) ); sout | "13" | s;
99
100 s[0] = 'q'; s[1] = '\0';
101 sin | incl( "abc", wdi( sizeof(s), s ) ); sout | "14" | s;
102 s[0] = 'q'; s[1] = '\0';
103 sin | excl( "u", wdi( sizeof(s), s ) ); sout | "15" | s;
104 sin | skip( "u" );
105 sin | "\n";
106 }
107 /* Keep harmonized with collections/string-istream-manip */
108 {
109 char c;
110 sin | c; sout | c;
111 sin | ignore( c ); sout | c;
112
113 signed char sc;
114 sin | sc; sout | sc;
115 sin | wdi( 3, sc ); sout | sc;
116 sin | ignore( sc ); sout | sc;
117 sin | ignore( wdi( 3, sc ) ); sout | sc;
118
119 unsigned char usc;
120 sin | usc; sout | usc;
121 sin | wdi( 3, usc ); sout | usc;
122 sin | ignore( usc ); sout | usc;
123 sin | ignore( wdi( 3, usc ) ); sout | usc;
124
125 signed short int ssi;
126 sin | ssi; sout | ssi;
127 sin | wdi( 3, ssi ); sout | ssi;
128 sin | ignore( ssi ); sout | ssi;
129 sin | ignore( wdi( 3, ssi ) ); sout | ssi;
130
131 unsigned short int usi;
132 sin | usi; sout | usi;
133 sin | wdi( 3, usi ); sout | usi;
134 sin | ignore( usi ); sout | usi;
135 sin | ignore( wdi( 3, usi ) ); sout | usi;
136
137 signed int si;
138 sin | si; sout | si;
139 sin | wdi( 3, si ); sout | si;
140 sin | ignore( si ); sout | si;
141 sin | ignore( wdi( 3, si ) ); sout | si;
142
143 unsigned int ui;
144 sin | ui; sout | ui;
145 sin | wdi( 3, ui ); sout | ui;
146 sin | ignore( ui ); sout | ui;
147 sin | ignore( wdi( 3, ui ) ); sout | ui;
148
149 signed long int sli;
150 sin | sli; sout | sli;
151 sin | wdi( 3, sli ); sout | sli;
152 sin | ignore( sli ); sout | sli;
153 sin | ignore( wdi( 3, sli ) ); sout | sli;
154
155 unsigned long int uli;
156 sin | uli; sout | uli;
157 sin | wdi( 3, uli ); sout | uli;
158 sin | ignore( uli ); sout | uli;
159 sin | ignore( wdi( 3, uli ) ); sout | uli;
160
161 signed long long int slli;
162 sin | slli; sout | slli;
163 sin | wdi( 3, slli ); sout | slli;
164 sin | ignore( slli ); sout | slli;
165 sin | ignore( wdi( 3, slli ) ); sout | slli;
166
167 unsigned long long int ulli;
168 sin | ulli; sout | ulli;
169 sin | wdi( 3, ulli ); sout | ulli;
170 sin | ignore( ulli ); sout | ulli;
171 sin | ignore( wdi( 3, ulli ) ); sout | ulli;
172
173 float f;
174 sin | f; sout | f;
175 sin | wdi( 8, f ); sout | f;
176 sin | ignore( f ); sout | f;
177 sin | ignore( wdi( 8, f ) ); sout | f;
178
179 double d;
180 sin | d; sout | d;
181 sin | wdi( 8, d ); sout | d;
182 sin | ignore( d ); sout | d;
183 sin | ignore( wdi( 8, d ) ); sout | d;
184
185 long double ld;
186 sin | ld; sout | ld;
187 sin | wdi( 8, ld ); sout | ld;
188 sin | ignore( ld ); sout | ld;
189 sin | ignore( wdi( 8, ld ) ); sout | ld;
190
191 float _Complex fc;
192 sin | fc; sout | fc;
193 sin | wdi( 8, fc ); sout | fc;
194 sin | ignore( fc ); sout | fc;
195 sin | ignore( wdi( 8, fc ) ); sout | fc;
196
197 double _Complex dc;
198 sin | dc; sout | dc;
199 sin | wdi( 8, dc ); sout | dc;
200 sin | ignore( dc ); sout | dc;
201 sin | ignore( wdi( 8, dc ) ); sout | dc;
202
203 long double _Complex ldc;
204 sin | ldc; sout | ldc;
205 sin | wdi( 8, ldc ); sout | ldc;
206 sin | ignore( ldc ); sout | ldc;
207 sin | ignore( wdi( 8, ldc ) ); sout | ldc;
208 }
209 #if defined( __SIZEOF_INT128__ )
210 {
211 int128 val;
212 for ( 15 ) {
213 sin | val;
214 sout | val;
215 }
216 }
217 #endif // __SIZEOF_INT128__
218} // main
219
220// Local Variables: //
221// tab-width: 4 //
222// compile-command: "cfa -Wall -Wextra manipulatorsInput.cfa" //
223// End: //
Note: See TracBrowser for help on using the repository browser.