1// PNGTranslatorTest.cpp
2//
3// NOTE: Most of the PNG images used in this test are from PNGSuite:
4// http://www.schaik.com/pngsuite/pngsuite.html
5#include "PNGTranslatorTest.h"
6#include <cppunit/Test.h>
7#include <cppunit/TestCaller.h>
8#include <cppunit/TestSuite.h>
9#include <stdio.h>
10#include <string.h>
11#include <unistd.h>
12#include <image.h>
13#include <Translator.h>
14#include <TranslatorFormats.h>
15#include <TranslatorRoster.h>
16#include <Message.h>
17#include <View.h>
18#include <Rect.h>
19#include <String.h>
20#include <File.h>
21#include <DataIO.h>
22#include <Errors.h>
23#include <OS.h>
24#include "TranslatorTestAddOn.h"
25
26// PNG Translator Settings
27#define PNG_SETTING_INTERLACE "png /interlace"
28
29#define PNG_TRANSLATOR_VERSION B_TRANSLATION_MAKE_VERSION(1,0,0)
30
31#define PNG_IN_QUALITY 0.8
32#define PNG_IN_CAPABILITY 0.8
33#define PNG_OUT_QUALITY 0.8
34#define PNG_OUT_CAPABILITY 0.5
35
36#define BBT_IN_QUALITY 0.8
37#define BBT_IN_CAPABILITY 0.6
38#define BBT_OUT_QUALITY 0.5
39#define BBT_OUT_CAPABILITY 0.4
40
41// Test Images Directory
42#define IMAGES_DIR "/boot/home/resources/png/"
43
44// Suite
45CppUnit::Test *
46PNGTranslatorTest::Suite()
47{
48	CppUnit::TestSuite *suite = new CppUnit::TestSuite();
49	typedef CppUnit::TestCaller<PNGTranslatorTest> TC;
50
51	suite->addTest(
52		new TC("PNGTranslator IdentifyTest",
53			&PNGTranslatorTest::IdentifyTest));
54
55	suite->addTest(
56		new TC("PNGTranslator TranslateTest",
57			&PNGTranslatorTest::TranslateTest));
58
59#if !TEST_R5
60	suite->addTest(
61		new TC("PNGTranslator LoadAddOnTest",
62			&PNGTranslatorTest::LoadAddOnTest));
63#endif
64
65	return suite;
66}
67
68// setUp
69void
70PNGTranslatorTest::setUp()
71{
72	BTestCase::setUp();
73}
74
75// tearDown
76void
77PNGTranslatorTest::tearDown()
78{
79	BTestCase::tearDown();
80}
81
82void
83CheckBits_PNG(translator_info *pti)
84{
85	CheckTranslatorInfo(pti, B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP,
86		BBT_IN_QUALITY, BBT_IN_CAPABILITY, "Be Bitmap Format (PNGTranslator)",
87		"image/x-be-bitmap");
88}
89
90void
91CheckPNG(translator_info *pti)
92{
93	CheckTranslatorInfo(pti, B_PNG_FORMAT, B_TRANSLATOR_BITMAP,
94		PNG_IN_QUALITY, PNG_IN_CAPABILITY, "PNG image", "image/png");
95}
96
97void
98IdentifyTests(PNGTranslatorTest *ptest, BTranslatorRoster *proster,
99	const char **paths, int32 len, bool bbits)
100{
101	translator_info ti;
102	printf(" [%d] ", (int) bbits);
103
104	BString fullpath;
105
106	for (int32 i = 0; i < len; i++) {
107		ptest->NextSubTest();
108		BFile file;
109		fullpath = IMAGES_DIR;
110		fullpath += paths[i];
111		printf(" [%s] ", fullpath.String());
112		CPPUNIT_ASSERT(file.SetTo(fullpath.String(), B_READ_ONLY) == B_OK);
113
114		// Identify (output: B_TRANSLATOR_ANY_TYPE)
115		ptest->NextSubTest();
116		memset(&ti, 0, sizeof(translator_info));
117		CPPUNIT_ASSERT(proster->Identify(&file, NULL, &ti) == B_OK);
118		if (bbits)
119			CheckBits_PNG(&ti);
120		else
121			CheckPNG(&ti);
122
123		// Identify (output: B_TRANSLATOR_BITMAP)
124		ptest->NextSubTest();
125		memset(&ti, 0, sizeof(translator_info));
126		CPPUNIT_ASSERT(proster->Identify(&file, NULL, &ti, 0, NULL,
127			B_TRANSLATOR_BITMAP) == B_OK);
128		if (bbits)
129			CheckBits_PNG(&ti);
130		else
131			CheckPNG(&ti);
132
133		// Identify (output: B_PNG_FORMAT)
134		ptest->NextSubTest();
135		memset(&ti, 0, sizeof(translator_info));
136		CPPUNIT_ASSERT(proster->Identify(&file, NULL, &ti, 0, NULL,
137			B_PNG_FORMAT) == B_OK);
138		if (bbits)
139			CheckBits_PNG(&ti);
140		else
141			CheckPNG(&ti);
142	}
143}
144
145void
146PNGTranslatorTest::IdentifyTest()
147{
148	// Init
149	NextSubTest();
150	status_t result = B_ERROR;
151	BTranslatorRoster *proster = new BTranslatorRoster();
152	CPPUNIT_ASSERT(proster);
153	CPPUNIT_ASSERT(proster->AddTranslators(
154		"/boot/home/config/add-ons/Translators/PNGTranslator") == B_OK);
155	BFile wronginput("../src/tests/kits/translation/data/images/image.jpg",
156		B_READ_ONLY);
157	CPPUNIT_ASSERT(wronginput.InitCheck() == B_OK);
158
159	// Identify (bad input, output types)
160	NextSubTest();
161	translator_info ti;
162	memset(&ti, 0, sizeof(translator_info));
163	result = proster->Identify(&wronginput, NULL, &ti, 0,
164		NULL, B_TRANSLATOR_TEXT);
165	CPPUNIT_ASSERT(result == B_NO_TRANSLATOR);
166	CPPUNIT_ASSERT(ti.type == 0 && ti.translator == 0);
167
168	// Identify (wrong type of input data)
169	NextSubTest();
170	memset(&ti, 0, sizeof(translator_info));
171	result = proster->Identify(&wronginput, NULL, &ti);
172	CPPUNIT_ASSERT(result == B_NO_TRANSLATOR);
173	CPPUNIT_ASSERT(ti.type == 0 && ti.translator == 0);
174
175	// Identify (bad PNG signature)
176	NextSubTest();
177	memset(&ti, 0, sizeof(translator_info));
178	BFile badsig1(IMAGES_DIR "xlfn0g04.png", B_READ_ONLY);
179	CPPUNIT_ASSERT(badsig1.InitCheck() == B_OK);
180	result = proster->Identify(&badsig1, NULL, &ti);
181	CPPUNIT_ASSERT(result == B_NO_TRANSLATOR);
182	CPPUNIT_ASSERT(ti.type == 0 && ti.translator == 0);
183
184	// Identify (bad PNG signature)
185	NextSubTest();
186	memset(&ti, 0, sizeof(translator_info));
187	BFile badsig2(IMAGES_DIR "/xcrn0g04.png", B_READ_ONLY);
188	CPPUNIT_ASSERT(badsig2.InitCheck() == B_OK);
189	result = proster->Identify(&badsig2, NULL, &ti);
190	CPPUNIT_ASSERT(result == B_NO_TRANSLATOR);
191	CPPUNIT_ASSERT(ti.type == 0 && ti.translator == 0);
192
193	// Identify (successfully identify the following files)
194	const char * aBitsPaths[] = {
195		"beer.bits",
196		"blocks.bits"
197	};
198	const char * aPNGPaths[] = {
199		"basi0g01.png",
200		"basi0g02.png",
201		"basn0g01.png",
202		"basn0g04.png",
203		"basi0g16.png",
204		"basi4a08.png",
205		"basn0g08.png",
206		"basi4a16.png",
207		"tp1n3p08.png",
208		"tp0n2c08.png",
209		"tbgn2c16.png",
210		"s39i3p04.png",
211		"basi6a08.png",
212		"basi6a16.png",
213		"basn6a08.png",
214		"basi3p01.png",
215		"basn3p02.png"
216	};
217
218	IdentifyTests(this, proster, aPNGPaths,
219		sizeof(aPNGPaths) / sizeof(const char *), false);
220	IdentifyTests(this, proster, aBitsPaths,
221		sizeof(aBitsPaths) / sizeof(const char *), true);
222
223	delete proster;
224	proster = NULL;
225}
226
227// coveniently group path of PNG image with
228// path of bits image that it should translate to
229struct TranslatePaths {
230	const char *pngPath;
231	const char *bitsPath;
232};
233
234void
235TranslateTests(PNGTranslatorTest *ptest, BTranslatorRoster *proster,
236	const TranslatePaths *paths, int32 len)
237{
238	BString png_fpath, bits_fpath;
239
240	// Perform translations on every file in the array
241	for (int32 i = 0; i < len; i++) {
242		// Setup input files
243		ptest->NextSubTest();
244		png_fpath = bits_fpath = IMAGES_DIR;
245		png_fpath += paths[i].pngPath;
246		bits_fpath += paths[i].bitsPath;
247		BFile png_file, bits_file;
248		CPPUNIT_ASSERT(png_file.SetTo(png_fpath.String(), B_READ_ONLY) == B_OK);
249		CPPUNIT_ASSERT(bits_file.SetTo(bits_fpath.String(), B_READ_ONLY) == B_OK);
250		printf(" [%s] ", png_fpath.String());
251
252		BMallocIO mallio, dmallio;
253
254		// Convert to B_TRANSLATOR_ANY_TYPE (should be B_TRANSLATOR_BITMAP)
255		ptest->NextSubTest();
256		CPPUNIT_ASSERT(mallio.Seek(0, SEEK_SET) == 0);
257		CPPUNIT_ASSERT(mallio.SetSize(0) == B_OK);
258		CPPUNIT_ASSERT(proster->Translate(&png_file, NULL, NULL, &mallio,
259			B_TRANSLATOR_ANY_TYPE) == B_OK);
260		CPPUNIT_ASSERT(CompareStreams(mallio, bits_file) == true);
261
262		// Convert to B_TRANSLATOR_BITMAP
263		ptest->NextSubTest();
264		CPPUNIT_ASSERT(mallio.Seek(0, SEEK_SET) == 0);
265		CPPUNIT_ASSERT(mallio.SetSize(0) == B_OK);
266		CPPUNIT_ASSERT(proster->Translate(&png_file, NULL, NULL, &mallio,
267			B_TRANSLATOR_BITMAP) == B_OK);
268		CPPUNIT_ASSERT(CompareStreams(mallio, bits_file) == true);
269
270		// Convert bits mallio to B_TRANSLATOR_BITMAP dmallio
271		ptest->NextSubTest();
272		CPPUNIT_ASSERT(dmallio.Seek(0, SEEK_SET) == 0);
273		CPPUNIT_ASSERT(dmallio.SetSize(0) == B_OK);
274		CPPUNIT_ASSERT(proster->Translate(&mallio, NULL, NULL, &dmallio,
275			B_TRANSLATOR_BITMAP) == B_OK);
276		CPPUNIT_ASSERT(CompareStreams(dmallio, bits_file) == true);
277
278		// Convert to B_PNG_FORMAT
279		ptest->NextSubTest();
280		CPPUNIT_ASSERT(mallio.Seek(0, SEEK_SET) == 0);
281		CPPUNIT_ASSERT(mallio.SetSize(0) == B_OK);
282		CPPUNIT_ASSERT(proster->Translate(&png_file, NULL, NULL, &mallio,
283			B_PNG_FORMAT) == B_OK);
284		CPPUNIT_ASSERT(CompareStreams(mallio, png_file) == true);
285
286		// Convert PNG mallio to B_TRANSLATOR_BITMAP dmallio
287		ptest->NextSubTest();
288		CPPUNIT_ASSERT(dmallio.Seek(0, SEEK_SET) == 0);
289		CPPUNIT_ASSERT(dmallio.SetSize(0) == B_OK);
290		CPPUNIT_ASSERT(proster->Translate(&mallio, NULL, NULL, &dmallio,
291			B_TRANSLATOR_BITMAP) == B_OK);
292		CPPUNIT_ASSERT(CompareStreams(dmallio, bits_file) == true);
293
294		// Convert PNG mallio to B_PNG_FORMAT dmallio
295		ptest->NextSubTest();
296		CPPUNIT_ASSERT(dmallio.Seek(0, SEEK_SET) == 0);
297		CPPUNIT_ASSERT(dmallio.SetSize(0) == B_OK);
298		CPPUNIT_ASSERT(proster->Translate(&mallio, NULL, NULL, &dmallio,
299			B_PNG_FORMAT) == B_OK);
300		CPPUNIT_ASSERT(CompareStreams(dmallio, png_file) == true);
301	}
302}
303
304void
305PNGTranslatorTest::TranslateTest()
306{
307	// Init
308	NextSubTest();
309	status_t result = B_ERROR;
310	off_t filesize = -1;
311	BTranslatorRoster *proster = new BTranslatorRoster();
312	CPPUNIT_ASSERT(proster);
313	CPPUNIT_ASSERT(proster->AddTranslators(
314		"/boot/home/config/add-ons/Translators/PNGTranslator") == B_OK);
315	BFile wronginput("../src/tests/kits/translation/data/images/image.jpg",
316		B_READ_ONLY);
317	CPPUNIT_ASSERT(wronginput.InitCheck() == B_OK);
318	BFile output("/tmp/png_test.out", B_WRITE_ONLY |
319		B_CREATE_FILE | B_ERASE_FILE);
320	CPPUNIT_ASSERT(output.InitCheck() == B_OK);
321
322	// Translate (bad input, output types)
323	NextSubTest();
324	result = proster->Translate(&wronginput, NULL, NULL, &output,
325		B_TRANSLATOR_TEXT);
326	CPPUNIT_ASSERT(result == B_NO_TRANSLATOR);
327	CPPUNIT_ASSERT(output.GetSize(&filesize) == B_OK);
328	CPPUNIT_ASSERT(filesize == 0);
329
330	// Translate (wrong type of input data)
331	NextSubTest();
332	result = proster->Translate(&wronginput, NULL, NULL, &output,
333		B_PNG_FORMAT);
334	CPPUNIT_ASSERT(result == B_NO_TRANSLATOR);
335	CPPUNIT_ASSERT(output.GetSize(&filesize) == B_OK);
336	CPPUNIT_ASSERT(filesize == 0);
337
338	// Translate (wrong type of input, B_TRANSLATOR_ANY_TYPE output)
339	NextSubTest();
340	result = proster->Translate(&wronginput, NULL, NULL, &output,
341		B_TRANSLATOR_ANY_TYPE);
342	CPPUNIT_ASSERT(result == B_NO_TRANSLATOR);
343	CPPUNIT_ASSERT(output.GetSize(&filesize) == B_OK);
344	CPPUNIT_ASSERT(filesize == 0);
345
346	// Translate (bad PNG signature)
347	NextSubTest();
348	BFile badsig1(IMAGES_DIR "xlfn0g04.png", B_READ_ONLY);
349	CPPUNIT_ASSERT(badsig1.InitCheck() == B_OK);
350	result = proster->Translate(&badsig1, NULL, NULL, &output,
351		B_TRANSLATOR_ANY_TYPE);
352	CPPUNIT_ASSERT(result == B_NO_TRANSLATOR);
353	CPPUNIT_ASSERT(output.GetSize(&filesize) == B_OK);
354	CPPUNIT_ASSERT(filesize == 0);
355
356	// Translate (bad PNG signature)
357	NextSubTest();
358	BFile badsig2(IMAGES_DIR "xcrn0g04.png", B_READ_ONLY);
359	CPPUNIT_ASSERT(badsig2.InitCheck() == B_OK);
360	result = proster->Translate(&badsig2, NULL, NULL, &output,
361		B_TRANSLATOR_ANY_TYPE);
362	CPPUNIT_ASSERT(result == B_NO_TRANSLATOR);
363	CPPUNIT_ASSERT(output.GetSize(&filesize) == B_OK);
364	CPPUNIT_ASSERT(filesize == 0);
365
366	// Translate (bad width)
367	NextSubTest();
368	BFile badw(IMAGES_DIR "x00n0g01.png", B_READ_ONLY);
369	CPPUNIT_ASSERT(badw.InitCheck() == B_OK);
370	result = proster->Translate(&badw, NULL, NULL, &output,
371		B_TRANSLATOR_ANY_TYPE);
372	CPPUNIT_ASSERT(result == B_ERROR);
373	CPPUNIT_ASSERT(output.GetSize(&filesize) == B_OK);
374	CPPUNIT_ASSERT(filesize == 0);
375
376	// Translate PNG images to bits
377	const TranslatePaths aPaths[] = {
378		{ "basi0g01.png", "basi0g01.bits" },
379		{ "basi0g02.png", "basi0g02.bits" },
380		{ "basn0g01.png", "basn0g01.bits" },
381		{ "basn0g04.png", "basn0g04.bits" },
382		{ "basi0g16.png", "basi0g16.bits" },
383		{ "basi4a08.png", "basi4a08.bits" },
384		{ "basn0g08.png", "basn0g08.bits" },
385		{ "basi4a16.png", "basi4a16.bits" },
386		{ "tp1n3p08.png", "tp1n3p08.bits" },
387		{ "tp0n2c08.png", "tp0n2c08.bits" },
388		{ "tbgn2c16.png", "tbgn2c16.bits" },
389		{ "s39i3p04.png", "s39i3p04.bits" },
390		{ "basi6a08.png", "basi6a08.bits" },
391		{ "basi6a16.png", "basi6a16.bits" },
392		{ "basn6a08.png", "basn6a08.bits" },
393		{ "basi3p01.png", "basi3p01.bits" },
394		{ "basn3p02.png", "basn3p02.bits" }
395	};
396
397	TranslateTests(this, proster, aPaths,
398		sizeof(aPaths) / sizeof(TranslatePaths));
399
400	delete proster;
401	proster = NULL;
402}
403
404#if !TEST_R5
405
406// The input formats that this translator supports.
407translation_format gPNGInputFormats[] = {
408	{
409		B_PNG_FORMAT,
410		B_TRANSLATOR_BITMAP,
411		PNG_IN_QUALITY,
412		PNG_IN_CAPABILITY,
413		"image/png",
414		"PNG image"
415	},
416	{
417		B_PNG_FORMAT,
418		B_TRANSLATOR_BITMAP,
419		PNG_IN_QUALITY,
420		PNG_IN_CAPABILITY,
421		"image/x-png",
422		"PNG image"
423	},
424	{
425		B_TRANSLATOR_BITMAP,
426		B_TRANSLATOR_BITMAP,
427		BBT_IN_QUALITY,
428		BBT_IN_CAPABILITY,
429		"image/x-be-bitmap",
430		"Be Bitmap Format (PNGTranslator)"
431	}
432};
433
434// The output formats that this translator supports.
435translation_format gPNGOutputFormats[] = {
436	{
437		B_PNG_FORMAT,
438		B_TRANSLATOR_BITMAP,
439		PNG_OUT_QUALITY,
440		PNG_OUT_CAPABILITY,
441		"image/png",
442		"PNG image"
443	},
444	{
445		B_TRANSLATOR_BITMAP,
446		B_TRANSLATOR_BITMAP,
447		BBT_OUT_QUALITY,
448		BBT_OUT_CAPABILITY,
449		"image/x-be-bitmap",
450		"Be Bitmap Format (PNGTranslator)"
451	}
452};
453
454void
455PNGTranslatorTest::LoadAddOnTest()
456{
457	TranslatorLoadAddOnTest("/boot/home/config/add-ons/Translators/PNGTranslator",
458		this,
459		gPNGInputFormats, sizeof(gPNGInputFormats) / sizeof(translation_format),
460		gPNGOutputFormats, sizeof(gPNGOutputFormats) / sizeof(translation_format),
461		PNG_TRANSLATOR_VERSION);
462}
463
464#endif // #if !TEST_R5
465