⛏️ index : haiku.git

// TranslatorTestAddOn.cpp

#include <stdio.h>
#include <string.h>
#include <Translator.h>
#include <OS.h>
#include "TranslatorTestAddOn.h"

// ##### Include headers for your tests here #####
#include "bmptranslator/BMPTranslatorTest.h"
#include "pngtranslator/PNGTranslatorTest.h"
#include "stxttranslator/STXTTranslatorTest.h"
#include "tgatranslator/TGATranslatorTest.h"
#include "tifftranslator/TIFFTranslatorTest.h"

BTestSuite *
getTestSuite()
{
	BTestSuite *suite = new BTestSuite("Translators");

	// ##### Add test suites here #####
	suite->addTest("BMPTranslator", BMPTranslatorTest::Suite());
	suite->addTest("PNGTranslator", PNGTranslatorTest::Suite());
	suite->addTest("STXTTranslator", STXTTranslatorTest::Suite());
	suite->addTest("TGATranslator", TGATranslatorTest::Suite());
	suite->addTest("TIFFTranslator", TIFFTranslatorTest::Suite());

	return suite;
}

// helper function used by multiple tests to
// determine if the given streams are exactly
// the same
bool
CompareStreams(BPositionIO &a, BPositionIO &b)
{
	off_t alen = 0, blen = 0;
	const uint32 kbuflen = 2048;
	uint8 abuf[kbuflen], bbuf[kbuflen];

	a.Seek(0, SEEK_END);
	alen = a.Position();
	b.Seek(0, SEEK_END);
	blen = b.Position();
	if (alen != blen)
		return false;

	if (a.Seek(0, SEEK_SET) != 0)
		return false;
	if (b.Seek(0, SEEK_SET) != 0)
		return false;

	ssize_t read = 0;
	while (alen > 0) {
		read = a.Read(abuf, kbuflen);
		if (read < 0)
			return false;
		if (b.Read(bbuf, read) != read)
			return false;

		if (memcmp(abuf, bbuf, read) != 0)
			return false;

		alen -= read;
	}

	return true;
}

// Check each member of translator_info to see that it matches
// what is expected
void
CheckTranslatorInfo(translator_info *pti, uint32 type, uint32 group,
	float quality, float capability, const char *name, const char *mime)
{
	CPPUNIT_ASSERT(pti->type == type);
	CPPUNIT_ASSERT(pti->translator != 0);
	CPPUNIT_ASSERT(pti->group == group);
	CPPUNIT_ASSERT(pti->quality > quality - 0.01f &&
		pti->quality < quality + 0.01f);
	CPPUNIT_ASSERT(pti->capability > capability - 0.01f &&
		pti->capability < capability + 0.01f);
	CPPUNIT_ASSERT(strcmp(pti->name, name) == 0);
	CPPUNIT_ASSERT(strcmp(pti->MIME, mime) == 0);
}

// Returns true if the translation_formats are
// identical (or nearly identical).  Returns false if
// they are different
bool
CompareTranslationFormat(const translation_format *pleft,
	const translation_format *pright)
{
	CPPUNIT_ASSERT(pleft->MIME);
	CPPUNIT_ASSERT(pright->MIME);
	CPPUNIT_ASSERT(pleft->name);
	CPPUNIT_ASSERT(pright->name);

	if (pleft->group != pright->group)
		return false;
	if (pleft->type != pright->type)
		return false;
	if (pleft->quality < pright->quality - 0.01f ||
		pleft->quality > pright->quality + 0.01f)
		return false;
	if (pleft->capability < pright->capability - 0.01f ||
		pleft->capability > pright->capability + 0.01f)
		return false;
	if (strcmp(pleft->MIME, pright->MIME) != 0)
		return false;
	if (strcmp(pleft->name, pright->name) != 0)
		return false;

	return true;
}

