xref: /haiku/src/tests/add-ons/translators/TranslatorTestAddOn.cpp (revision 5b3152c4fb0290b10bc0883c8573b410069a4489)
1 // TranslatorTestAddOn.cpp
2 
3 #include <stdio.h>
4 #include <string.h>
5 #include <Translator.h>
6 #include <OS.h>
7 #include "TranslatorTestAddOn.h"
8 
9 // ##### Include headers for your tests here #####
10 #include "bmptranslator/BMPTranslatorTest.h"
11 #include "pngtranslator/PNGTranslatorTest.h"
12 #include "stxttranslator/STXTTranslatorTest.h"
13 #include "tgatranslator/TGATranslatorTest.h"
14 #include "tifftranslator/TIFFTranslatorTest.h"
15 
16 BTestSuite *
getTestSuite()17 getTestSuite()
18 {
19 	BTestSuite *suite = new BTestSuite("Translators");
20 
21 	// ##### Add test suites here #####
22 	suite->addTest("BMPTranslator", BMPTranslatorTest::Suite());
23 	suite->addTest("PNGTranslator", PNGTranslatorTest::Suite());
24 	suite->addTest("STXTTranslator", STXTTranslatorTest::Suite());
25 	suite->addTest("TGATranslator", TGATranslatorTest::Suite());
26 	suite->addTest("TIFFTranslator", TIFFTranslatorTest::Suite());
27 
28 	return suite;
29 }
30 
31 // helper function used by multiple tests to
32 // determine if the given streams are exactly
33 // the same
34 bool
CompareStreams(BPositionIO & a,BPositionIO & b)35 CompareStreams(BPositionIO &a, BPositionIO &b)
36 {
37 	off_t alen = 0, blen = 0;
38 	const uint32 kbuflen = 2048;
39 	uint8 abuf[kbuflen], bbuf[kbuflen];
40 
41 	a.Seek(0, SEEK_END);
42 	alen = a.Position();
43 	b.Seek(0, SEEK_END);
44 	blen = b.Position();
45 	if (alen != blen)
46 		return false;
47 
48 	if (a.Seek(0, SEEK_SET) != 0)
49 		return false;
50 	if (b.Seek(0, SEEK_SET) != 0)
51 		return false;
52 
53 	ssize_t read = 0;
54 	while (alen > 0) {
55 		read = a.Read(abuf, kbuflen);
56 		if (read < 0)
57 			return false;
58 		if (b.Read(bbuf, read) != read)
59 			return false;
60 
61 		if (memcmp(abuf, bbuf, read) != 0)
62 			return false;
63 
64 		alen -= read;
65 	}
66 
67 	return true;
68 }
69 
70 // Check each member of translator_info to see that it matches
71 // what is expected
72 void
CheckTranslatorInfo(translator_info * pti,uint32 type,uint32 group,float quality,float capability,const char * name,const char * mime)73 CheckTranslatorInfo(translator_info *pti, uint32 type, uint32 group,
74 	float quality, float capability, const char *name, const char *mime)
75 {
76 	CPPUNIT_ASSERT(pti->type == type);
77 	CPPUNIT_ASSERT(pti->translator != 0);
78 	CPPUNIT_ASSERT(pti->group == group);
79 	CPPUNIT_ASSERT(pti->quality > quality - 0.01f &&
80 		pti->quality < quality + 0.01f);
81 	CPPUNIT_ASSERT(pti->capability > capability - 0.01f &&
82 		pti->capability < capability + 0.01f);
83 	CPPUNIT_ASSERT(strcmp(pti->name, name) == 0);
84 	CPPUNIT_ASSERT(strcmp(pti->MIME, mime) == 0);
85 }
86 
87 // Returns true if the translation_formats are
88 // identical (or nearly identical).  Returns false if
89 // they are different
90 bool
CompareTranslationFormat(const translation_format * pleft,const translation_format * pright)91 CompareTranslationFormat(const translation_format *pleft,
92 	const translation_format *pright)
93 {
94 	CPPUNIT_ASSERT(pleft->MIME);
95 	CPPUNIT_ASSERT(pright->MIME);
96 	CPPUNIT_ASSERT(pleft->name);
97 	CPPUNIT_ASSERT(pright->name);
98 
99 	if (pleft->group != pright->group)
100 		return false;
101 	if (pleft->type != pright->type)
102 		return false;
103 	if (pleft->quality < pright->quality - 0.01f ||
104 		pleft->quality > pright->quality + 0.01f)
105 		return false;
106 	if (pleft->capability < pright->capability - 0.01f ||
107 		pleft->capability > pright->capability + 0.01f)
108 		return false;
109 	if (strcmp(pleft->MIME, pright->MIME) != 0)
110 		return false;
111 	if (strcmp(pleft->name, pright->name) != 0)
112 		return false;
113 
114 	return true;
115 }
116 
117 // Apply a number of tests to a BTranslator * to a TGATranslator object
118 void
TestBTranslator(BTestCase * ptest,BTranslator * ptran,const translation_format * pExpectedIns,uint32 nExpectedIns,const translation_format * pExpectedOuts,uint32 nExpectedOuts,int32 expectedVer)119 TestBTranslator(BTestCase *ptest, BTranslator *ptran,
120 	const translation_format *pExpectedIns, uint32 nExpectedIns,
121 	const translation_format *pExpectedOuts, uint32 nExpectedOuts,
122 	int32 expectedVer)
123 {
124 	const uint32 knmatches = 50;
125 	uint8 matches[knmatches];
126 	CPPUNIT_ASSERT(nExpectedIns <= knmatches && nExpectedOuts <= knmatches);
127 
128 	// The translator should only have one reference
129 	ptest->NextSubTest();
130 	CPPUNIT_ASSERT(ptran->ReferenceCount() == 1);
131 
132 	// Make sure Acquire returns a BTranslator even though its
133 	// already been Acquired once
134 	ptest->NextSubTest();
135 	CPPUNIT_ASSERT(ptran->Acquire() == ptran);
136 
137 	// Acquired twice, refcount should be 2
138 	ptest->NextSubTest();
139 	CPPUNIT_ASSERT(ptran->ReferenceCount() == 2);
140 
141 	// Release should return ptran because it is still acquired
142 	ptest->NextSubTest();
143 	CPPUNIT_ASSERT(ptran->Release() == ptran);
144 
145 	ptest->NextSubTest();
146 	CPPUNIT_ASSERT(ptran->ReferenceCount() == 1);
147 
148 	ptest->NextSubTest();
149 	CPPUNIT_ASSERT(ptran->Acquire() == ptran);
150 
151 	ptest->NextSubTest();
152 	CPPUNIT_ASSERT(ptran->ReferenceCount() == 2);
153 
154 	ptest->NextSubTest();
155 	CPPUNIT_ASSERT(ptran->Release() == ptran);
156 
157 	ptest->NextSubTest();
158 	CPPUNIT_ASSERT(ptran->ReferenceCount() == 1);
159 
160 	// A name would be nice
161 	ptest->NextSubTest();
162 	const char *tranname = ptran->TranslatorName();
163 	CPPUNIT_ASSERT(tranname);
164 	printf(" {%s} ", tranname);
165 
166 	// More info would be nice
167 	ptest->NextSubTest();
168 	const char *traninfo = ptran->TranslatorInfo();
169 	CPPUNIT_ASSERT(traninfo);
170 	printf(" {%s} ", traninfo);
171 
172 	// What version are you?
173 	// (when ver == 100, that means that version is 1.00)
174 	ptest->NextSubTest();
175 	int32 ver = ptran->TranslatorVersion();
176 	CPPUNIT_ASSERT(ver == expectedVer);
177 	printf(" {0x%.8lx} ", ver);
178 
179 	// Input formats?
180 	ptest->NextSubTest();
181 	{
182 		printf("input:");
183 
184 		int32 incount = 0;
185 		const translation_format *pins = ptran->InputFormats(&incount);
186 		CPPUNIT_ASSERT((unsigned)incount == nExpectedIns);
187 		CPPUNIT_ASSERT(pins);
188 
189 		memset(matches, 0, sizeof(uint8) * nExpectedIns);
190 		for (int32 i = 0; i < incount; i++) {
191 			bool bmatch = false;
192 			for (uint32 k = 0; bmatch == false && k < nExpectedIns; k++) {
193 				bmatch = CompareTranslationFormat(pins + i, pExpectedIns + k);
194 				if (bmatch)
195 					matches[k] = 1;
196 			}
197 
198 			CPPUNIT_ASSERT(bmatch);
199 		}
200 
201 		// make sure that each expected input format was matched
202 		for (uint32 i = 0; i < nExpectedIns; i++)
203 			CPPUNIT_ASSERT(matches[i]);
204 	}
205 
206 	// Output formats?
207 	ptest->NextSubTest();
208 	{
209 		printf("output:");
210 
211 		int32 outcount = 0;
212 		const translation_format *pouts = ptran->OutputFormats(&outcount);
213 		CPPUNIT_ASSERT((unsigned)outcount == nExpectedOuts);
214 		CPPUNIT_ASSERT(pouts);
215 
216 		memset(matches, 0, sizeof(uint8) * nExpectedOuts);
217 		for (int32 i = 0; i < outcount; i++) {
218 			bool bmatch = false;
219 			for (uint32 k = 0; bmatch == false && k < nExpectedOuts; k++) {
220 				bmatch = CompareTranslationFormat(pouts + i, pExpectedOuts + k);
221 				if (bmatch)
222 					matches[k] = 1;
223 			}
224 
225 			CPPUNIT_ASSERT(bmatch);
226 		}
227 
228 		// make sure that each expected input format was matched
229 		for (uint32 i = 0; i < nExpectedOuts; i++)
230 			CPPUNIT_ASSERT(matches[i]);
231 	}
232 
233 	// Release should return NULL because Release has been called
234 	// as many times as it has been acquired
235 	ptest->NextSubTest();
236 	CPPUNIT_ASSERT(ptran->Release() == NULL);
237 	ptran = NULL;
238 }
239 
240 void
TranslatorLoadAddOnTest(const char * path,BTestCase * ptest,const translation_format * pExpectedIns,uint32 nExpectedIns,const translation_format * pExpectedOuts,uint32 nExpectedOuts,int32 expectedVer)241 TranslatorLoadAddOnTest(const char *path, BTestCase *ptest,
242 	const translation_format *pExpectedIns, uint32 nExpectedIns,
243 	const translation_format *pExpectedOuts, uint32 nExpectedOuts,
244 	int32 expectedVer)
245 {
246 	// Make sure the add_on loads
247 	ptest->NextSubTest();
248 	image_id image = load_add_on(path);
249 	CPPUNIT_ASSERT(image >= 0);
250 
251 	// Load in function to make the object
252 	ptest->NextSubTest();
253 	BTranslator *(*pMakeNthTranslator)(int32 n,image_id you,uint32 flags,...);
254 	status_t err = get_image_symbol(image, "make_nth_translator",
255 		B_SYMBOL_TYPE_TEXT, (void **)&pMakeNthTranslator);
256 	CPPUNIT_ASSERT(!err);
257 
258 	// Make sure the function returns a pointer to a BTranslator
259 	ptest->NextSubTest();
260 	BTranslator *ptran = pMakeNthTranslator(0, image, 0);
261 	CPPUNIT_ASSERT(ptran);
262 
263 	// Make sure the function only returns one BTranslator
264 	ptest->NextSubTest();
265 	CPPUNIT_ASSERT(!pMakeNthTranslator(1, image, 0));
266 	CPPUNIT_ASSERT(!pMakeNthTranslator(2, image, 0));
267 	CPPUNIT_ASSERT(!pMakeNthTranslator(3, image, 0));
268 	CPPUNIT_ASSERT(!pMakeNthTranslator(16, image, 0));
269 	CPPUNIT_ASSERT(!pMakeNthTranslator(1023, image, 0));
270 
271 	// Run a number of tests on the BTranslator object
272 	TestBTranslator(ptest, ptran, pExpectedIns, nExpectedIns,
273 		pExpectedOuts, nExpectedOuts, expectedVer);
274 		// NOTE: this function Release()s ptran
275 	ptran = NULL;
276 
277 	// Unload Add-on
278 	ptest->NextSubTest();
279 	CPPUNIT_ASSERT(unload_add_on(image) == B_OK);
280 }
281