aboutsummaryrefslogtreecommitdiff
path: root/engines/testbed
diff options
context:
space:
mode:
Diffstat (limited to 'engines/testbed')
-rw-r--r--engines/testbed/detection.cpp95
-rw-r--r--engines/testbed/gfxtests.cpp140
-rw-r--r--engines/testbed/gfxtests.h15
-rw-r--r--engines/testbed/graphics.cpp51
-rw-r--r--engines/testbed/graphics.h37
-rw-r--r--engines/testbed/module.mk18
-rw-r--r--engines/testbed/testbed.cpp73
-rw-r--r--engines/testbed/testbed.h18
-rw-r--r--engines/testbed/testsuite.h144
9 files changed, 591 insertions, 0 deletions
diff --git a/engines/testbed/detection.cpp b/engines/testbed/detection.cpp
new file mode 100644
index 0000000000..317b9e7dbd
--- /dev/null
+++ b/engines/testbed/detection.cpp
@@ -0,0 +1,95 @@
+#include "testbed/testbed.h"
+
+#include "common/config-manager.h"
+#include "common/error.h"
+#include "common/fs.h"
+
+#include "engines/metaengine.h"
+
+static const PlainGameDescriptor testbed_setting[] = {
+ { "testbed", "TestBed: The backend testing framework" },
+ { 0, 0 }
+};
+
+class TestbedMetaEngine : public MetaEngine {
+public:
+ virtual const char *getName() const {
+ return "TestBed: The backend testing framework";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ return "Copyright (C) ScummVM";
+ }
+
+ virtual GameList getSupportedGames() const {
+ GameList games;
+ const PlainGameDescriptor *g = testbed_setting;
+ while (g->gameid) {
+ games.push_back(*g);
+ g++;
+ }
+
+ return games;
+ }
+
+ virtual GameDescriptor findGame(const char *gameid) const {
+ const PlainGameDescriptor *g = testbed_setting;
+ while (g->gameid) {
+ if (0 == scumm_stricmp(gameid, g->gameid))
+ break;
+ g++;
+ }
+ return GameDescriptor(g->gameid, g->description);
+ }
+
+ virtual GameList detectGames(const Common::FSList &fslist) const {
+ GameList detectedGames;
+
+ // Iterate over all files in the given directory
+ for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
+ if (!file->isDirectory()) {
+ const char *gameName = file->getName().c_str();
+
+ if (0 == scumm_stricmp("README", gameName)) {
+ // You could check the contents of the file now if you need to.
+ detectedGames.push_back(testbed_setting[0]);
+ break;
+ }
+ }
+ }
+ return detectedGames;
+ }
+
+ virtual Common::Error createInstance(OSystem *syst, Engine **engine) const {
+ assert(syst);
+ assert(engine);
+
+ // Scan the target directory for files (error out if it does not exist)
+ Common::FSList fslist;
+ Common::FSNode dir(ConfMan.get("path"));
+ if (!dir.getChildren(fslist, Common::FSNode::kListAll)) {
+ return Common::kInvalidPathError;
+ }
+
+ // Invoke the detector
+ Common::String gameid = ConfMan.get("gameid");
+ GameList detectedGames = detectGames(fslist);
+
+ for (uint i = 0; i < detectedGames.size(); i++) {
+ if (detectedGames[i].gameid() == gameid) {
+ // At this point you may want to perform additional sanity checks.
+ *engine = new Testbed::TestbedEngine(syst);
+ return Common::kNoError;
+ }
+ }
+
+ // Failed to find any game data
+ return Common::kNoGameDataFoundError;
+ }
+};
+
+#if PLUGIN_ENABLED_DYNAMIC(TESTBED)
+ REGISTER_PLUGIN_DYNAMIC(TESTBED, PLUGIN_TYPE_ENGINE, TestbedMetaEngine);
+#else
+ REGISTER_PLUGIN_STATIC(TESTBED, PLUGIN_TYPE_ENGINE, TestbedMetaEngine);
+#endif
diff --git a/engines/testbed/gfxtests.cpp b/engines/testbed/gfxtests.cpp
new file mode 100644
index 0000000000..2eeb7125b2
--- /dev/null
+++ b/engines/testbed/gfxtests.cpp
@@ -0,0 +1,140 @@
+#include "testbed/gfxtests.h"
+#include "testbed/graphics.h"
+#include "testbed/testsuite.h"
+
+#include "graphics/fontman.h"
+#include "graphics/surface.h"
+#include "graphics/cursorman.h"
+
+namespace Testbed {
+
+bool testFullScreenMode() {
+
+ Testsuite::displayMessage("Testing fullscreen mode. \n \
+ If the feature is supported by the backend, you should expect to see a toggle between fullscreen and normal modes");
+
+ Common::Point pt(0,100);
+ Common::Rect rect = Testsuite::writeOnScreen("Testing fullscreen mode", pt);
+
+ bool isFeaturePresent;
+ bool isFeatureEnabled;
+
+ isFeaturePresent = g_system->hasFeature(OSystem::kFeatureFullscreenMode);
+ isFeatureEnabled = g_system->getFeatureState(OSystem::kFeatureFullscreenMode);
+ g_system->delayMillis(1000);
+
+ if (isFeaturePresent) {
+ //Toggle
+
+ g_system->beginGFXTransaction();
+ g_system->setFeatureState(OSystem::kFeatureFullscreenMode, !isFeatureEnabled);
+ g_system->endGFXTransaction();
+
+ g_system->delayMillis(1000);
+
+ g_system->beginGFXTransaction();
+ g_system->setFeatureState(OSystem::kFeatureFullscreenMode, isFeatureEnabled);
+ g_system->endGFXTransaction();
+ }
+ else {
+ Testsuite::displayMessage("feature not supported");
+ }
+
+ Testsuite::clearScreen(rect);
+ return true;
+}
+
+bool testAspectRatio() {
+ Testsuite::displayMessage("Testing Aspect Ratio Correction. \n \
+ With this feature enabled games running at 320x200 should be scaled upto 320x240 pixels");
+
+ Common::Point pt(0,100);
+ Common::Rect rect = Testsuite::writeOnScreen("Testing Aspect ratio correction", pt);
+
+ bool isFeaturePresent;
+ bool isFeatureEnabled;
+
+ isFeaturePresent = g_system->hasFeature(OSystem::kFeatureAspectRatioCorrection);
+ isFeatureEnabled = g_system->getFeatureState(OSystem::kFeatureAspectRatioCorrection);
+ g_system->delayMillis(1000);
+
+ if (isFeaturePresent) {
+ //Toggle
+
+ g_system->beginGFXTransaction();
+ g_system->setFeatureState(OSystem::kFeatureAspectRatioCorrection, !isFeatureEnabled);
+ g_system->endGFXTransaction();
+
+ g_system->delayMillis(1000);
+
+ g_system->beginGFXTransaction();
+ g_system->setFeatureState(OSystem::kFeatureAspectRatioCorrection, isFeatureEnabled);
+ g_system->endGFXTransaction();
+ }
+ else {
+ Testsuite::displayMessage("feature not supported");
+ }
+
+ Testsuite::clearScreen(rect);
+ return true;
+}
+
+bool testPalettizedCursors() {
+ Testsuite::displayMessage("Testing Cursors. You should expect to see a red colored cursor.\n");
+
+ Common::Point pt(0,100);
+ Common::Rect rect = Testsuite::writeOnScreen("Testing Palettized Cursors", pt);
+
+ bool isFeaturePresent;
+ bool isFeatureEnabled;
+
+ isFeaturePresent = g_system->hasFeature(OSystem::kFeatureCursorHasPalette);
+ isFeatureEnabled = g_system->getFeatureState(OSystem::kFeatureCursorHasPalette);
+ g_system->delayMillis(1000);
+
+ if (isFeaturePresent) {
+ byte palette[3 * 4]; // Black, white and yellow
+ palette[0] = palette[1] = palette[2] = 0;
+ palette[4] = palette[5] = palette[6] = 255;
+ palette[8] = palette[9] = 255;
+ palette[10] = 0;
+
+ byte buffer[10 * 10];
+ memset(buffer, 2, 10 * 10);
+
+ CursorMan.pushCursorPalette(palette, 0, 3);
+ CursorMan.pushCursor(buffer, 10, 10, 40, 40, 2, 1);
+ CursorMan.showMouse(true);
+ g_system->updateScreen();
+ }
+ else {
+ Testsuite::displayMessage("feature not supported");
+ }
+ Testsuite::clearScreen(rect);
+ return true;
+}
+
+bool testCopyRectToScreen() {
+ Testsuite::displayMessage("Testing Blitting a Bitmap to screen. \n\
+ You should expect to see a 20x40 yellow horizontal rectangle centred at the screen.");
+
+ GFXTestSuite::setCustomColor(255, 255, 0);
+ byte buffer[20 * 40];
+ memset(buffer, 2, 20 * 40);
+
+ uint x = g_system->getWidth() / 2 - 20;
+ uint y = g_system->getHeight() / 2 - 10;
+
+ g_system->copyRectToScreen(buffer, 40, x, y, 40, 20);
+ g_system->updateScreen();
+ g_system->delayMillis(1000);
+
+ Common::Rect rect(x, y, x+40, y+20);
+ Testsuite::clearScreen(rect);
+
+ return true;
+
+}
+
+
+}
diff --git a/engines/testbed/gfxtests.h b/engines/testbed/gfxtests.h
new file mode 100644
index 0000000000..bd219411e9
--- /dev/null
+++ b/engines/testbed/gfxtests.h
@@ -0,0 +1,15 @@
+#ifndef GFXTESTS_H
+#define GFXTESTS_H
+
+namespace Testbed {
+
+// will contain function declarations for GFX tests
+bool testFullScreenMode();
+bool testAspectRatio();
+bool testPalettizedCursors();
+bool testCopyRectToScreen();
+// add more here
+
+}
+
+#endif
diff --git a/engines/testbed/graphics.cpp b/engines/testbed/graphics.cpp
new file mode 100644
index 0000000000..ea1c1b1130
--- /dev/null
+++ b/engines/testbed/graphics.cpp
@@ -0,0 +1,51 @@
+#include "testbed/graphics.h"
+#include "testbed/gfxtests.h"
+
+namespace Testbed {
+
+byte GFXTestSuite::_palette[3 * 4] = {0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0};
+
+GFXTestSuite::GFXTestSuite() {
+ // Initialize color palettes
+ // Te fourth field is for alpha channel which is unused
+ // Assuming 8bpp as of now
+ g_system->setPalette(_palette, 0, 3);
+ g_system->grabPalette(_palette, 0, 3);
+
+ // Add tests here
+// addTest("FullScreenMode", &testFullScreenMode);
+// addTest("AspectRatio", &testAspectRatio);
+ addTest("PalettizedCursors", &testPalettizedCursors);
+// addTest("BlitBitmaps", &testCopyRectToScreen);
+}
+
+const char *GFXTestSuite::getName() {
+ return "GFX";
+}
+
+void GFXTestSuite::setCustomColor(uint r, uint g, uint b) {
+ _palette[8] = r;
+ _palette[9] = g;
+ _palette[10] = b;
+ g_system->setPalette(_palette, 0, 3);
+ g_system->grabPalette(_palette, 0, 3);
+}
+
+void GFXTestSuite::execute() {
+ for (Common::Array<Test*>::iterator i = _testsToExecute.begin(); i != _testsToExecute.end(); ++i) {
+ printf("Executing Test:%s\n", ((*i)->featureName).c_str());
+ // Invoke the test
+ (*i)->driver();
+ _numTestsExecuted++;
+ // Verify result by Interacting with the tester.
+ Common::String prompt("Was this similar to what you expected?");
+ if (handleInteractiveInput(prompt)) {
+ _numTestsPassed++;
+ }
+ }
+
+ // Report Generation
+ genReport();
+}
+
+}
diff --git a/engines/testbed/graphics.h b/engines/testbed/graphics.h
new file mode 100644
index 0000000000..eb84310db7
--- /dev/null
+++ b/engines/testbed/graphics.h
@@ -0,0 +1,37 @@
+#ifndef GRAPHICS_H
+#define GRAPHICS_H
+
+#include "testbed/testsuite.h"
+
+namespace Testbed {
+
+class GFXTestSuite : public Testsuite {
+public:
+ /**
+ * The constructor for the GFXTestSuite
+ * For every test to be executed one must:
+ * 1) Create a function that would invoke the test
+ * 2) Add that test to list by executing addTest()
+ *
+ * @see addTest()
+ */
+ GFXTestSuite();
+ ~GFXTestSuite(){}
+ void execute();
+ const char *getName();
+ static void setCustomColor(uint r, uint g, uint b);
+
+private:
+ /**
+ * A Palette consists of 4 components RGBA.
+ * As of now we only take 3 colors
+ * 0 (R:0, G:0, B:0) Black (kColorBlack)
+ * 1 (R:255, G:255, B:255) White (kColorWhite)
+ * 2 (R:255, G:255, B:255) your customized color (by default white) (kColorCustom)
+ */
+ static byte _palette[3 * 4];
+};
+
+} // End of namespace Testbed
+
+#endif
diff --git a/engines/testbed/module.mk b/engines/testbed/module.mk
new file mode 100644
index 0000000000..0c19aba441
--- /dev/null
+++ b/engines/testbed/module.mk
@@ -0,0 +1,18 @@
+MODULE := engines/testbed
+
+MODULE_OBJS := \
+ detection.o \
+ graphics.o \
+ gfxtests.o \
+ testbed.o
+
+MODULE_DIRS += \
+ engines/testbed
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_TESTBED), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/testbed/testbed.cpp b/engines/testbed/testbed.cpp
new file mode 100644
index 0000000000..4d178d80bd
--- /dev/null
+++ b/engines/testbed/testbed.cpp
@@ -0,0 +1,73 @@
+#include "common/scummsys.h"
+#include "common/system.h"
+
+#include "engines/util.h"
+
+#include "testbed/testbed.h"
+#include "testbed/graphics.h"
+
+namespace Testbed {
+
+TestbedEngine::TestbedEngine(OSystem *syst)
+ : Engine(syst) {
+ // Put your engine in a sane state, but do nothing big yet;
+ // in particular, do not load data from files; rather, if you
+ // need to do such things, do them from init().
+
+ // Do not initialize graphics here
+
+ // However this is the place to specify all default directories
+
+ printf("TestbedEngine::TestbedEngine()\n");
+}
+
+TestbedEngine::~TestbedEngine() {
+ // Dispose your resources here
+ printf("TestbedEngine::~TestbedEngine()\n");
+
+ // Remove all of our debug levels here
+}
+
+Common::Error TestbedEngine::run() {
+ // Initialize graphics using following:
+ initGraphics(320, 200, false);
+
+ // You could use backend transactions directly as an alternative,
+ // but it isn't recommended, until you want to handle the error values
+ // from OSystem::endGFXTransaction yourself.
+ // This is just an example template:
+ //_system->beginGFXTransaction();
+ // // This setup the graphics mode according to users seetings
+ // initCommonGFX(false);
+ //
+ // // Specify dimensions of game graphics window.
+ // // In this example: 320x200
+ // _system->initSize(320, 200);
+ //FIXME: You really want to handle
+ //OSystem::kTransactionSizeChangeFailed here
+ //_system->endGFXTransaction();
+
+ // Additional setup.
+ printf("TestbedEngine::init\n");
+
+ // As of now we are using GUI::MessageDialog for interaction, Test if it works.
+ // interactive mode could also be modified by a config parameter "non-interactive=1"
+ // TODO: Implement that
+
+ bool interactive;
+ Common::String prompt("Welcome to the ScummVM testbed! \n \
+ It is a framework to test the various ScummVM subsystems namely GFX, Sound, FS, events etc. \n \
+ If you are seeing this correctly, it means interactive tests would run on this system :)");
+ interactive = Testsuite::handleInteractiveInput(prompt);
+
+ if (interactive) {
+ printf("Running tests in Interactive Mode\n");
+ // Executing GFX Tests
+ GFXTestSuite ts;
+ ts.execute();
+ }
+
+ return Common::kNoError;
+}
+
+} // End of namespace Testbed
diff --git a/engines/testbed/testbed.h b/engines/testbed/testbed.h
new file mode 100644
index 0000000000..47ef6adbf3
--- /dev/null
+++ b/engines/testbed/testbed.h
@@ -0,0 +1,18 @@
+#ifndef TESTBED_H
+#define TESTBED_H
+
+#include "engines/engine.h"
+
+namespace Testbed {
+
+class TestbedEngine : public Engine {
+public:
+ TestbedEngine(OSystem *syst);
+ ~TestbedEngine();
+
+ virtual Common::Error run();
+};
+
+} // End of namespace Testbed
+
+#endif
diff --git a/engines/testbed/testsuite.h b/engines/testbed/testsuite.h
new file mode 100644
index 0000000000..ffeb2588c4
--- /dev/null
+++ b/engines/testbed/testsuite.h
@@ -0,0 +1,144 @@
+#ifndef TESTSUITE_H
+#define TESTSUITE_H
+
+#include "common/system.h"
+#include "common/str.h"
+#include "common/array.h"
+
+#include "graphics/fontman.h"
+#include "graphics/surface.h"
+
+#include "gui/message.h"
+
+namespace Testbed {
+
+enum {
+ kColorBlack = 0,
+ kColorWhite = 1,
+ kColorCustom = 2
+};
+
+typedef bool (*invokingFunction)();
+
+/**
+ * This represents a feature to be tested
+ */
+
+struct Test {
+ Test(Common::String name, invokingFunction f) : featureName(name), driver(f), enabled(true), passed(false) {}
+ Common::String featureName; ///< Name of feature to be tested
+ invokingFunction driver; ///< Pointer to the function that will invoke this feature test
+ bool enabled; ///< Decides whether or not this test is to be executed
+ bool passed; ///< Collects and stores result of this feature test
+};
+
+
+/**
+ * The basic Testsuite class
+ * All the other testsuites would inherit it and override its virtual methods
+ */
+
+class Testsuite {
+public:
+ Testsuite() {
+ _numTestsPassed = 0;
+ _numTestsExecuted = 0;
+ }
+
+ virtual ~Testsuite() {
+ for (Common::Array<Test*>::iterator i = _testsToExecute.begin(); i != _testsToExecute.end(); ++i) {
+ delete (*i);
+ }
+ }
+
+ int getNumTests() { return _testsToExecute.size(); }
+ int getNumTestsPassed() { return _numTestsPassed; }
+ int getNumTestsFailed() { return _numTestsExecuted - _numTestsPassed; }
+ void genReport() {
+ printf("Subsystem:%s\n",getName());
+ printf("Tests executed:%d\n", _numTestsExecuted);
+ printf("Tests Passed:%d\n", _numTestsPassed);
+ printf("Tests Failed:%d\n", getNumTestsFailed());
+ }
+
+ /**
+ * Prompts for User Input in form of "Yes" or "No" for interactive tests
+ * e.g: "Is this like you expect?" "Yes" or "No"
+ *
+ * @param textToDisplay Display text
+ * @return true if "Yes" false otherwise
+ */
+ static bool handleInteractiveInput(const Common::String &textToDisplay) {
+ GUI::MessageDialog prompt(textToDisplay, "Yes", "No");
+ return prompt.runModal() == GUI::kMessageOK ? true : false;
+ }
+
+ static void displayMessage(const Common::String &textToDisplay) {
+ GUI::MessageDialog prompt(textToDisplay);
+ prompt.runModal();
+ }
+
+ static Common::Rect writeOnScreen(const Common::String &textToDisplay, const Common::Point &pt) {
+ const Graphics::Font &font(*FontMan.getFontByUsage(Graphics::FontManager::kConsoleFont));
+
+ Graphics::Surface *screen = g_system->lockScreen();
+
+ int height = font.getFontHeight();
+ int width = screen->w;
+
+ Common::Rect rect(pt.x, pt.y, pt.x + width, pt.y + height);
+
+ screen->fillRect(rect, kColorBlack);
+ font.drawString(screen, textToDisplay, rect.left, rect.top, screen->w, kColorWhite, Graphics::kTextAlignCenter);
+
+ g_system->unlockScreen();
+ g_system->updateScreen();
+
+ return rect;
+ }
+
+ static void clearScreen(const Common::Rect &rect) {
+ Graphics::Surface *screen = g_system->lockScreen();
+
+ screen->fillRect(rect, kColorBlack);
+
+ g_system->unlockScreen();
+ g_system->updateScreen();
+ }
+
+ /**
+ * Adds a test to the list of tests to be executed
+ *
+ * @param name the string description of the test, for display purposes
+ * @param f pointer to the function that invokes this test
+ */
+ void addTest(const Common::String &name, invokingFunction f) {
+ Test* featureTest = new Test(name, f);
+ _testsToExecute.push_back(featureTest);
+ }
+
+ /**
+ * The driver function for the testsuite
+ * All code should go in here.
+ */
+ virtual void execute() {
+ for (Common::Array<Test*>::iterator i = _testsToExecute.begin(); i != _testsToExecute.end(); ++i) {
+ printf("Executing Test:%s\n", ((*i)->featureName).c_str());
+ _numTestsExecuted++;
+ if ((*i)->driver()) {
+ _numTestsPassed++;
+ }
+ }
+ genReport();
+ }
+ virtual const char *getName() = 0;
+
+protected:
+ Common::Array<Test*> _testsToExecute; ///< List of tests to be executed
+ int _numTestsPassed; ///< Number of tests passed
+ int _numTestsExecuted; ///< Number of tests executed
+};
+
+} // End of namespace testbed
+
+#endif