source: tests/collections/string-istream-manip.cfa @ 8a33777

Last change on this file since 8a33777 was 8a33777, checked in by Michael Brooks <mlbrooks@…>, 5 months ago

Fix analysis error in string-input testing.

Add comments correlating .in file content with line of code that reads it.

This test's correctness expectation is bootstrapped from the actual behaviour of scanf.
A mistake in knowing "which character are we on at this point"
led to an inaccurate understanding of what scanf does on an edge case.
The test was showing that the CFA analogs behave the same as scanf.
But the test was not exercising the case that it suggested it was.
This issue is now fixed.

Old position, mistaken: case 14 begins on line ccccuuuucccc
Old position, corrected: cases 12/13 consume leading cccc; case 14 begins on uuuucccc
New positions: as commented in test .cfa

prior scanf understanding, mistaken: include skips unwanted characters before capturing
wanted characters, while exclude fails on unwanted characters

scanf understanding, corrected: include and exclude fail on unwanted characters

  • Property mode set to 100644
File size: 7.7 KB
Line 
1
2#include <fstream.hfa>
3#include <collections/string.hfa>
4#include <collections/string_res.hfa>
5#include <stdio.h>
6
7// No-op manipulators.
8// Temporary hack while there are two code paths in the string implementation.
9// (One for reading plain strings, the other for reading via a manipulator.)
10// The test cases that use plainjane(-) are exercising the via-manipulator code path,
11// just with trivial manipulation.
12static _Istream_Sstr plainjane( string     & s )  { return (_Istream_Sstr)@{  s, {{0p}, -1, {.flags.rwd : false}} }; }
13static _Istream_Rstr plainjane( string_res & s )  { return (_Istream_Rstr)@{ &s, {{0p}, -1, {.flags.rwd : false}} }; }
14
15static void forceStringHeapFreeSpaceTo(int desiredSize) {
16    for (1_000_000) {
17        string x = "a";
18        (void)x;
19      if (desiredSize == DEBUG_string_bytes_avail_until_gc(DEBUG_string_heap())) return;
20    }
21    sout | "Unable to force size" | desiredSize | "in 1,000,000 tries";
22}
23
24int main() {
25    // These "pre" cases deal with issues analogous to the "pre" cases of io/manipulatorsInput.
26    // The acceptance criterion is simpler but driving the cases is harder.
27    // The tests just read strings and echo what they read; acceptance of simple echoing assures
28    // no spurious splitting merging.
29    // The lengths of the strings are chosen to match white-box knowledge of when the string layer
30    // has tor drive the cstring layer through a second iteration:
31    //  - for no-manip, lengths are near the room at end of string heap
32    //    (chosen target size of 9 showed the original bug on preS2, aligned with the other cases)
33    //  - for manip, lengths are near the auxiliary buffer size of 128
34    // Only first case repeats for string_res; rest run only from the passthru string layer.
35    // Similarly, the manipulator breadth isn't checked at the cstring layer either.
36    {
37        // S: string, no manipulator
38        void echoTillX(const char * casename) {
39            string s;
40            // loop assumes behaviour not tested until main-case #15:
41            // on reading nothing, the prior string value is left alone
42            do {
43                s = "";
44                forceStringHeapFreeSpaceTo(9);
45                sin | s;
46                sout | casename | s;
47            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
48        }
49        echoTillX("preS1");
50        echoTillX("preS2");
51        echoTillX("preS3");
52        echoTillX("preS4");
53    }
54    {
55        // SMN: string, manipulator for no-op
56        void echoTillX(const char * casename) {
57            string s;
58            do {
59                s = "";
60                sin | plainjane( s );
61                sout | casename | s;
62            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
63        }
64        echoTillX("preSMN1");
65        echoTillX("preSMN2");
66        echoTillX("preSMN3");
67        echoTillX("preSMN4");
68    }
69    {
70        // RMN: string_res, manipulator for no-op
71        void echoTillX(const char * casename) {
72            string_res s;
73            do {
74                s = "";
75                sin | plainjane( s );
76                sout | casename | s;
77            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
78        }
79        echoTillX("preRMN1");
80        echoTillX("preRMN2");
81        echoTillX("preRMN3");
82        echoTillX("preRMN4");
83    }
84    {
85        // SMI: string, manipulator `incl`
86        void echoTillX(const char * casename) {
87            string s;
88            do {
89                s = "";
90                sin | skip("-\n");
91                sin | incl( ".:|# x", s );
92                sout | casename | " \"" | s | "\"";
93            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
94        }
95        echoTillX("preSMI1");
96        echoTillX("preSMI2");
97        echoTillX("preSMI3");
98        echoTillX("preSMI4");
99    }
100    {
101        // SME: string, manipulator `excl`
102        void echoTillX(const char * casename) {
103            string s;
104            do {
105                s = "";
106                sin | skip("-\n");
107                sin | excl( "-\n", s );
108                sout | casename | " \"" | s | "\"";
109            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
110        }
111        echoTillX("preSME1");
112        echoTillX("preSME2");
113        echoTillX("preSME3");
114        echoTillX("preSME4");
115    }
116    sin | skip("-\n");
117    {
118        // SMG: string, manipulator `getline`
119        void echoTillX(const char * casename) {
120            string s;
121            do {
122                s = "";
123                sin | getline( s );
124                sout | casename | s;
125            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
126        }
127        echoTillX("preSMG1");
128        echoTillX("preSMG2");
129        echoTillX("preSMG3");
130        echoTillX("preSMG4");
131    }
132    {
133        // SMD: string, manipulator (`getline` with custom) delimiter
134        void echoTillX(const char * casename) {
135            string s;
136            do {
137                s = "";
138                sin | getline( s, '@' );
139                sout | casename | s;
140            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
141            sin | skip(" \n");
142        }
143        echoTillX("preSMD1");
144        echoTillX("preSMD2");
145        echoTillX("preSMD3");
146        echoTillX("preSMD4");
147    }
148
149    /* Keep harmonized with io/manipulatorsInput */
150    {
151        string s = "yyyyyyyyyyyyyyyyyyyy";
152        char sk[] = "abc";
153        sin | "abc " | skip( sk ) | skip( 5 );          sout | "1" | s;
154        sin | s;                                        sout | "2" | s;
155        sin | ignore( s );                              sout | "3" | s;
156        sin | wdi( 8, s );                              sout | "4" | s;
157        sin | ignore( wdi( 8, s ) );                    sout | "5" | s;
158
159        sin | incl( "abc", s );                         sout | "6" | s;
160        sin | excl( "abc", s );                         sout | "7" | s;
161        sin | ignore( incl( "abc", s ) );               sout | "8" | s;
162        sin | ignore( excl( "abc", s ) );               sout | "9" | s;
163        sin | incl( "abc", wdi( 8, s ) );               sout | "10" | s;
164        sin | excl( "abc", wdi( 8, s ) );               sout | "11" | s;
165        sin | ignore( incl( "abc", wdi( 8, s ) ) );     sout | "12" | s;
166        sin | ignore( excl( "abc", wdi( 8, s ) ) );     sout | "13" | s;
167                sin | "\n";
168
169                s = "q";
170                sin | incl( "abc", s );                         sout | "14" | s;
171                s = "q";
172                sin | excl( "u", s );                           sout | "15" | s;
173                sin | skip( "u" );
174                sin | "\n";
175        }
176    // Full repeat on string_res layer assures the full manipulator vocabulary is supported there.
177    {
178        string_res s = "yyyyyyyyyyyyyyyyyyyy";
179        char sk[] = "abc";
180        sin | "abc " | skip( sk ) | skip( 5 );          sout | "1" | s;
181        sin | s;                                        sout | "2" | s;
182        sin | ignore( s );                              sout | "3" | s;
183        sin | wdi( 8, s );                              sout | "4" | s;
184        sin | ignore( wdi( 8, s ) );                    sout | "5" | s;
185
186        sin | incl( "abc", s );                         sout | "6" | s;
187        sin | excl( "abc", s );                         sout | "7" | s;
188        sin | ignore( incl( "abc", s ) );               sout | "8" | s;
189        sin | ignore( excl( "abc", s ) );               sout | "9" | s;
190        sin | incl( "abc", wdi( 8, s ) );               sout | "10" | s;
191        sin | excl( "abc", wdi( 8, s ) );               sout | "11" | s;
192        sin | ignore( incl( "abc", wdi( 8, s ) ) );     sout | "12" | s;
193        sin | ignore( excl( "abc", wdi( 8, s ) ) );     sout | "13" | s;
194                sin | "\n";
195
196                s = "q";
197                sin | incl( "abc", s );                         sout | "14" | s;
198                s = "q";
199                sin | excl( "u", s );                           sout | "15" | s;
200                sin | skip( "u" );
201                sin | "\n";
202    }
203}
Note: See TracBrowser for help on using the repository browser.