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