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