// Apply a number of tests to a BTranslator * to a TGATranslator object
void
TestBTranslator(BTestCase *ptest, BTranslator *ptran,
	const translation_format *pExpectedIns, uint32 nExpectedIns,
	const translation_format *pExpectedOuts, uint32 nExpectedOuts,
	int32 expectedVer)
{
	const uint32 knmatches = 50;
	uint8 matches[knmatches];
	CPPUNIT_ASSERT(nExpectedIns <= knmatches && nExpectedOuts <= knmatches);

	// The translator should only have one reference
	ptest->NextSubTest();
	CPPUNIT_ASSERT(ptran->ReferenceCount() == 1);

	// Make sure Acquire returns a BTranslator even though its
	// already been Acquired once
	ptest->NextSubTest();
	CPPUNIT_ASSERT(ptran->Acquire() == ptran);

	// Acquired twice, refcount should be 2
	ptest->NextSubTest();
	CPPUNIT_ASSERT(ptran->ReferenceCount() == 2);

	// Release should return ptran because it is still acquired
	ptest->NextSubTest();
	CPPUNIT_ASSERT(ptran->Release() == ptran);

	ptest->NextSubTest();
	CPPUNIT_ASSERT(ptran->ReferenceCount() == 1);

	ptest->NextSubTest();
	CPPUNIT_ASSERT(ptran->Acquire() == ptran);

	ptest->NextSubTest();
	CPPUNIT_ASSERT(ptran->ReferenceCount() == 2);

	ptest->NextSubTest();
	CPPUNIT_ASSERT(ptran->Release() == ptran);

	ptest->NextSubTest();
	CPPUNIT_ASSERT(ptran->ReferenceCount() == 1);

	// A name would be nice
	ptest->NextSubTest();
	const char *tranname = ptran->TranslatorName();
	CPPUNIT_ASSERT(tranname);
	printf(" {%s} ", tranname);

	// More info would be nice
	ptest->NextSubTest();
	const char *traninfo = ptran->TranslatorInfo();
	CPPUNIT_ASSERT(traninfo);
	printf(" {%s} ", traninfo);

	// What version are you?
	// (when ver == 100, that means that version is 1.00)
	ptest->NextSubTest();
	int32 ver = ptran->TranslatorVersion();
	CPPUNIT_ASSERT(ver == expectedVer);
	printf(" {0x%.8lx} ", ver);

	// Input formats?
	ptest->NextSubTest();
	{
		printf("input:");

		int32 incount = 0;
		const translation_format *pins = ptran->InputFormats(&incount);
		CPPUNIT_ASSERT((unsigned)incount == nExpectedIns);
		CPPUNIT_ASSERT(pins);

		memset(matches, 0, sizeof(uint8) * nExpectedIns);
		for (int32 i = 0; i < incount; i++) {
			bool bmatch = false;
			for (uint32 k = 0; bmatch == false && k < nExpectedIns; k++) {
				bmatch = CompareTranslationFormat(pins + i, pExpectedIns + k);
				if (bmatch)
					matches[k] = 1;
			}

			CPPUNIT_ASSERT(bmatch);
		}

		// make sure that each expected input format was matched
		for (uint32 i = 0; i < nExpectedIns; i++)
			CPPUNIT_ASSERT(matches[i]);
	}

	// Output formats?
	ptest->NextSubTest();
	{
		printf("output:");

		int32 outcount = 0;
		const translation_format *pouts = ptran->OutputFormats(&outcount);
		CPPUNIT_ASSERT((unsigned)outcount == nExpectedOuts);
		CPPUNIT_ASSERT(pouts);

		memset(matches, 0, sizeof(uint8) * nExpectedOuts);
		for (int32 i = 0; i < outcount; i++) {
			bool bmatch = false;
			for (uint32 k = 0; bmatch == false && k < nExpectedOuts; k++) {
				bmatch = CompareTranslationFormat(pouts + i, pExpectedOuts + k);
				if (bmatch)
					matches[k] = 1;
			}

			CPPUNIT_ASSERT(bmatch);
		}

		// make sure that each expected input format was matched
		for (uint32 i = 0; i < nExpectedOuts; i++)
			CPPUNIT_ASSERT(matches[i]);
	}

	// Release should return NULL because Release has been called
	// as many times as it has been acquired
	ptest->NextSubTest();
	CPPUNIT_ASSERT(ptran->Release() == NULL);
	ptran = NULL;
}

void
TranslatorLoadAddOnTest(const char *path, BTestCase *ptest,
	const translation_format *pExpectedIns, uint32 nExpectedIns,
	const translation_format *pExpectedOuts, uint32 nExpectedOuts,
	int32 expectedVer)
{
	// Make sure the add_on loads
	ptest->NextSubTest();
	image_id image = load_add_on(path);
	CPPUNIT_ASSERT(image >= 0);

	// Load in function to make the object
	ptest->NextSubTest();
	BTranslator *(*pMakeNthTranslator)(int32 n,image_id you,uint32 flags,...);
	status_t err = get_image_symbol(image, "make_nth_translator",
		B_SYMBOL_TYPE_TEXT, (void **)&pMakeNthTranslator);
	CPPUNIT_ASSERT(!err);

	// Make sure the function returns a pointer to a BTranslator
	ptest->NextSubTest();
	BTranslator *ptran = pMakeNthTranslator(0, image, 0);
	CPPUNIT_ASSERT(ptran);

	// Make sure the function only returns one BTranslator
	ptest->NextSubTest();
	CPPUNIT_ASSERT(!pMakeNthTranslator(1, image, 0));
	CPPUNIT_ASSERT(!pMakeNthTranslator(2, image, 0));
	CPPUNIT_ASSERT(!pMakeNthTranslator(3, image, 0));
	CPPUNIT_ASSERT(!pMakeNthTranslator(16, image, 0));
	CPPUNIT_ASSERT(!pMakeNthTranslator(1023, image, 0));

	// Run a number of tests on the BTranslator object
	TestBTranslator(ptest, ptran, pExpectedIns, nExpectedIns,
		pExpectedOuts, nExpectedOuts, expectedVer);
		// NOTE: this function Release()s ptran
	ptran = NULL;

	// Unload Add-on
	ptest->NextSubTest();
	CPPUNIT_ASSERT(unload_add_on(image) == B_OK);
}