1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
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 <unotools/tempfile.hxx>
18 //Tests for eofbit/badbit/goodbit/failbit
23 class Test
: public CppUnit::TestFixture
26 void test_stdstream();
27 void test_fastostring();
28 void test_read_cstring();
29 void test_read_pstring();
31 void test_makereadonly();
32 void test_write_unicode();
34 CPPUNIT_TEST_SUITE(Test
);
35 CPPUNIT_TEST(test_stdstream
);
36 CPPUNIT_TEST(test_fastostring
);
37 CPPUNIT_TEST(test_read_cstring
);
38 CPPUNIT_TEST(test_read_pstring
);
39 CPPUNIT_TEST(test_readline
);
40 CPPUNIT_TEST(test_makereadonly
);
41 CPPUNIT_TEST(test_write_unicode
);
42 CPPUNIT_TEST_SUITE_END();
45 void Test::test_stdstream()
48 std::istringstream
iss(foo
, std::istringstream::in
);
49 SvMemoryStream
aMemStream(foo
, SAL_N_ELEMENTS(foo
)-1, StreamMode::READ
);
53 CPPUNIT_ASSERT_EQUAL('f', std_a
);
56 aMemStream
.ReadChar( tools_a
);
57 CPPUNIT_ASSERT_EQUAL('f', tools_a
);
59 iss
.seekg(0, std::ios_base::end
);
60 //seeking to end doesn't set eof, reading past eof does
61 CPPUNIT_ASSERT(!iss
.eof());
62 CPPUNIT_ASSERT(iss
.good());
64 aMemStream
.Seek(STREAM_SEEK_TO_END
);
65 //seeking to end doesn't set eof, reading past eof does
66 CPPUNIT_ASSERT(!aMemStream
.eof());
67 CPPUNIT_ASSERT(aMemStream
.good());
72 CPPUNIT_ASSERT(iss
.eof());
73 //a failed read doesn't change the data, it remains unchanged
74 CPPUNIT_ASSERT_EQUAL(static_cast<char>(78), std_a
);
75 //nothing wrong with the stream, so not bad
76 CPPUNIT_ASSERT(!iss
.bad());
77 //yet, the read didn't succeed
78 CPPUNIT_ASSERT(!iss
.good());
79 CPPUNIT_ASSERT_EQUAL((std::ios::failbit
|std::ios::eofbit
), iss
.rdstate());
82 aMemStream
.ReadChar( tools_a
);
84 CPPUNIT_ASSERT(aMemStream
.eof());
85 //a failed read doesn't change the data, it remains unchanged
86 CPPUNIT_ASSERT_EQUAL(static_cast<char>(78), tools_a
);
87 //nothing wrong with the stream, so not bad
88 CPPUNIT_ASSERT(!aMemStream
.bad());
89 //yet, the read didn't succeed
90 CPPUNIT_ASSERT(!aMemStream
.good());
92 //set things up so that there is only one byte available on an attempt
93 //to read a two-byte sal_uInt16. The byte should be consumed, but the
94 //operation should fail, and tools_b should remain unchanged,
95 sal_uInt16 tools_b
= 0x1122;
96 aMemStream
.SeekRel(-1);
97 CPPUNIT_ASSERT(!aMemStream
.eof());
98 CPPUNIT_ASSERT(aMemStream
.good());
99 aMemStream
.ReadUInt16( tools_b
);
100 CPPUNIT_ASSERT(!aMemStream
.good());
101 CPPUNIT_ASSERT(aMemStream
.eof());
102 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(0x1122), tools_b
);
106 CPPUNIT_ASSERT(iss
.good());
108 CPPUNIT_ASSERT_EQUAL('f', std_a
);
111 CPPUNIT_ASSERT(aMemStream
.good());
112 aMemStream
.ReadChar( tools_a
);
113 CPPUNIT_ASSERT_EQUAL('f', tools_a
);
115 //failbit is rather subtle wrt e.g seeks
121 CPPUNIT_ASSERT(iss
.good());
122 iss
.read(buffer
, sizeof(buffer
));
123 CPPUNIT_ASSERT_EQUAL(static_cast<std::streamsize
>(3), iss
.gcount());
124 CPPUNIT_ASSERT(!iss
.good());
125 CPPUNIT_ASSERT(!iss
.bad());
126 CPPUNIT_ASSERT(iss
.eof());
129 CPPUNIT_ASSERT(aMemStream
.good());
130 std::size_t nRet
= aMemStream
.ReadBytes(buffer
, sizeof(buffer
));
131 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(3), nRet
);
132 CPPUNIT_ASSERT(!aMemStream
.good());
133 CPPUNIT_ASSERT(!aMemStream
.bad());
134 CPPUNIT_ASSERT(aMemStream
.eof());
137 void Test::test_fastostring()
139 char foo
[] = "foobar";
140 SvMemoryStream
aMemStream(foo
, SAL_N_ELEMENTS(foo
)-1, StreamMode::READ
);
142 OString aOne
= read_uInt8s_ToOString(aMemStream
, 3);
143 CPPUNIT_ASSERT_EQUAL("foo"_ostr
, aOne
);
145 OString aTwo
= read_uInt8s_ToOString(aMemStream
, 3);
146 CPPUNIT_ASSERT_EQUAL("bar"_ostr
, aTwo
);
148 OString aThree
= read_uInt8s_ToOString(aMemStream
, 3);
149 CPPUNIT_ASSERT(aThree
.isEmpty());
153 OString aFour
= read_uInt8s_ToOString(aMemStream
, 100);
154 CPPUNIT_ASSERT_EQUAL(OString(foo
), aFour
);
157 void Test::test_read_cstring()
159 char foo
[] = "foobar";
160 SvMemoryStream
aMemStream(foo
, SAL_N_ELEMENTS(foo
)-1, StreamMode::READ
);
162 OString aOne
= read_zeroTerminated_uInt8s_ToOString(aMemStream
);
163 CPPUNIT_ASSERT_EQUAL("foobar"_ostr
, aOne
);
164 CPPUNIT_ASSERT(!aMemStream
.good());
165 CPPUNIT_ASSERT(!aMemStream
.bad());
166 CPPUNIT_ASSERT(aMemStream
.eof());
170 OString aTwo
= read_zeroTerminated_uInt8s_ToOString(aMemStream
);
171 CPPUNIT_ASSERT_EQUAL("foo"_ostr
, aTwo
);
172 CPPUNIT_ASSERT(aMemStream
.good());
175 void Test::test_read_pstring()
177 char foo
[] = "\3foobar";
178 SvMemoryStream
aMemStream(foo
, SAL_N_ELEMENTS(foo
)-1, StreamMode::READ
);
180 OString aFoo
= read_uInt8_lenPrefixed_uInt8s_ToOString(aMemStream
);
181 CPPUNIT_ASSERT_EQUAL("foo"_ostr
, aFoo
);
182 CPPUNIT_ASSERT(aMemStream
.good());
183 CPPUNIT_ASSERT(!aMemStream
.bad());
184 CPPUNIT_ASSERT(!aMemStream
.eof());
188 aFoo
= read_uInt8_lenPrefixed_uInt8s_ToOString(aMemStream
);
189 CPPUNIT_ASSERT_EQUAL("foobar"_ostr
, aFoo
);
190 CPPUNIT_ASSERT(!aMemStream
.good());
191 CPPUNIT_ASSERT(!aMemStream
.bad());
192 CPPUNIT_ASSERT(aMemStream
.eof());
194 aMemStream
.SetEndian(SvStreamEndian::BIG
);
198 aFoo
= read_uInt16_lenPrefixed_uInt8s_ToOString(aMemStream
);
199 CPPUNIT_ASSERT_EQUAL("oob"_ostr
, aFoo
);
200 CPPUNIT_ASSERT(aMemStream
.good());
201 CPPUNIT_ASSERT(!aMemStream
.bad());
202 CPPUNIT_ASSERT(!aMemStream
.eof());
205 void Test::test_readline()
207 char foo
[] = "foo\nbar\n\n";
208 SvMemoryStream
aMemStream(foo
, SAL_N_ELEMENTS(foo
)-1, StreamMode::READ
);
213 bRet
= aMemStream
.ReadLine(aFoo
);
214 CPPUNIT_ASSERT(bRet
);
215 CPPUNIT_ASSERT_EQUAL("foo"_ostr
, aFoo
);
216 CPPUNIT_ASSERT(aMemStream
.good());
218 bRet
= aMemStream
.ReadLine(aFoo
);
219 CPPUNIT_ASSERT(bRet
);
220 CPPUNIT_ASSERT_EQUAL("bar"_ostr
, aFoo
);
221 CPPUNIT_ASSERT(aMemStream
.good());
223 bRet
= aMemStream
.ReadLine(aFoo
);
224 CPPUNIT_ASSERT(bRet
);
225 CPPUNIT_ASSERT(aFoo
.isEmpty());
226 CPPUNIT_ASSERT(aMemStream
.good());
228 bRet
= aMemStream
.ReadLine(aFoo
);
229 CPPUNIT_ASSERT(!bRet
);
230 CPPUNIT_ASSERT(aFoo
.isEmpty());
231 CPPUNIT_ASSERT(aMemStream
.eof());
233 foo
[3] = 0; //test reading embedded nulls
236 bRet
= aMemStream
.ReadLine(aFoo
);
237 CPPUNIT_ASSERT(bRet
);
238 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aFoo
.getLength());
239 CPPUNIT_ASSERT_EQUAL('\0', aFoo
[3]);
240 CPPUNIT_ASSERT(aMemStream
.good());
242 std::string
sStr(foo
, RTL_CONSTASCII_LENGTH(foo
));
243 std::istringstream
iss(sStr
, std::istringstream::in
);
244 std::getline(iss
, sStr
, '\n');
245 //embedded null read as expected
246 CPPUNIT_ASSERT_EQUAL(std::string::size_type(7), sStr
.size());
247 CPPUNIT_ASSERT_EQUAL('\0', sStr
[3]);
248 CPPUNIT_ASSERT(iss
.good());
250 bRet
= aMemStream
.ReadLine(aFoo
);
251 CPPUNIT_ASSERT(bRet
);
252 CPPUNIT_ASSERT(aFoo
.isEmpty());
253 CPPUNIT_ASSERT(aMemStream
.good());
255 std::getline(iss
, sStr
, '\n');
256 CPPUNIT_ASSERT(sStr
.empty());
257 CPPUNIT_ASSERT(iss
.good());
259 bRet
= aMemStream
.ReadLine(aFoo
);
260 CPPUNIT_ASSERT(!bRet
);
261 CPPUNIT_ASSERT(aFoo
.isEmpty());
262 CPPUNIT_ASSERT(aMemStream
.eof());
263 CPPUNIT_ASSERT(!aMemStream
.bad());
265 std::getline(iss
, sStr
, '\n');
266 CPPUNIT_ASSERT(sStr
.empty());
267 CPPUNIT_ASSERT(iss
.eof());
268 CPPUNIT_ASSERT(!iss
.bad());
271 SvMemoryStream
aMemStreamB(bar
, SAL_N_ELEMENTS(bar
)-1, StreamMode::READ
);
272 bRet
= aMemStreamB
.ReadLine(aFoo
);
273 CPPUNIT_ASSERT(bRet
);
274 CPPUNIT_ASSERT_EQUAL("foo"_ostr
, aFoo
);
275 CPPUNIT_ASSERT(!aMemStreamB
.eof()); //<-- diff A
277 std::istringstream
issB(bar
, std::istringstream::in
);
278 std::getline(issB
, sStr
, '\n');
279 CPPUNIT_ASSERT_EQUAL(std::string("foo"), sStr
);
280 CPPUNIT_ASSERT(issB
.eof()); //<-- diff A
283 void Test::test_makereadonly()
285 SvMemoryStream aMemStream
;
286 CPPUNIT_ASSERT(aMemStream
.IsWritable());
287 CPPUNIT_ASSERT_EQUAL(sal_uInt64(0), aMemStream
.GetSize());
288 aMemStream
.WriteInt64(21);
289 CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE
, aMemStream
.GetError());
290 CPPUNIT_ASSERT_EQUAL(sal_uInt64(8), aMemStream
.GetSize());
292 aMemStream
.MakeReadOnly();
293 CPPUNIT_ASSERT(!aMemStream
.IsWritable());
294 CPPUNIT_ASSERT_EQUAL(sal_uInt64(8), aMemStream
.GetSize());
295 aMemStream
.WriteInt64(42);
296 CPPUNIT_ASSERT_EQUAL(ERRCODE_IO_CANTWRITE
, aMemStream
.GetError());
297 CPPUNIT_ASSERT_EQUAL(sal_uInt64(8), aMemStream
.GetSize());
299 aMemStream
.ResetError();
300 // Check that seeking past the end doesn't resize a read-only stream.
301 // This apparently doesn't set an error, but at least it shouldn't
303 aMemStream
.Seek(1024LL*1024*1024*3);
304 CPPUNIT_ASSERT_EQUAL(sal_uInt64(8), aMemStream
.GetSize());
306 aMemStream
.ResetError();
309 aMemStream
.ReadInt64(res
);
310 CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE
, aMemStream
.GetError());
311 CPPUNIT_ASSERT_EQUAL(sal_Int64(21), res
);
314 void Test::test_write_unicode()
316 constexpr OUString
write(u
"abc"_ustr
);
317 utl::TempFileNamed
aTempFile(u
"test_write_unicode");
318 aTempFile
.EnableKillingFile();
320 SvStream
& s
= *aTempFile
.GetStream(StreamMode::WRITE
);
321 s
.SetEndian(SvStreamEndian::BIG
);
322 if (!s
.IsEndianSwap())
323 s
.SetEndian(SvStreamEndian::LITTLE
);
324 CPPUNIT_ASSERT(s
.IsEndianSwap());
325 // StartWritingUnicodeText must switch to no endian swapping and write 0xfeff
326 s
.StartWritingUnicodeText();
327 // Without the fix in place, this would fail
328 CPPUNIT_ASSERT(!s
.IsEndianSwap());
329 s
.WriteUnicodeOrByteText(write
, RTL_TEXTENCODING_UNICODE
);
330 aTempFile
.CloseStream();
333 SvStream
& s
= *aTempFile
.GetStream(StreamMode::READ
);
334 s
.SetEndian(SvStreamEndian::BIG
);
335 if (!s
.IsEndianSwap())
336 s
.SetEndian(SvStreamEndian::LITTLE
);
337 CPPUNIT_ASSERT(s
.IsEndianSwap());
338 s
.StartReadingUnicodeText(RTL_TEXTENCODING_DONTKNOW
);
339 CPPUNIT_ASSERT(!s
.IsEndianSwap());
340 CPPUNIT_ASSERT_EQUAL(sal_uInt64(2), s
.Tell()); // after BOM
342 CPPUNIT_ASSERT(s
.ReadUniOrByteStringLine(read
, RTL_TEXTENCODING_UNICODE
));
343 // Without the fix in place, this would fail with
346 CPPUNIT_ASSERT_EQUAL(write
, read
);
347 aTempFile
.CloseStream();
351 CPPUNIT_TEST_SUITE_REGISTRATION(Test
);
354 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */