1// STXTTranslatorTest.cpp
2#include "STXTTranslatorTest.h"
3#include <cppunit/Test.h>
4#include <cppunit/TestCaller.h>
5#include <cppunit/TestSuite.h>
6#include <stdio.h>
7#include <string.h>
8#include <unistd.h>
9#include <image.h>
10#include <Translator.h>
11#include <TranslatorFormats.h>
12#include <TranslatorRoster.h>
13#include <Message.h>
14#include <View.h>
15#include <Rect.h>
16#include <File.h>
17#include <DataIO.h>
18#include <Errors.h>
19#include <OS.h>
20#include "TranslatorTestAddOn.h"
21
22// Suite
23CppUnit::Test *
24STXTTranslatorTest::Suite()
25{
26	CppUnit::TestSuite *suite = new CppUnit::TestSuite();
27	typedef CppUnit::TestCaller<STXTTranslatorTest> TC;
28
29	suite->addTest(
30		new TC("STXTTranslator IdentifyTest",
31			&STXTTranslatorTest::IdentifyTest));
32
33	suite->addTest(
34		new TC("STXTTranslator TranslateTest",
35			&STXTTranslatorTest::TranslateTest));
36
37	suite->addTest(
38		new TC("STXTTranslator ConfigMessageTest",
39			&STXTTranslatorTest::ConfigMessageTest));
40
41#if !TEST_R5
42	suite->addTest(
43		new TC("STXTTranslator LoadAddOnTest",
44			&STXTTranslatorTest::LoadAddOnTest));
45#endif
46
47	return suite;
48}
49
50// setUp
51void
52STXTTranslatorTest::setUp()
53{
54	BTestCase::setUp();
55}
56
57// tearDown
58void
59STXTTranslatorTest::tearDown()
60{
61	BTestCase::tearDown();
62}
63
64void
65CheckStyled(translator_info *pti)
66{
67	CheckTranslatorInfo(pti, B_STYLED_TEXT_FORMAT, B_TRANSLATOR_TEXT,
68		0.5f, 0.5f, "Be styled text file", "text/x-vnd.Be-stxt");
69}
70
71void
72CheckPlain(translator_info *pti)
73{
74	CheckTranslatorInfo(pti, B_TRANSLATOR_TEXT, B_TRANSLATOR_TEXT,
75		0.4f, 0.6f, "Plain text file", "text/plain");
76}
77
78void
79IdentifyTests(STXTTranslatorTest *ptest, BTranslatorRoster *proster,
80	const char **paths, int32 len, bool bplain)
81{
82	translator_info ti;
83	printf(" [%d] ", (int) bplain);
84
85	for (int32 i = 0; i < len; i++) {
86		ptest->NextSubTest();
87		BFile file;
88		printf(" [%s] ", paths[i]);
89		CPPUNIT_ASSERT(file.SetTo(paths[i], B_READ_ONLY) == B_OK);
90
91		// Identify (output: B_TRANSLATOR_ANY_TYPE)
92		ptest->NextSubTest();
93		memset(&ti, 0, sizeof(translator_info));
94		CPPUNIT_ASSERT(proster->Identify(&file, NULL, &ti) == B_OK);
95		if (bplain)
96			CheckPlain(&ti);
97		else
98			CheckStyled(&ti);
99
100		// Identify (output: B_TRANSLATOR_TEXT)
101		ptest->NextSubTest();
102		memset(&ti, 0, sizeof(translator_info));
103		CPPUNIT_ASSERT(proster->Identify(&file, NULL, &ti, 0, NULL,
104			B_TRANSLATOR_TEXT) == B_OK);
105		if (bplain)
106			CheckPlain(&ti);
107		else
108			CheckStyled(&ti);
109
110		// Identify (output: B_STYLED_TEXT_FORMAT)
111		ptest->NextSubTest();
112		memset(&ti, 0, sizeof(translator_info));
113		CPPUNIT_ASSERT(proster->Identify(&file, NULL, &ti, 0, NULL,
114			B_STYLED_TEXT_FORMAT) == B_OK);
115		if (bplain)
116			CheckPlain(&ti);
117		else
118			CheckStyled(&ti);
119	}
120}
121
122void
123STXTTranslatorTest::IdentifyTest()
124{
125	// Init
126	NextSubTest();
127	status_t result = B_ERROR;
128	BTranslatorRoster *proster = new BTranslatorRoster();
129	CPPUNIT_ASSERT(proster);
130	CPPUNIT_ASSERT(proster->AddTranslators(
131		"/boot/home/config/add-ons/Translators/STXTTranslator") == B_OK);
132	BFile wronginput("../src/tests/kits/translation/data/images/image.jpg",
133		B_READ_ONLY);
134	CPPUNIT_ASSERT(wronginput.InitCheck() == B_OK);
135
136	// Identify (bad input, output types)
137	NextSubTest();
138	translator_info ti;
139	memset(&ti, 0, sizeof(translator_info));
140	result = proster->Identify(&wronginput, NULL, &ti, 0,
141		NULL, B_TRANSLATOR_BITMAP);
142	CPPUNIT_ASSERT(result == B_NO_TRANSLATOR);
143	CPPUNIT_ASSERT(ti.type == 0 && ti.translator == 0);
144
145	// Identify (wrong type of input data)
146	NextSubTest();
147	memset(&ti, 0, sizeof(translator_info));
148	result = proster->Identify(&wronginput, NULL, &ti);
149	CPPUNIT_ASSERT(result == B_OK);
150	CheckTranslatorInfo(&ti, B_TRANSLATOR_TEXT, B_TRANSLATOR_TEXT, 0.4f, 0.36f,
151		"Plain text file", "text/plain");
152
153	// Identify (wrong magic)
154	NextSubTest();
155	memset(&ti, 0, sizeof(translator_info));
156	BFile wrongmagic("../src/tests/kits/translation/data/text/wrong_magic.stxt",
157		B_READ_ONLY);
158	CPPUNIT_ASSERT(wrongmagic.InitCheck() == B_OK);
159	result = proster->Identify(&wrongmagic, NULL, &ti);
160	CPPUNIT_ASSERT(result == B_OK);
161	CheckTranslatorInfo(&ti, B_TRANSLATOR_TEXT, B_TRANSLATOR_TEXT, 0.4f, 0.36f,
162		"Plain text file", "text/plain");
163
164	// Identify (wrong version)
165	NextSubTest();
166	memset(&ti, 0, sizeof(translator_info));
167	BFile wrongversion("../src/tests/kits/translation/data/text/wrong_version.stxt",
168		B_READ_ONLY);
169	CPPUNIT_ASSERT(wrongversion.InitCheck() == B_OK);
170	result = proster->Identify(&wrongversion, NULL, &ti);
171	CPPUNIT_ASSERT(result == B_OK);
172	CheckTranslatorInfo(&ti, B_TRANSLATOR_TEXT, B_TRANSLATOR_TEXT, 0.4f, 0.36f,
173		"Plain text file", "text/plain");
174
175	const char *aPlainFiles[] = {
176		"../src/tests/kits/translation/data/text/ascii.txt",
177		"../src/tests/kits/translation/data/text/japanese.txt",
178		"../src/tests/kits/translation/data/text/multi_byte.txt",
179		"../src/tests/kits/translation/data/text/one_length.txt",
180		"../src/tests/kits/translation/data/text/sentence.txt",
181		"../src/tests/kits/translation/data/text/symbols.txt",
182		"../src/tests/kits/translation/data/text/zero_length.txt"
183	};
184	const char *aStyledFiles[] = {
185		"../src/tests/kits/translation/data/text/ascii.stxt",
186		"../src/tests/kits/translation/data/text/japanese.stxt",
187		"../src/tests/kits/translation/data/text/multi_byte.stxt",
188		"../src/tests/kits/translation/data/text/one_length.stxt",
189		"../src/tests/kits/translation/data/text/sentence.stxt",
190		"../src/tests/kits/translation/data/text/symbols.stxt",
191		"../src/tests/kits/translation/data/text/zero_length.stxt",
192	};
193	IdentifyTests(this, proster, aPlainFiles,
194		sizeof(aPlainFiles) / sizeof(const char *), true);
195	IdentifyTests(this, proster, aStyledFiles,
196		sizeof(aStyledFiles) / sizeof(const char *), false);
197}
198
199void
200TranslateTests(STXTTranslatorTest *ptest, BTranslatorRoster *proster,
201	const char **paths, int32 len, bool bplain)
202{
203	int32 nlongest = 0, ncurrent = 0;
204	// find the length of the longest string
205	for (int32 i = 0; i < len; i++) {
206		ncurrent = strlen(paths[i]);
207		if (ncurrent > nlongest)
208			nlongest = ncurrent;
209	}
210
211	char *styled_path = NULL, *plain_path = NULL;
212	styled_path = new char[nlongest + 6];
213	plain_path = new char[nlongest + 6];
214
215	BFile styled_file, plain_file;
216
217	// Perform translations on every file in the array
218	for (int32 i = 0; i < len; i++) {
219		strcpy(styled_path, paths[i]);
220		strcat(styled_path, ".stxt");
221		strcpy(plain_path, paths[i]);
222		strcat(plain_path, ".txt");
223
224		// Setup input files
225		ptest->NextSubTest();
226		CPPUNIT_ASSERT(styled_file.SetTo(styled_path, B_READ_ONLY) == B_OK);
227		CPPUNIT_ASSERT(plain_file.SetTo(plain_path, B_READ_ONLY) == B_OK);
228
229		BFile *pinput_file;
230		if (bplain) {
231			printf(" [%s] ", plain_path);
232			pinput_file = &plain_file;
233		} else {
234			printf(" [%s] ", styled_path);
235			pinput_file = &styled_file;
236		}
237
238		BMallocIO mallio, dmallio;
239
240		// Convert to B_TRANSLATOR_ANY_TYPE (should be B_TRANSLATOR_TEXT)
241		ptest->NextSubTest();
242		CPPUNIT_ASSERT(mallio.Seek(0, SEEK_SET) == 0);
243		CPPUNIT_ASSERT(mallio.SetSize(0) == B_OK);
244		CPPUNIT_ASSERT(proster->Translate(pinput_file, NULL, NULL, &mallio,
245			B_TRANSLATOR_ANY_TYPE) == B_OK);
246		CPPUNIT_ASSERT(CompareStreams(mallio, plain_file) == true);
247
248		// Convert to B_TRANSLATOR_TEXT
249		ptest->NextSubTest();
250		CPPUNIT_ASSERT(mallio.Seek(0, SEEK_SET) == 0);
251		CPPUNIT_ASSERT(mallio.SetSize(0) == B_OK);
252		CPPUNIT_ASSERT(proster->Translate(pinput_file, NULL, NULL, &mallio,
253			B_TRANSLATOR_TEXT) == B_OK);
254		CPPUNIT_ASSERT(CompareStreams(mallio, plain_file) == true);
255
256		// Convert plain mallio to B_TRANSLATOR_TEXT dmallio
257		ptest->NextSubTest();
258		CPPUNIT_ASSERT(dmallio.Seek(0, SEEK_SET) == 0);
259		CPPUNIT_ASSERT(dmallio.SetSize(0) == B_OK);
260		CPPUNIT_ASSERT(proster->Translate(&mallio, NULL, NULL, &dmallio,
261			B_TRANSLATOR_TEXT) == B_OK);
262		CPPUNIT_ASSERT(CompareStreams(dmallio, plain_file) == true);
263
264		// Convert to B_STYLED_TEXT_FORMAT
265		ptest->NextSubTest();
266		CPPUNIT_ASSERT(mallio.Seek(0, SEEK_SET) == 0);
267		CPPUNIT_ASSERT(mallio.SetSize(0) == B_OK);
268		CPPUNIT_ASSERT(proster->Translate(pinput_file, NULL, NULL, &mallio,
269			B_STYLED_TEXT_FORMAT) == B_OK);
270		CPPUNIT_ASSERT(CompareStreams(mallio, styled_file) == true);
271
272		// Convert styled mallio to B_TRANSLATOR_TEXT dmallio
273		ptest->NextSubTest();
274		CPPUNIT_ASSERT(dmallio.Seek(0, SEEK_SET) == 0);
275		CPPUNIT_ASSERT(dmallio.SetSize(0) == B_OK);
276		CPPUNIT_ASSERT(proster->Translate(&mallio, NULL, NULL, &dmallio,
277			B_TRANSLATOR_TEXT) == B_OK);
278		CPPUNIT_ASSERT(CompareStreams(dmallio, plain_file) == true);
279
280		// Convert styled mallio to B_STYLED_TEXT_FORMAT dmallio
281		ptest->NextSubTest();
282		CPPUNIT_ASSERT(dmallio.Seek(0, SEEK_SET) == 0);
283		CPPUNIT_ASSERT(dmallio.SetSize(0) == B_OK);
284		CPPUNIT_ASSERT(proster->Translate(&mallio, NULL, NULL, &dmallio,
285			B_STYLED_TEXT_FORMAT) == B_OK);
286		CPPUNIT_ASSERT(CompareStreams(dmallio, styled_file) == true);
287	}
288
289	delete[] styled_path;
290	styled_path = NULL;
291	delete[] plain_path;
292	plain_path = NULL;
293}
294
295void
296STXTTranslatorTest::TranslateTest()
297{
298	// Init
299	NextSubTest();
300	status_t result = B_ERROR;
301	off_t filesize = -1;
302	BTranslatorRoster *proster = new BTranslatorRoster();
303	CPPUNIT_ASSERT(proster);
304	CPPUNIT_ASSERT(proster->AddTranslators(
305		"/boot/home/config/add-ons/Translators/STXTTranslator") == B_OK);
306	BFile wronginput("../src/tests/kits/translation/data/images/image.jpg",
307		B_READ_ONLY);
308	CPPUNIT_ASSERT(wronginput.InitCheck() == B_OK);
309	BFile output("/tmp/stxt_test.out", B_READ_WRITE |
310		B_CREATE_FILE | B_ERASE_FILE);
311	CPPUNIT_ASSERT(output.InitCheck() == B_OK);
312
313	// Translate (bad input, output types)
314	NextSubTest();
315	result = proster->Translate(&wronginput, NULL, NULL, &output,
316		B_TRANSLATOR_BITMAP);
317	CPPUNIT_ASSERT(result == B_NO_TRANSLATOR);
318	CPPUNIT_ASSERT(output.GetSize(&filesize) == B_OK);
319	CPPUNIT_ASSERT(filesize == 0);
320
321	// Translate (wrong type of input data)
322	NextSubTest();
323	result = proster->Translate(&wronginput, NULL, NULL, &output,
324		B_TRANSLATOR_TEXT);
325	CPPUNIT_ASSERT(result == B_OK);
326	CPPUNIT_ASSERT(CompareStreams(wronginput, output) == true);
327
328	// Translate (wrong type of input, B_TRANSLATOR_ANY_TYPE output)
329	NextSubTest();
330	CPPUNIT_ASSERT(output.Seek(0, SEEK_SET) == 0);
331	CPPUNIT_ASSERT(output.SetSize(0) == B_OK);
332	result = proster->Translate(&wronginput, NULL, NULL, &output,
333		B_TRANSLATOR_ANY_TYPE);
334	CPPUNIT_ASSERT(result == B_OK);
335	CPPUNIT_ASSERT(CompareStreams(wronginput, output) == true);
336
337	// Translate (wrong magic)
338	NextSubTest();
339	CPPUNIT_ASSERT(output.Seek(0, SEEK_SET) == 0);
340	CPPUNIT_ASSERT(output.SetSize(0) == B_OK);
341	BFile wrongmagic("../src/tests/kits/translation/data/text/wrong_magic.stxt",
342		B_READ_ONLY);
343	CPPUNIT_ASSERT(wrongmagic.InitCheck() == B_OK);
344	result = proster->Translate(&wrongmagic, NULL, NULL, &output,
345		B_TRANSLATOR_ANY_TYPE);
346	CPPUNIT_ASSERT(result == B_OK);
347	CPPUNIT_ASSERT(CompareStreams(wrongmagic, output) == true);
348
349	// Translate (wrong version)
350	NextSubTest();
351	CPPUNIT_ASSERT(output.Seek(0, SEEK_SET) == 0);
352	CPPUNIT_ASSERT(output.SetSize(0) == B_OK);
353	BFile wrongversion("../src/tests/kits/translation/data/text/wrong_version.stxt",
354		B_READ_ONLY);
355	CPPUNIT_ASSERT(wrongversion.InitCheck() == B_OK);
356	result = proster->Translate(&wrongversion, NULL, NULL, &output,
357		B_TRANSLATOR_ANY_TYPE);
358	CPPUNIT_ASSERT(result == B_OK);
359	CPPUNIT_ASSERT(CompareStreams(wrongversion, output) == true);
360
361	// Translate various data
362	const char *aPlainTextFiles[] = {
363		"../src/tests/kits/translation/data/text/ascii",
364		"../src/tests/kits/translation/data/text/japanese",
365		"../src/tests/kits/translation/data/text/multi_byte",
366		"../src/tests/kits/translation/data/text/one_length",
367		"../src/tests/kits/translation/data/text/symbols",
368		"../src/tests/kits/translation/data/text/zero_length"
369	};
370	const char *aStyledTextFiles[] = {
371		"../src/tests/kits/translation/data/text/ascii",
372		"../src/tests/kits/translation/data/text/japanese",
373		"../src/tests/kits/translation/data/text/multi_byte",
374		"../src/tests/kits/translation/data/text/one_length",
375		"../src/tests/kits/translation/data/text/sentence",
376		"../src/tests/kits/translation/data/text/symbols",
377		"../src/tests/kits/translation/data/text/zero_length"
378	};
379	TranslateTests(this, proster, aPlainTextFiles,
380		sizeof(aPlainTextFiles) / sizeof(const char *), true);
381	TranslateTests(this, proster, aStyledTextFiles,
382		sizeof(aStyledTextFiles) / sizeof(const char *), false);
383}
384
385// Make certain that the STXTTranslator does not
386// provide a configuration message
387void
388STXTTranslatorTest::ConfigMessageTest()
389{
390	// Init
391	NextSubTest();
392	BTranslatorRoster *proster = new BTranslatorRoster();
393	CPPUNIT_ASSERT(proster);
394	CPPUNIT_ASSERT(proster->AddTranslators(
395		"/boot/home/config/add-ons/Translators/STXTTranslator") == B_OK);
396
397	// GetAllTranslators
398	NextSubTest();
399	translator_id tid, *pids = NULL;
400	int32 count = 0;
401	CPPUNIT_ASSERT(proster->GetAllTranslators(&pids, &count) == B_OK);
402	CPPUNIT_ASSERT(pids);
403	CPPUNIT_ASSERT(count == 1);
404	tid = pids[0];
405	delete[] pids;
406	pids = NULL;
407
408	// GetConfigurationMessage
409	NextSubTest();
410	BMessage msg;
411	CPPUNIT_ASSERT(proster->GetConfigurationMessage(tid, &msg) == B_OK);
412	CPPUNIT_ASSERT(!msg.IsEmpty());
413
414	// B_TRANSLATOR_EXT_HEADER_ONLY
415	NextSubTest();
416	bool bheaderonly = true;
417	CPPUNIT_ASSERT(
418		msg.FindBool(B_TRANSLATOR_EXT_HEADER_ONLY, &bheaderonly) == B_OK);
419	CPPUNIT_ASSERT(bheaderonly == false);
420
421	// B_TRANSLATOR_EXT_DATA_ONLY
422	NextSubTest();
423	bool bdataonly = true;
424	CPPUNIT_ASSERT(
425		msg.FindBool(B_TRANSLATOR_EXT_DATA_ONLY, &bdataonly) == B_OK);
426	CPPUNIT_ASSERT(bdataonly == false);
427}
428
429#if !TEST_R5
430
431// The input formats that this translator is supposed to support
432translation_format gSTXTInputFormats[] = {
433	{
434		B_TRANSLATOR_TEXT,
435		B_TRANSLATOR_TEXT,
436		0.4f, // quality
437		0.6f, // capability
438		"text/plain",
439		"Plain text file"
440	},
441	{
442		B_STYLED_TEXT_FORMAT,
443		B_TRANSLATOR_TEXT,
444		0.5f,
445		0.5f,
446		"text/x-vnd.Be-stxt",
447		"Be styled text file"
448	}
449};
450
451// The output formats that this translator is supposed to support
452translation_format gSTXTOutputFormats[] = {
453	{
454		B_TRANSLATOR_TEXT,
455		B_TRANSLATOR_TEXT,
456		0.4f, // quality
457		0.6f, // capability
458		"text/plain",
459		"Plain text file"
460	},
461	{
462		B_STYLED_TEXT_FORMAT,
463		B_TRANSLATOR_TEXT,
464		0.5f,
465		0.5f,
466		"text/x-vnd.Be-stxt",
467		"Be styled text file"
468	}
469};
470
471void
472STXTTranslatorTest::LoadAddOnTest()
473{
474	TranslatorLoadAddOnTest("/boot/home/config/add-ons/Translators/STXTTranslator",
475		this,
476		gSTXTInputFormats, sizeof(gSTXTInputFormats) / sizeof(translation_format),
477		gSTXTOutputFormats, sizeof(gSTXTOutputFormats) / sizeof(translation_format),
478		B_TRANSLATION_MAKE_VERSION(1,0,0));
479}
480
481#endif // #if !TEST_R5
482