1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 #include <sal/types.h>
11 #include <cppunit/TestAssert.h>
12 #include <cppunit/TestFixture.h>
13 #include <cppunit/extensions/HelperMacros.h>
14 #include <tools/stream.hxx>
15 #include <sstream>
16 
17 //Tests for eofbit/badbit/goodbit/failbit
18 
19 namespace
20 {
21 
22     class Test: public CppUnit::TestFixture
23     {
24     public:
25         void test_stdstream();
26         void test_fastostring();
27         void test_read_cstring();
28         void test_read_pstring();
29         void test_readline();
30 
31         CPPUNIT_TEST_SUITE(Test);
32         CPPUNIT_TEST(test_stdstream);
33         CPPUNIT_TEST(test_fastostring);
34         CPPUNIT_TEST(test_read_cstring);
35         CPPUNIT_TEST(test_read_pstring);
36         CPPUNIT_TEST(test_readline);
37         CPPUNIT_TEST_SUITE_END();
38     };
39 
test_stdstream()40     void Test::test_stdstream()
41     {
42         char foo[] = "foo";
43         std::istringstream iss(foo, std::istringstream::in);
44         SvMemoryStream aMemStream(foo, SAL_N_ELEMENTS(foo)-1, StreamMode::READ);
45 
46         char std_a(78);
47         iss >> std_a;
48         CPPUNIT_ASSERT_EQUAL('f', std_a);
49 
50         char tools_a(78);
51         aMemStream.ReadChar( tools_a );
52         CPPUNIT_ASSERT_EQUAL('f', tools_a);
53 
54         iss.seekg(0, std::ios_base::end);
55         //seeking to end doesn't set eof, reading past eof does
56         CPPUNIT_ASSERT(!iss.eof());
57         CPPUNIT_ASSERT(iss.good());
58 
59         aMemStream.Seek(STREAM_SEEK_TO_END);
60         //seeking to end doesn't set eof, reading past eof does
61         CPPUNIT_ASSERT(!aMemStream.eof());
62         CPPUNIT_ASSERT(aMemStream.good());
63 
64         std_a = 78;
65         iss >> std_a;
66         //so, now eof is set
67         CPPUNIT_ASSERT(iss.eof());
68         //a failed read doesn't change the data, it remains unchanged
69         CPPUNIT_ASSERT_EQUAL(static_cast<char>(78), std_a);
70         //nothing wrong with the stream, so not bad
71         CPPUNIT_ASSERT(!iss.bad());
72         //yet, the read didn't succeed
73         CPPUNIT_ASSERT(!iss.good());
74         CPPUNIT_ASSERT_EQUAL((std::ios::failbit|std::ios::eofbit), iss.rdstate());
75 
76         tools_a = 78;
77         aMemStream.ReadChar( tools_a );
78         //so, now eof is set
79         CPPUNIT_ASSERT(aMemStream.eof());
80         //a failed read doesn't change the data, it remains unchanged
81         CPPUNIT_ASSERT_EQUAL(static_cast<char>(78), tools_a);
82         //nothing wrong with the stream, so not bad
83         CPPUNIT_ASSERT(!aMemStream.bad());
84         //yet, the read didn't succeed
85         CPPUNIT_ASSERT(!aMemStream.good());
86 
87         //set things up so that there is only one byte available on an attempt
88         //to read a two-byte sal_uInt16.  The byte should be consumed, but the
89         //operation should fail, and tools_b should remain unchanged,
90         sal_uInt16 tools_b = 0x1122;
91         aMemStream.SeekRel(-1);
92         CPPUNIT_ASSERT(!aMemStream.eof());
93         CPPUNIT_ASSERT(aMemStream.good());
94         aMemStream.ReadUInt16( tools_b );
95         CPPUNIT_ASSERT(!aMemStream.good());
96         CPPUNIT_ASSERT(aMemStream.eof());
97         CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(0x1122), tools_b);
98 
99         iss.clear();
100         iss.seekg(0);
101         CPPUNIT_ASSERT(iss.good());
102         iss >> std_a;
103         CPPUNIT_ASSERT_EQUAL('f', std_a);
104 
105         aMemStream.Seek(0);
106         CPPUNIT_ASSERT(aMemStream.good());
107         aMemStream.ReadChar( tools_a );
108         CPPUNIT_ASSERT_EQUAL('f', tools_a);
109 
110         //failbit is rather subtle wrt e.g seeks
111 
112         char buffer[1024];
113 
114         iss.clear();
115         iss.seekg(0);
116         CPPUNIT_ASSERT(iss.good());
117         iss.read(buffer, sizeof(buffer));
118         CPPUNIT_ASSERT_EQUAL(static_cast<std::streamsize>(3), iss.gcount());
119         CPPUNIT_ASSERT(!iss.good());
120         CPPUNIT_ASSERT(!iss.bad());
121         CPPUNIT_ASSERT(iss.eof());
122 
123         aMemStream.Seek(0);
124         CPPUNIT_ASSERT(aMemStream.good());
125         std::size_t nRet = aMemStream.ReadBytes(buffer, sizeof(buffer));
126         CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(3), nRet);
127         CPPUNIT_ASSERT(!aMemStream.good());
128         CPPUNIT_ASSERT(!aMemStream.bad());
129         CPPUNIT_ASSERT(aMemStream.eof());
130     }
131 
test_fastostring()132     void Test::test_fastostring()
133     {
134         char foo[] = "foobar";
135         SvMemoryStream aMemStream(foo, SAL_N_ELEMENTS(foo)-1, StreamMode::READ);
136 
137         OString aOne = read_uInt8s_ToOString(aMemStream, 3);
138         CPPUNIT_ASSERT_EQUAL(OString("foo"), aOne);
139 
140         OString aTwo = read_uInt8s_ToOString(aMemStream, 3);
141         CPPUNIT_ASSERT_EQUAL(OString("bar"), aTwo);
142 
143         OString aThree = read_uInt8s_ToOString(aMemStream, 3);
144         CPPUNIT_ASSERT(aThree.isEmpty());
145 
146         aMemStream.Seek(0);
147 
148         OString aFour = read_uInt8s_ToOString(aMemStream, 100);
149         CPPUNIT_ASSERT_EQUAL(OString(foo), aFour);
150     }
151 
test_read_cstring()152     void Test::test_read_cstring()
153     {
154         char foo[] = "foobar";
155         SvMemoryStream aMemStream(foo, SAL_N_ELEMENTS(foo)-1, StreamMode::READ);
156 
157         OString aOne = read_zeroTerminated_uInt8s_ToOString(aMemStream);
158         CPPUNIT_ASSERT_EQUAL(OString("foobar"), aOne);
159         CPPUNIT_ASSERT(!aMemStream.good());
160         CPPUNIT_ASSERT(!aMemStream.bad());
161         CPPUNIT_ASSERT(aMemStream.eof());
162 
163         aMemStream.Seek(0);
164         foo[3] = 0;
165         OString aTwo = read_zeroTerminated_uInt8s_ToOString(aMemStream);
166         CPPUNIT_ASSERT_EQUAL(OString("foo"), aTwo);
167         CPPUNIT_ASSERT(aMemStream.good());
168     }
169 
test_read_pstring()170     void Test::test_read_pstring()
171     {
172         char foo[] = "\3foobar";
173         SvMemoryStream aMemStream(foo, SAL_N_ELEMENTS(foo)-1, StreamMode::READ);
174 
175         OString aFoo = read_uInt8_lenPrefixed_uInt8s_ToOString(aMemStream);
176         CPPUNIT_ASSERT_EQUAL(OString("foo"), aFoo);
177         CPPUNIT_ASSERT(aMemStream.good());
178         CPPUNIT_ASSERT(!aMemStream.bad());
179         CPPUNIT_ASSERT(!aMemStream.eof());
180 
181         aMemStream.Seek(0);
182         foo[0] = 10;
183         aFoo = read_uInt8_lenPrefixed_uInt8s_ToOString(aMemStream);
184         CPPUNIT_ASSERT_EQUAL(OString("foobar"), aFoo);
185         CPPUNIT_ASSERT(!aMemStream.good());
186         CPPUNIT_ASSERT(!aMemStream.bad());
187         CPPUNIT_ASSERT(aMemStream.eof());
188 
189         aMemStream.SetEndian(SvStreamEndian::BIG);
190         aMemStream.Seek(0);
191         foo[0] = 0;
192         foo[1] = 3;
193         aFoo = read_uInt16_lenPrefixed_uInt8s_ToOString(aMemStream);
194         CPPUNIT_ASSERT_EQUAL(OString("oob"), aFoo);
195         CPPUNIT_ASSERT(aMemStream.good());
196         CPPUNIT_ASSERT(!aMemStream.bad());
197         CPPUNIT_ASSERT(!aMemStream.eof());
198     }
199 
test_readline()200     void Test::test_readline()
201     {
202         char foo[] = "foo\nbar\n\n";
203         SvMemoryStream aMemStream(foo, SAL_N_ELEMENTS(foo)-1, StreamMode::READ);
204 
205         OString aFoo;
206         bool bRet;
207 
208         bRet = aMemStream.ReadLine(aFoo);
209         CPPUNIT_ASSERT(bRet);
210         CPPUNIT_ASSERT_EQUAL(OString("foo"), aFoo);
211         CPPUNIT_ASSERT(aMemStream.good());
212 
213         bRet = aMemStream.ReadLine(aFoo);
214         CPPUNIT_ASSERT(bRet);
215         CPPUNIT_ASSERT_EQUAL(OString("bar"), aFoo);
216         CPPUNIT_ASSERT(aMemStream.good());
217 
218         bRet = aMemStream.ReadLine(aFoo);
219         CPPUNIT_ASSERT(bRet);
220         CPPUNIT_ASSERT(aFoo.isEmpty());
221         CPPUNIT_ASSERT(aMemStream.good());
222 
223         bRet = aMemStream.ReadLine(aFoo);
224         CPPUNIT_ASSERT(!bRet);
225         CPPUNIT_ASSERT(aFoo.isEmpty());
226         CPPUNIT_ASSERT(aMemStream.eof());
227 
228         foo[3] = 0; //test reading embedded nulls
229 
230         aMemStream.Seek(0);
231         bRet = aMemStream.ReadLine(aFoo);
232         CPPUNIT_ASSERT(bRet);
233         CPPUNIT_ASSERT(aFoo.getLength() == 7 && aFoo[3] == 0);
234         CPPUNIT_ASSERT(aMemStream.good());
235 
236         std::string sStr(foo, RTL_CONSTASCII_LENGTH(foo));
237         std::istringstream iss(sStr, std::istringstream::in);
238         std::getline(iss, sStr, '\n');
239         //embedded null read as expected
240         CPPUNIT_ASSERT(sStr.size() == 7 && sStr[3] == 0);
241         CPPUNIT_ASSERT(iss.good());
242 
243         bRet = aMemStream.ReadLine(aFoo);
244         CPPUNIT_ASSERT(bRet);
245         CPPUNIT_ASSERT(aFoo.isEmpty());
246         CPPUNIT_ASSERT(aMemStream.good());
247 
248         std::getline(iss, sStr, '\n');
249         CPPUNIT_ASSERT(sStr.empty());
250         CPPUNIT_ASSERT(iss.good());
251 
252         bRet = aMemStream.ReadLine(aFoo);
253         CPPUNIT_ASSERT(!bRet);
254         CPPUNIT_ASSERT(aFoo.isEmpty());
255         CPPUNIT_ASSERT(aMemStream.eof() && !aMemStream.bad());
256 
257         std::getline(iss, sStr, '\n');
258         CPPUNIT_ASSERT(sStr.empty());
259         CPPUNIT_ASSERT(iss.eof() && !iss.bad());
260 
261         char bar[] = "foo";
262         SvMemoryStream aMemStreamB(bar, SAL_N_ELEMENTS(bar)-1, StreamMode::READ);
263         bRet = aMemStreamB.ReadLine(aFoo);
264         CPPUNIT_ASSERT(bRet);
265         CPPUNIT_ASSERT_EQUAL(OString("foo"), aFoo);
266         CPPUNIT_ASSERT(!aMemStreamB.eof()); //<-- diff A
267 
268         std::istringstream issB(bar, std::istringstream::in);
269         std::getline(issB, sStr, '\n');
270         CPPUNIT_ASSERT_EQUAL(std::string("foo"), sStr);
271         CPPUNIT_ASSERT(issB.eof());         //<-- diff A
272     }
273 
274     CPPUNIT_TEST_SUITE_REGISTRATION(Test);
275 }
276 
277 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
278