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	// Perform translations on every file in the array
216	for (int32 i = 0; i < len; i++) {
217		strcpy(styled_path, paths[i]);
218		strcat(styled_path, ".stxt");
219		strcpy(plain_path, paths[i]);
220		strcat(plain_path, ".txt");
221
222		// Setup input files
223		ptest->NextSubTest();
224		BFile styled_file, plain_file, *pinput_file;
225		CPPUNIT_ASSERT(styled_file.SetTo(styled_path, B_READ_ONLY) == B_OK);
226		CPPUNIT_ASSERT(plain_file.SetTo(plain_path, B_READ_ONLY) == B_OK);
227		if (bplain) {
228			printf(" [%s] ", plain_path);
229			pinput_file = &plain_file;
230		} else {
231			printf(" [%s] ", styled_path);
232			pinput_file = &styled_file;
233		}
234
235		BMallocIO mallio, dmallio;
236
237		// Convert to B_TRANSLATOR_ANY_TYPE (should be B_TRANSLATOR_TEXT)
238		ptest->NextSubTest();
239		CPPUNIT_ASSERT(mallio.Seek(0, SEEK_SET) == 0);
240		CPPUNIT_ASSERT(mallio.SetSize(0) == B_OK);
241		CPPUNIT_ASSERT(proster->Translate(pinput_file, NULL, NULL, &mallio,
242			B_TRANSLATOR_ANY_TYPE) == B_OK);
243		CPPUNIT_ASSERT(CompareStreams(mallio, plain_file) == true);
244
245		// Convert to B_TRANSLATOR_TEXT
246		ptest->NextSubTest();
247		CPPUNIT_ASSERT(mallio.Seek(0, SEEK_SET) == 0);
248		CPPUNIT_ASSERT(mallio.SetSize(0) == B_OK);
249		CPPUNIT_ASSERT(proster->Translate(pinput_file, NULL, NULL, &mallio,
250			B_TRANSLATOR_TEXT) == B_OK);
251		CPPUNIT_ASSERT(CompareStreams(mallio, plain_file) == true);
252
253		// Convert plain mallio to B_TRANSLATOR_TEXT dmallio
254		ptest->NextSubTest();
255		CPPUNIT_ASSERT(dmallio.Seek(0, SEEK_SET) == 0);
256		CPPUNIT_ASSERT(dmallio.SetSize(0) == B_OK);
257		CPPUNIT_ASSERT(proster->Translate(&mallio, NULL, NULL, &dmallio,
258			B_TRANSLATOR_TEXT) == B_OK);
259		CPPUNIT_ASSERT(CompareStreams(dmallio, plain_file) == true);
260
261		// Convert to B_STYLED_TEXT_FORMAT
262		ptest->NextSubTest();
263		CPPUNIT_ASSERT(mallio.Seek(0, SEEK_SET) == 0);
264		CPPUNIT_ASSERT(mallio.SetSize(0) == B_OK);
265		CPPUNIT_ASSERT(proster->Translate(pinput_file, NULL, NULL, &mallio,
266			B_STYLED_TEXT_FORMAT) == B_OK);
267		CPPUNIT_ASSERT(CompareStreams(mallio, styled_file) == true);
268
269		// Convert styled mallio to B_TRANSLATOR_TEXT dmallio
270		ptest->NextSubTest();
271		CPPUNIT_ASSERT(dmallio.Seek(0, SEEK_SET) == 0);
272		CPPUNIT_ASSERT(dmallio.SetSize(0) == B_OK);
273		CPPUNIT_ASSERT(proster->Translate(&mallio, NULL, NULL, &dmallio,
274			B_TRANSLATOR_TEXT) == B_OK);
275		CPPUNIT_ASSERT(CompareStreams(dmallio, plain_file) == true);
276
277		// Convert styled mallio to B_STYLED_TEXT_FORMAT dmallio
278		ptest->NextSubTest();
279		CPPUNIT_ASSERT(dmallio.Seek(0, SEEK_SET) == 0);
280		CPPUNIT_ASSERT(dmallio.SetSize(0) == B_OK);
281		CPPUNIT_ASSERT(proster->Translate(&mallio, NULL, NULL, &dmallio,
282			B_STYLED_TEXT_FORMAT) == B_OK);
283		CPPUNIT_ASSERT(CompareStreams(dmallio, styled_file) == true);
284	}
285
286	delete[] styled_path;
287	styled_path = NULL;
288	delete[] plain_path;
289	plain_path = NULL;
290}
291
292void
293STXTTranslatorTest::TranslateTest()
294{
295	// Init
296	NextSubTest();
297	status_t result = B_ERROR;
298	off_t filesize = -1;
299	BTranslatorRoster *proster = new BTranslatorRoster();
300	CPPUNIT_ASSERT(proster);
301	CPPUNIT_ASSERT(proster->AddTranslators(
302		"/boot/home/config/add-ons/Translators/STXTTranslator") == B_OK);
303	BFile wronginput("../src/tests/kits/translation/data/images/image.jpg",
304		B_READ_ONLY);
305	CPPUNIT_ASSERT(wronginput.InitCheck() == B_OK);
306	BFile output("/tmp/stxt_test.out", B_READ_WRITE |
307		B_CREATE_FILE | B_ERASE_FILE);
308	CPPUNIT_ASSERT(output.InitCheck() == B_OK);
309
310	// Translate (bad input, output types)
311	NextSubTest();
312	result = proster->Translate(&wronginput, NULL, NULL, &output,
313		B_TRANSLATOR_BITMAP);
314	CPPUNIT_ASSERT(result == B_NO_TRANSLATOR);
315	CPPUNIT_ASSERT(output.GetSize(&filesize) == B_OK);
316	CPPUNIT_ASSERT(filesize == 0);
317
318	// Translate (wrong type of input data)
319	NextSubTest();
320	result = proster->Translate(&wronginput, NULL, NULL, &output,
321		B_TRANSLATOR_TEXT);
322	CPPUNIT_ASSERT(result == B_OK);
323	CPPUNIT_ASSERT(CompareStreams(wronginput, output) == true);
324
325	// Translate (wrong type of input, B_TRANSLATOR_ANY_TYPE output)
326	NextSubTest();
327	CPPUNIT_ASSERT(output.Seek(0, SEEK_SET) == 0);
328	CPPUNIT_ASSERT(output.SetSize(0) == B_OK);
329	result = proster->Translate(&wronginput, NULL, NULL, &output,
330		B_TRANSLATOR_ANY_TYPE);
331	CPPUNIT_ASSERT(result == B_OK);
332	CPPUNIT_ASSERT(CompareStreams(wronginput, output) == true);
333
334	// Translate (wrong magic)
335	NextSubTest();
336	CPPUNIT_ASSERT(output.Seek(0, SEEK_SET) == 0);
337	CPPUNIT_ASSERT(output.SetSize(0) == B_OK);
338	BFile wrongmagic("../src/tests/kits/translation/data/text/wrong_magic.stxt",
339		B_READ_ONLY);
340	CPPUNIT_ASSERT(wrongmagic.InitCheck() == B_OK);
341	result = proster->Translate(&wrongmagic, NULL, NULL, &output,
342		B_TRANSLATOR_ANY_TYPE);
343	CPPUNIT_ASSERT(result == B_OK);
344	CPPUNIT_ASSERT(CompareStreams(wrongmagic, output) == true);
345
346	// Translate (wrong version)
347	NextSubTest();
348	CPPUNIT_ASSERT(output.Seek(0, SEEK_SET) == 0);
349	CPPUNIT_ASSERT(output.SetSize(0) == B_OK);
350	BFile wrongversion("../src/tests/kits/translation/data/text/wrong_version.stxt",
351		B_READ_ONLY);
352	CPPUNIT_ASSERT(wrongversion.InitCheck() == B_OK);
353	result = proster->Translate(&wrongversion, NULL, NULL, &output,
354		B_TRANSLATOR_ANY_TYPE);
355	CPPUNIT_ASSERT(result == B_OK);
356	CPPUNIT_ASSERT(CompareStreams(wrongversion, output) == true);
357
358	// Translate various data
359	const char *aPlainTextFiles[] = {
360		"../src/tests/kits/translation/data/text/ascii",
361		"../src/tests/kits/translation/data/text/japanese",
362		"../src/tests/kits/translation/data/text/multi_byte",
363		"../src/tests/kits/translation/data/text/one_length",
364		"../src/tests/kits/translation/data/text/symbols",
365		"../src/tests/kits/translation/data/text/zero_length"
366	};
367	const char *aStyledTextFiles[] = {
368		"../src/tests/kits/translation/data/text/ascii",
369		"../src/tests/kits/translation/data/text/japanese",
370		"../src/tests/kits/translation/data/text/multi_byte",
371		"../src/tests/kits/translation/data/text/one_length",
372		"../src/tests/kits/translation/data/text/sentence",
373		"../src/tests/kits/translation/data/text/symbols",
374		"../src/tests/kits/translation/data/text/zero_length"
375	};
376	TranslateTests(this, proster, aPlainTextFiles,
377		sizeof(aPlainTextFiles) / sizeof(const char *), true);
378	TranslateTests(this, proster, aStyledTextFiles,
379		sizeof(aStyledTextFiles) / sizeof(const char *), false);
380}
381
382// Make certain that the STXTTranslator does not
383// provide a configuration message
384void
385STXTTranslatorTest::ConfigMessageTest()
386{
387	// Init
388	NextSubTest();
389	BTranslatorRoster *proster = new BTranslatorRoster();
390	CPPUNIT_ASSERT(proster);
391	CPPUNIT_ASSERT(proster->AddTranslators(
392		"/boot/home/config/add-ons/Translators/STXTTranslator") == B_OK);
393
394	// GetAllTranslators
395	NextSubTest();
396	translator_id tid, *pids = NULL;
397	int32 count = 0;
398	CPPUNIT_ASSERT(proster->GetAllTranslators(&pids, &count) == B_OK);
399	CPPUNIT_ASSERT(pids);
400	CPPUNIT_ASSERT(count == 1);
401	tid = pids[0];
402	delete[] pids;
403	pids = NULL;
404
405	// GetConfigurationMessage
406	NextSubTest();
407	BMessage msg;
408	CPPUNIT_ASSERT(proster->GetConfigurationMessage(tid, &msg) == B_OK);
409	CPPUNIT_ASSERT(!msg.IsEmpty());
410
411	// B_TRANSLATOR_EXT_HEADER_ONLY
412	NextSubTest();
413	bool bheaderonly = true;
414	CPPUNIT_ASSERT(
415		msg.FindBool(B_TRANSLATOR_EXT_HEADER_ONLY, &bheaderonly) == B_OK);
416	CPPUNIT_ASSERT(bheaderonly == false);
417
418	// B_TRANSLATOR_EXT_DATA_ONLY
419	NextSubTest();
420	bool bdataonly = true;
421	CPPUNIT_ASSERT(
422		msg.FindBool(B_TRANSLATOR_EXT_DATA_ONLY, &bdataonly) == B_OK);
423	CPPUNIT_ASSERT(bdataonly == false);
424}
425
426#if !TEST_R5
427
428// The input formats that this translator is supposed to support
429translation_format gSTXTInputFormats[] = {
430	{
431		B_TRANSLATOR_TEXT,
432		B_TRANSLATOR_TEXT,
433		0.4f, // quality
434		0.6f, // capability
435		"text/plain",
436		"Plain text file"
437	},
438	{
439		B_STYLED_TEXT_FORMAT,
440		B_TRANSLATOR_TEXT,
441		0.5f,
442		0.5f,
443		"text/x-vnd.Be-stxt",
444		"Be styled text file"
445	}
446};
447
448// The output formats that this translator is supposed to support
449translation_format gSTXTOutputFormats[] = {
450	{
451		B_TRANSLATOR_TEXT,
452		B_TRANSLATOR_TEXT,
453		0.4f, // quality
454		0.6f, // capability
455		"text/plain",
456		"Plain text file"
457	},
458	{
459		B_STYLED_TEXT_FORMAT,
460		B_TRANSLATOR_TEXT,
461		0.5f,
462		0.5f,
463		"text/x-vnd.Be-stxt",
464		"Be styled text file"
465	}
466};
467
468void
469STXTTranslatorTest::LoadAddOnTest()
470{
471	TranslatorLoadAddOnTest("/boot/home/config/add-ons/Translators/STXTTranslator",
472		this,
473		gSTXTInputFormats, sizeof(gSTXTInputFormats) / sizeof(translation_format),
474		gSTXTOutputFormats, sizeof(gSTXTOutputFormats) / sizeof(translation_format),
475		B_TRANSLATION_MAKE_VERSION(1,0,0));
476}
477
478#endif // #if !TEST_R5
479