1/*****************************************************************************/
2// Haiku Translation Kit Test
3// Authors: Brian Matzon <brian@matzon.dk>, Michael Wilber
4// Version:
5//
6// This is the Test application for BBitmapStream
7//
8//
9// This application and all source files used in its construction, except
10// where noted, are licensed under the MIT License, and have been written
11// and are:
12//
13// Copyright (c) 2002 Haiku Project
14//
15// Permission is hereby granted, free of charge, to any person obtaining a
16// copy of this software and associated documentation files (the "Software"),
17// to deal in the Software without restriction, including without limitation
18// the rights to use, copy, modify, merge, publish, distribute, sublicense,
19// and/or sell copies of the Software, and to permit persons to whom the
20// Software is furnished to do so, subject to the following conditions:
21//
22// The above copyright notice and this permission notice shall be included
23// in all copies or substantial portions of the Software.
24//
25// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
26// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31// DEALINGS IN THE SOFTWARE.
32/*****************************************************************************/
33#include "BitmapStreamTest.h"
34
35#include <TranslatorRoster.h>
36#include <Application.h>
37#include <Bitmap.h>
38
39#include <stdio.h>
40#include <string.h>
41
42/* cppunit framework */
43#include <cppunit/Test.h>
44#include <cppunit/TestCaller.h>
45#include <cppunit/TestSuite.h>
46
47/**
48 * Default constructor - no work
49 */
50BitmapStreamTest::BitmapStreamTest(std::string name)
51	: BTestCase(name)
52{
53}
54
55/**
56 * Default destructor - no work
57 */
58BitmapStreamTest::~BitmapStreamTest()
59{
60}
61
62CppUnit::Test *
63BitmapStreamTest::Suite()
64{
65	/* create our suite */
66	CppUnit::TestSuite *suite = new CppUnit::TestSuite("BitmapStream");
67	typedef CppUnit::TestCaller<BitmapStreamTest> TC;
68
69	/* add tests */
70	suite->addTest(new TC("BitmapStreamTest::Constructor Test",
71		&BitmapStreamTest::ConstructorTest));
72
73	suite->addTest(new TC("BitmapStreamTest::DetachBitmap Test",
74		&BitmapStreamTest::DetachBitmapTest));
75
76	suite->addTest(new TC("BitmapStreamTest::Seek Test",
77		&BitmapStreamTest::SeekTest));
78
79	suite->addTest(new TC("BitmapStreamTest::SetSize Test",
80		&BitmapStreamTest::SetSizeTest));
81
82	suite->addTest(new TC("BitmapStreamTest::ReadWrite Test",
83		&BitmapStreamTest::ReadWriteTest));
84
85	return suite;
86}
87
88/**
89 * Tests:
90 * BBitmapStream(BBitmap *map = NULL)
91 */
92void
93BitmapStreamTest::ConstructorTest()
94{
95	BApplication
96		app("application/x-vnd.Haiku-translationkit_bitmapstreamtest");
97
98	//BBitmapStream with no bitmap supplied
99	NextSubTest();
100	BBitmapStream streamEmpty;
101	BBitmap *pbits = NULL;
102	CPPUNIT_ASSERT(streamEmpty.Position() == 0);
103	CPPUNIT_ASSERT(streamEmpty.Size() == 0);
104	CPPUNIT_ASSERT(streamEmpty.DetachBitmap(&pbits) == B_ERROR);
105	CPPUNIT_ASSERT(pbits == NULL);
106
107	//BBitmapStream with an empty BBitmap
108	NextSubTest();
109	pbits = new BBitmap(BRect(0,0,5,5), B_RGB32);
110	CPPUNIT_ASSERT(pbits);
111
112	BBitmapStream *pstreamWithBits;
113	pstreamWithBits = new BBitmapStream(pbits);
114	CPPUNIT_ASSERT(pstreamWithBits);
115	CPPUNIT_ASSERT(pstreamWithBits->Position() == 0);
116	CPPUNIT_ASSERT(pstreamWithBits->Size() == 176);
117	BBitmap *poutbits = NULL;
118	CPPUNIT_ASSERT(pstreamWithBits->DetachBitmap(&poutbits) == B_OK);
119	CPPUNIT_ASSERT(pbits == poutbits);
120
121	delete pstreamWithBits;
122	pstreamWithBits = NULL;
123
124	delete pbits;
125	pbits = NULL;
126
127	//constructor is also created with a value in DetachBitmapTest()
128}
129
130/**
131 * Tests:
132 * status_t DetachBitmap(BBitmap **outMap)
133 */
134void
135BitmapStreamTest::DetachBitmapTest()
136{
137	BApplication
138		app("application/x-vnd.Haiku-translationkit_bitmapstreamtest");
139
140	NextSubTest();
141	BFile file("../src/tests/kits/translation/data/images/image.jpg",
142		B_READ_ONLY);
143	CPPUNIT_ASSERT(file.InitCheck() == B_OK);
144
145	//translate a file into a BBitmapStream
146	NextSubTest();
147	BBitmapStream *pstream = new BBitmapStream;
148	BBitmap *pbits = NULL;
149	BTranslatorRoster *proster = BTranslatorRoster::Default();
150	CPPUNIT_ASSERT(proster->Translate(&file, NULL, NULL, pstream,
151		B_TRANSLATOR_BITMAP) == B_OK);
152	CPPUNIT_ASSERT(pstream->DetachBitmap(&pbits) == B_NO_ERROR);
153	CPPUNIT_ASSERT(pbits);
154	CPPUNIT_ASSERT(pbits->IsValid());
155
156	//B_BAD_VALUE
157	NextSubTest();
158	CPPUNIT_ASSERT(pstream->DetachBitmap(NULL) == B_BAD_VALUE);
159
160	//Attempt double detach
161	NextSubTest();
162	BBitmap *pdbits = NULL;
163	CPPUNIT_ASSERT(pstream->DetachBitmap(&pdbits) == B_ERROR);
164
165	//make sure that deleting the stream
166	//does not destroy the detached BBitmap
167	NextSubTest();
168	delete pstream;
169	pstream = NULL;
170	CPPUNIT_ASSERT(pbits->IsValid());
171	CPPUNIT_ASSERT(pbits->BitsLength() > 0);
172
173	//create a new stream using the BBitmap
174	//created by the first stream
175	NextSubTest();
176	BBitmapStream *pfullstream = new BBitmapStream(pbits);
177	CPPUNIT_ASSERT(pfullstream->Position() == 0);
178	CPPUNIT_ASSERT(pfullstream->Size() ==
179		pbits->BitsLength() + sizeof(TranslatorBitmap));
180
181	//deleting pfullstream should also destroy
182	//the bitmap attached to it (pbits)
183	NextSubTest();
184	delete pfullstream;
185	pfullstream = NULL;
186	CPPUNIT_ASSERT(pbits->BitsLength() == 0);
187}
188
189/**
190 * Tests:
191 * ssize_t ReadAt(off_t pos, void *buffer, size_t numBytes)
192 * ssize_t WriteAt(off_t pos, void *buffer, size_t numBytes)
193 */
194void
195BitmapStreamTest::ReadWriteTest()
196{
197	NextSubTest();
198	BApplication
199		app("application/x-vnd.Haiku-translationkit_bitmapstreamtest");
200	char chbuf[sizeof(TranslatorBitmap)],
201		chheader[sizeof(TranslatorBitmap)], *pch;
202	TranslatorBitmap sheader;
203	BBitmapStream stream;
204	int32 width = 5, height = 5;
205
206	sheader.magic = B_TRANSLATOR_BITMAP;
207	sheader.bounds.left = 0;
208	sheader.bounds.top = 0;
209	sheader.bounds.right = width - 1;
210	sheader.bounds.bottom = height - 1;
211	sheader.rowBytes = width * 4;
212	sheader.colors = B_RGB32;
213	sheader.dataSize = sheader.rowBytes * height;
214
215	memcpy(&chheader, &sheader, sizeof(TranslatorBitmap));
216	CPPUNIT_ASSERT(swap_data(B_UINT32_TYPE, &(chheader[0]),
217		sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) == B_OK);
218
219	// Write header, 1 byte at a time
220	NextSubTest();
221	off_t nPos;
222	for (nPos = 0; nPos < sizeof(TranslatorBitmap); nPos++) {
223		pch = (char *)(&(chheader[0])) + nPos;
224		CPPUNIT_ASSERT(stream.WriteAt(nPos, pch, 1) == 1);
225	}
226	// Check size
227	NextSubTest();
228	CPPUNIT_ASSERT(stream.Size() ==
229		sizeof(TranslatorBitmap) + sheader.dataSize);
230
231	// Read header, 1 byte at a time
232	NextSubTest();
233	for (nPos = 0; nPos < sizeof(TranslatorBitmap); nPos++) {
234		pch = (char *)(&(chheader[0])) + nPos;
235		CPPUNIT_ASSERT(stream.ReadAt(nPos, &(chbuf[0]), 1) == 1);
236		CPPUNIT_ASSERT(pch[0] == chbuf[0]);
237	}
238
239	// Write header, all at once
240	NextSubTest();
241	pch = (char *)(&(chheader[0]));
242	CPPUNIT_ASSERT(stream.WriteAt(0, pch,
243		sizeof(TranslatorBitmap)) == sizeof(TranslatorBitmap));
244	// Check size
245	NextSubTest();
246	CPPUNIT_ASSERT(stream.Size() ==
247		sizeof(TranslatorBitmap) + sheader.dataSize);
248
249	// Read header, all at once
250	NextSubTest();
251	CPPUNIT_ASSERT(stream.ReadAt(0, &(chbuf[0]),
252		sizeof(TranslatorBitmap)) == sizeof(TranslatorBitmap));
253	CPPUNIT_ASSERT(memcmp(pch, &(chbuf[0]), sizeof(TranslatorBitmap)) == 0);
254
255	// Write bitmap data
256	NextSubTest();
257	int32 bytesLeft = sheader.dataSize;
258	char byt = 0xCF;
259	nPos = sizeof(TranslatorBitmap);
260	while (bytesLeft--)
261		CPPUNIT_ASSERT(stream.WriteAt(nPos++, &byt, 1) == 1);
262	// Check size
263	NextSubTest();
264	CPPUNIT_ASSERT(stream.Size() ==
265		sizeof(TranslatorBitmap) + sheader.dataSize);
266
267	// Test reading zero bytes
268	NextSubTest();
269	CPPUNIT_ASSERT(stream.ReadAt(stream.Size(), &(chbuf[0]), 0) == 0);
270	CPPUNIT_ASSERT(stream.ReadAt(sheader.dataSize + 1000, &(chbuf[0]), 0) == 0);
271	CPPUNIT_ASSERT(stream.ReadAt(-1, &(chbuf[0]), 0) == 0);
272
273	// Read bitmap data
274	NextSubTest();
275	#if !TEST_R5
276		// This test fails with Be's version because of a bug.
277		// Be's BBitmapStream::ReadAt() has strange behavior in cases
278		// where the pos parameter of ReadAt() is != BBitmapStream::Position().
279		// If BBitmapStream::Read() is used instead, it calls
280		// BBitmapStream::ReadAt() with pos = BBitmapStream::Position(),
281		// so, this issue is rarely a problem because Read() is most often used.
282		bytesLeft = sheader.dataSize;
283		nPos = sizeof(TranslatorBitmap);
284		while (bytesLeft--) {
285			chbuf[0] = 0x99;
286			ssize_t rd = stream.ReadAt(nPos++, &(chbuf[0]), 1);
287			CPPUNIT_ASSERT(rd == 1);
288			CPPUNIT_ASSERT(chbuf[0] == byt);
289		}
290	#endif
291
292	// Send erroneous and weird data to WriteAt()
293	NextSubTest();
294	CPPUNIT_ASSERT(stream.WriteAt(0, &byt, 0) == 0);
295	CPPUNIT_ASSERT(stream.WriteAt(-1, &byt, 1) == B_BAD_VALUE);
296	CPPUNIT_ASSERT(stream.WriteAt(stream.Size(), &byt, 1) == B_BAD_VALUE);
297	CPPUNIT_ASSERT(stream.WriteAt(stream.Size() + 1, &byt, 1) == B_BAD_VALUE);
298	CPPUNIT_ASSERT(stream.WriteAt(0, NULL, 1) == B_BAD_VALUE);
299
300	// Send erroneous and weird data to ReadAt()
301	NextSubTest();
302	CPPUNIT_ASSERT(stream.ReadAt(0, &(chbuf[0]), 0) == 0);
303	CPPUNIT_ASSERT(stream.ReadAt(-1, &(chbuf[0]), 1) == B_BAD_VALUE);
304	CPPUNIT_ASSERT(stream.ReadAt(stream.Size(), &(chbuf[0]),
305		 1) == B_ERROR);
306	CPPUNIT_ASSERT(stream.ReadAt(stream.Size() + 1,
307		&(chbuf[0]), 1) == B_ERROR);
308	#if !TEST_R5
309		// Be's version doesn't check for NULL
310		CPPUNIT_ASSERT(stream.ReadAt(0, NULL, 1) == B_BAD_VALUE);
311	#endif
312
313	// There is a segment violation with Be's version when stream is destroyed.
314	// Don't yet know why.
315}
316
317/**
318 * Tests:
319 * off_t Seek(off_t position, uint32 whence)
320 * off_t Position() const
321 */
322void
323BitmapStreamTest::SeekTest()
324{
325	BApplication
326		app("application/x-vnd.Haiku-translationkit_bitmapstreamtest");
327
328	NextSubTest();
329	BFile file("../src/tests/kits/translation/data/images/image.jpg",
330		B_READ_ONLY);
331	CPPUNIT_ASSERT(file.InitCheck() == B_OK);
332
333	//translate a file into a BBitmapStream
334	NextSubTest();
335	BBitmapStream stream;
336	BTranslatorRoster *proster = BTranslatorRoster::Default();
337	CPPUNIT_ASSERT(proster->Translate(&file, NULL, NULL, &stream,
338		B_TRANSLATOR_BITMAP) == B_OK);
339
340	// Test SEEK_END
341	NextSubTest();
342	off_t nPos;
343	nPos = stream.Size();
344	CPPUNIT_ASSERT(stream.Seek(0, SEEK_END) == nPos);
345	CPPUNIT_ASSERT(stream.Position() == nPos);
346
347	nPos = 0;
348	CPPUNIT_ASSERT(stream.Seek(-stream.Size(), SEEK_END) == nPos);
349	CPPUNIT_ASSERT(stream.Position() == nPos);
350
351	nPos = stream.Size() - 15;
352	CPPUNIT_ASSERT(stream.Seek(-15, SEEK_END) == nPos);
353	CPPUNIT_ASSERT(stream.Position() == nPos);
354
355	CPPUNIT_ASSERT(stream.Seek(1, SEEK_END) == B_BAD_VALUE);
356	CPPUNIT_ASSERT(stream.Position() == nPos);
357
358	CPPUNIT_ASSERT(stream.Seek(-(stream.Size() + 1),
359		SEEK_END) == B_BAD_VALUE);
360	CPPUNIT_ASSERT(stream.Position() == nPos);
361
362	// Test SEEK_SET
363	NextSubTest();
364	nPos = 0;
365	CPPUNIT_ASSERT(stream.Seek(0, SEEK_SET) == nPos);
366	CPPUNIT_ASSERT(stream.Position() == nPos);
367
368	nPos = stream.Size();
369	CPPUNIT_ASSERT(stream.Seek(nPos, SEEK_SET) == nPos);
370	CPPUNIT_ASSERT(stream.Position() == nPos);
371
372	nPos /= 2;
373	CPPUNIT_ASSERT(stream.Seek(nPos, SEEK_SET) == nPos);
374	CPPUNIT_ASSERT(stream.Position() == nPos);
375
376	CPPUNIT_ASSERT(stream.Seek(-1, SEEK_SET) == B_BAD_VALUE);
377	CPPUNIT_ASSERT(stream.Position() == nPos);
378
379	CPPUNIT_ASSERT(stream.Seek(stream.Size() + 1, SEEK_SET) == B_BAD_VALUE);
380	CPPUNIT_ASSERT(stream.Position() == nPos);
381
382	// Test SEEK_CUR
383	NextSubTest();
384	CPPUNIT_ASSERT(stream.Seek(-nPos, SEEK_CUR) == 0);
385	CPPUNIT_ASSERT(stream.Position() == 0);
386
387	nPos = stream.Size();
388	CPPUNIT_ASSERT(stream.Seek(nPos, SEEK_CUR) == nPos);
389	CPPUNIT_ASSERT(stream.Position() == nPos);
390
391	nPos -= 11;
392	CPPUNIT_ASSERT(stream.Seek(-11, SEEK_CUR) == nPos);
393	CPPUNIT_ASSERT(stream.Position() == nPos);
394
395	nPos += 8;
396	CPPUNIT_ASSERT(stream.Seek(8, SEEK_CUR) == nPos);
397	CPPUNIT_ASSERT(stream.Position() == nPos);
398
399	CPPUNIT_ASSERT(stream.Seek(-(stream.Position() + 1),
400		SEEK_CUR) == B_BAD_VALUE);
401	CPPUNIT_ASSERT(stream.Position() == nPos);
402
403	CPPUNIT_ASSERT(stream.Seek((stream.Size() - stream.Position()) + 1,
404		SEEK_CUR) == B_BAD_VALUE);
405	CPPUNIT_ASSERT(stream.Position() == nPos);
406}
407
408/**
409 * Tests:
410 * status_t SetSize(off_t size) const
411 */
412void
413BitmapStreamTest::SetSizeTest()
414{
415	BApplication
416		app("application/x-vnd.Haiku-translationkit_bitmapstreamtest");
417
418	NextSubTest();
419	BFile file("../src/tests/kits/translation/data/images/image.jpg",
420		B_READ_ONLY);
421	CPPUNIT_ASSERT(file.InitCheck() == B_OK);
422
423	//translate a file into a BBitmapStream
424	NextSubTest();
425	BBitmapStream stream;
426	BTranslatorRoster *proster = BTranslatorRoster::Default();
427	CPPUNIT_ASSERT(proster->Translate(&file, NULL, NULL, &stream,
428		B_TRANSLATOR_BITMAP) == B_OK);
429
430	// Send crap to SetSize
431	NextSubTest();
432	CPPUNIT_ASSERT(stream.SetSize(-1) == B_BAD_VALUE);
433	CPPUNIT_ASSERT(stream.SetSize(stream.Size() + 1) == B_BAD_VALUE);
434}
435