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