diff options
author | Eugene Sandulenko | 2016-08-30 13:54:12 +0200 |
---|---|---|
committer | GitHub | 2016-08-30 13:54:12 +0200 |
commit | bfbfbd3e1a8397cc3b1c9eaff6c7754abe3ddc3d (patch) | |
tree | 68851bdc99b78b4b1902944c1df3c3ee5d4f4489 /engines | |
parent | 7df744c291e5fcf5dc7afd3b21189c2c56810f8e (diff) | |
parent | 368f664c813075f8b8cb2c572dce65f60128eda4 (diff) | |
download | scummvm-rg350-bfbfbd3e1a8397cc3b1c9eaff6c7754abe3ddc3d.tar.gz scummvm-rg350-bfbfbd3e1a8397cc3b1c9eaff6c7754abe3ddc3d.tar.bz2 scummvm-rg350-bfbfbd3e1a8397cc3b1c9eaff6c7754abe3ddc3d.zip |
Merge pull request #788 from Tkachov/cloud
ALL: Add Cloud storage support
Diffstat (limited to 'engines')
46 files changed, 1117 insertions, 35 deletions
diff --git a/engines/access/detection.cpp b/engines/access/detection.cpp index 368753f117..3e70de3635 100644 --- a/engines/access/detection.cpp +++ b/engines/access/detection.cpp @@ -111,7 +111,8 @@ bool AccessMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSupportsLoadingDuringStartup) || (f == kSupportsDeleteSave) || (f == kSavesSupportMetaInfo) || - (f == kSavesSupportThumbnail); + (f == kSavesSupportThumbnail) || + (f == kSimpleSavesNames); } bool Access::AccessEngine::hasFeature(EngineFeature f) const { diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp index be9165b127..10812d79ea 100644 --- a/engines/adl/detection.cpp +++ b/engines/adl/detection.cpp @@ -205,6 +205,7 @@ bool AdlMetaEngine::hasFeature(MetaEngineFeature f) const { case kSavesSupportThumbnail: case kSavesSupportCreationDate: case kSavesSupportPlayTime: + case kSimpleSavesNames: return true; default: return false; diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp index 9f66d78d80..5cb239f8d8 100644 --- a/engines/agi/detection.cpp +++ b/engines/agi/detection.cpp @@ -231,7 +231,8 @@ bool AgiMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSavesSupportMetaInfo) || (f == kSavesSupportThumbnail) || (f == kSavesSupportCreationDate) || - (f == kSavesSupportPlayTime); + (f == kSavesSupportPlayTime) || + (f == kSimpleSavesNames); } bool AgiBase::hasFeature(EngineFeature f) const { diff --git a/engines/agos/detection.cpp b/engines/agos/detection.cpp index 2c89522089..dbc4ee9145 100644 --- a/engines/agos/detection.cpp +++ b/engines/agos/detection.cpp @@ -125,7 +125,8 @@ public: bool AgosMetaEngine::hasFeature(MetaEngineFeature f) const { return - (f == kSupportsListSaves); + (f == kSupportsListSaves) || + (f == kSimpleSavesNames); } bool AGOS::AGOSEngine::hasFeature(EngineFeature f) const { diff --git a/engines/avalanche/detection.cpp b/engines/avalanche/detection.cpp index e35c5d2cac..def395b77f 100644 --- a/engines/avalanche/detection.cpp +++ b/engines/avalanche/detection.cpp @@ -99,7 +99,8 @@ bool AvalancheMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSupportsDeleteSave) || (f == kSupportsLoadingDuringStartup) || (f == kSavesSupportMetaInfo) || - (f == kSavesSupportThumbnail); + (f == kSavesSupportThumbnail) || + (f == kSimpleSavesNames); } SaveStateList AvalancheMetaEngine::listSaves(const char *target) const { diff --git a/engines/bbvs/detection.cpp b/engines/bbvs/detection.cpp index 7c0045ee73..fa735c9ec3 100644 --- a/engines/bbvs/detection.cpp +++ b/engines/bbvs/detection.cpp @@ -97,7 +97,8 @@ bool BbvsMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSupportsLoadingDuringStartup) || (f == kSavesSupportMetaInfo) || (f == kSavesSupportThumbnail) || - (f == kSavesSupportCreationDate); + (f == kSavesSupportCreationDate) || + (f == kSimpleSavesNames); } void BbvsMetaEngine::removeSaveState(const char *target, int slot) const { diff --git a/engines/cge/detection.cpp b/engines/cge/detection.cpp index 82d27f8d54..0df1e8711e 100644 --- a/engines/cge/detection.cpp +++ b/engines/cge/detection.cpp @@ -180,7 +180,8 @@ bool CGEMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSupportsDeleteSave) || (f == kSavesSupportMetaInfo) || (f == kSavesSupportThumbnail) || - (f == kSavesSupportCreationDate); + (f == kSavesSupportCreationDate) || + (f == kSimpleSavesNames); } void CGEMetaEngine::removeSaveState(const char *target, int slot) const { diff --git a/engines/cge2/detection.cpp b/engines/cge2/detection.cpp index 2b84d167c7..3701baa40f 100644 --- a/engines/cge2/detection.cpp +++ b/engines/cge2/detection.cpp @@ -185,7 +185,8 @@ bool CGE2MetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSavesSupportThumbnail) || (f == kSavesSupportCreationDate) || (f == kSupportsListSaves) || - (f == kSupportsLoadingDuringStartup); + (f == kSupportsLoadingDuringStartup) || + (f == kSimpleSavesNames); } int CGE2MetaEngine::getMaximumSaveSlot() const { diff --git a/engines/drascula/detection.cpp b/engines/drascula/detection.cpp index ffec393a0a..3bc8069b76 100644 --- a/engines/drascula/detection.cpp +++ b/engines/drascula/detection.cpp @@ -339,7 +339,8 @@ bool DrasculaMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSavesSupportMetaInfo) || (f == kSavesSupportThumbnail) || (f == kSavesSupportCreationDate) || - (f == kSavesSupportPlayTime); + (f == kSavesSupportPlayTime) || + (f == kSimpleSavesNames); } const ExtraGuiOptions DrasculaMetaEngine::getExtraGuiOptions(const Common::String &target) const { diff --git a/engines/gnap/detection.cpp b/engines/gnap/detection.cpp index 7e4ab56d1f..d92a037232 100644 --- a/engines/gnap/detection.cpp +++ b/engines/gnap/detection.cpp @@ -89,7 +89,8 @@ bool GnapMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSupportsDeleteSave) || (f == kSavesSupportMetaInfo) || (f == kSavesSupportThumbnail) || - (f == kSavesSupportCreationDate); + (f == kSavesSupportCreationDate) || + (f == kSimpleSavesNames); } bool Gnap::GnapEngine::hasFeature(EngineFeature f) const { diff --git a/engines/hopkins/detection.cpp b/engines/hopkins/detection.cpp index cfdbf8030c..041afecaa8 100644 --- a/engines/hopkins/detection.cpp +++ b/engines/hopkins/detection.cpp @@ -128,7 +128,8 @@ bool HopkinsMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSupportsLoadingDuringStartup) || (f == kSupportsDeleteSave) || (f == kSavesSupportMetaInfo) || - (f == kSavesSupportThumbnail); + (f == kSavesSupportThumbnail) || + (f == kSimpleSavesNames); } bool Hopkins::HopkinsEngine::hasFeature(EngineFeature f) const { diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp index 989a45b420..70c7e7c93c 100644 --- a/engines/kyra/detection.cpp +++ b/engines/kyra/detection.cpp @@ -173,7 +173,8 @@ bool KyraMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSupportsLoadingDuringStartup) || (f == kSupportsDeleteSave) || (f == kSavesSupportMetaInfo) || - (f == kSavesSupportThumbnail); + (f == kSavesSupportThumbnail) || + (f == kSimpleSavesNames); } bool Kyra::KyraEngine_v1::hasFeature(EngineFeature f) const { diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h index c801829855..4de7494510 100644 --- a/engines/kyra/kyra_v1.h +++ b/engines/kyra/kyra_v1.h @@ -38,6 +38,7 @@ #include "kyra/item.h" namespace Common { +class OutSaveFile; class SeekableReadStream; class WriteStream; } // End of namespace Common @@ -423,7 +424,7 @@ protected: virtual Common::Error saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumbnail) = 0; Common::SeekableReadStream *openSaveForReading(const char *filename, SaveHeader &header, bool checkID = true); - Common::WriteStream *openSaveForWriting(const char *filename, const char *saveName, const Graphics::Surface *thumbnail) const; + Common::OutSaveFile *openSaveForWriting(const char *filename, const char *saveName, const Graphics::Surface *thumbnail) const; // TODO: Consider moving this to Screen virtual Graphics::Surface *generateSaveThumbnail() const { return 0; } diff --git a/engines/kyra/saveload.cpp b/engines/kyra/saveload.cpp index 2ae6420bd7..81ea796fe9 100644 --- a/engines/kyra/saveload.cpp +++ b/engines/kyra/saveload.cpp @@ -184,7 +184,7 @@ Common::SeekableReadStream *KyraEngine_v1::openSaveForReading(const char *filena return in; } -Common::WriteStream *KyraEngine_v1::openSaveForWriting(const char *filename, const char *saveName, const Graphics::Surface *thumbnail) const { +Common::OutSaveFile *KyraEngine_v1::openSaveForWriting(const char *filename, const char *saveName, const Graphics::Surface *thumbnail) const { if (shouldQuit()) return 0; @@ -226,7 +226,7 @@ Common::WriteStream *KyraEngine_v1::openSaveForWriting(const char *filename, con delete genThumbnail; } - return out; + return new Common::OutSaveFile(out); } const char *KyraEngine_v1::getSavegameFilename(int num) { diff --git a/engines/kyra/saveload_eob.cpp b/engines/kyra/saveload_eob.cpp index cca8f3a0a4..9329d14255 100644 --- a/engines/kyra/saveload_eob.cpp +++ b/engines/kyra/saveload_eob.cpp @@ -995,7 +995,7 @@ bool EoBCoreEngine::saveAsOriginalSaveFile(int slot) { return false; Common::FSNode nf = nd.getChild(_flags.gameID == GI_EOB1 ? "EOBDATA.SAV" : Common::String::format("EOBDATA%d.SAV", slot)); - Common::WriteStream *out = nf.createWriteStream(); + Common::OutSaveFile *out = new Common::OutSaveFile(nf.createWriteStream()); if (_flags.gameID == GI_EOB2) { static const char tempStr[20] = "SCUMMVM EXPORT "; diff --git a/engines/lab/detection.cpp b/engines/lab/detection.cpp index 30890b5acf..bf6d4563b5 100644 --- a/engines/lab/detection.cpp +++ b/engines/lab/detection.cpp @@ -151,7 +151,8 @@ bool LabMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSavesSupportMetaInfo) || (f == kSavesSupportThumbnail) || (f == kSavesSupportCreationDate) || - (f == kSavesSupportPlayTime); + (f == kSavesSupportPlayTime) || + (f == kSimpleSavesNames); } bool Lab::LabEngine::hasFeature(EngineFeature f) const { diff --git a/engines/mads/detection.cpp b/engines/mads/detection.cpp index 4736503a38..4fb8b82eb3 100644 --- a/engines/mads/detection.cpp +++ b/engines/mads/detection.cpp @@ -166,7 +166,8 @@ bool MADSMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSupportsLoadingDuringStartup) || (f == kSupportsDeleteSave) || (f == kSavesSupportMetaInfo) || - (f == kSavesSupportThumbnail); + (f == kSavesSupportThumbnail) || + (f == kSimpleSavesNames); } bool MADS::MADSEngine::hasFeature(EngineFeature f) const { diff --git a/engines/metaengine.h b/engines/metaengine.h index e7bfebab71..568b66ac51 100644 --- a/engines/metaengine.h +++ b/engines/metaengine.h @@ -236,7 +236,19 @@ public: * the game till the save. * This flag may only be set when 'kSavesSupportMetaInfo' is set. */ - kSavesSupportPlayTime + kSavesSupportPlayTime, + + /** + * Feature is available if engine's saves could be detected + * with "<target>.###" pattern and "###" corresponds to slot + * number. + * + * If that's not true or engine is using some unusual way + * of detecting saves and slot numbers, this should be + * unavailable. In that case Save/Load dialog for engine's + * games is locked during cloud saves sync. + */ + kSimpleSavesNames }; /** diff --git a/engines/mortevielle/detection.cpp b/engines/mortevielle/detection.cpp index 6791707dd5..7bc5339179 100644 --- a/engines/mortevielle/detection.cpp +++ b/engines/mortevielle/detection.cpp @@ -90,6 +90,7 @@ bool MortevielleMetaEngine::hasFeature(MetaEngineFeature f) const { case kSavesSupportMetaInfo: case kSavesSupportThumbnail: case kSavesSupportCreationDate: + case kSimpleSavesNames: return true; default: return false; diff --git a/engines/neverhood/detection.cpp b/engines/neverhood/detection.cpp index 0f409a6435..0c0347ef13 100644 --- a/engines/neverhood/detection.cpp +++ b/engines/neverhood/detection.cpp @@ -228,7 +228,8 @@ bool NeverhoodMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSavesSupportMetaInfo) || (f == kSavesSupportThumbnail) || (f == kSavesSupportCreationDate) || - (f == kSavesSupportPlayTime); + (f == kSavesSupportPlayTime) || + (f == kSimpleSavesNames); } bool Neverhood::NeverhoodEngine::hasFeature(EngineFeature f) const { diff --git a/engines/prince/detection.cpp b/engines/prince/detection.cpp index 1c6f63aff3..ad759823d8 100644 --- a/engines/prince/detection.cpp +++ b/engines/prince/detection.cpp @@ -56,7 +56,8 @@ bool PrinceMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSavesSupportThumbnail) || (f == kSavesSupportCreationDate) || (f == kSupportsListSaves) || - (f == kSupportsLoadingDuringStartup); + (f == kSupportsLoadingDuringStartup) || + (f == kSimpleSavesNames); } bool Prince::PrinceEngine::hasFeature(EngineFeature f) const { diff --git a/engines/saga/detection.cpp b/engines/saga/detection.cpp index 0677e84d67..6fe4277c27 100644 --- a/engines/saga/detection.cpp +++ b/engines/saga/detection.cpp @@ -157,7 +157,8 @@ bool SagaMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSavesSupportMetaInfo) || (f == kSavesSupportThumbnail) || (f == kSavesSupportCreationDate) || - (f == kSavesSupportPlayTime); + (f == kSavesSupportPlayTime) || + (f == kSimpleSavesNames); } bool Saga::SagaEngine::hasFeature(EngineFeature f) const { diff --git a/engines/savestate.cpp b/engines/savestate.cpp index 186d7bc5f2..7366aa6a61 100644 --- a/engines/savestate.cpp +++ b/engines/savestate.cpp @@ -27,12 +27,12 @@ SaveStateDescriptor::SaveStateDescriptor() // FIXME: default to 0 (first slot) or to -1 (invalid slot) ? : _slot(-1), _description(), _isDeletable(true), _isWriteProtected(false), - _saveDate(), _saveTime(), _playTime(), _thumbnail() { + _isLocked(false), _saveDate(), _saveTime(), _playTime(), _thumbnail() { } SaveStateDescriptor::SaveStateDescriptor(int s, const Common::String &d) : _slot(s), _description(d), _isDeletable(true), _isWriteProtected(false), - _saveDate(), _saveTime(), _playTime(), _thumbnail() { + _isLocked(false), _saveDate(), _saveTime(), _playTime(), _thumbnail() { } void SaveStateDescriptor::setThumbnail(Graphics::Surface *t) { diff --git a/engines/savestate.h b/engines/savestate.h index 21ade602fa..3244d61fdb 100644 --- a/engines/savestate.h +++ b/engines/savestate.h @@ -90,6 +90,24 @@ public: bool getWriteProtectedFlag() const { return _isWriteProtected; } /** + * Defines whether the save state is "locked" because is being synced. + */ + void setLocked(bool state) { + _isLocked = state; + + //just in case: + if (state) { + setDeletableFlag(false); + setWriteProtectedFlag(true); + } + } + + /** + * Queries whether the save state is "locked" because is being synced. + */ + bool getLocked() const { return _isLocked; } + + /** * Return a thumbnail graphics surface representing the savestate visually. * This is usually a scaled down version of the game graphics. The size * should be either 160x100 or 160x120 pixels, depending on the aspect @@ -180,6 +198,11 @@ private: bool _isWriteProtected; /** + * Whether the save state is "locked" because is being synced. + */ + bool _isLocked; + + /** * Human readable description of the date the save state was created. */ Common::String _saveDate; diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp index 4c9d1221aa..e6740df482 100644 --- a/engines/scumm/detection.cpp +++ b/engines/scumm/detection.cpp @@ -974,7 +974,8 @@ bool ScummMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSavesSupportMetaInfo) || (f == kSavesSupportThumbnail) || (f == kSavesSupportCreationDate) || - (f == kSavesSupportPlayTime); + (f == kSavesSupportPlayTime) || + (f == kSimpleSavesNames); } bool ScummEngine::hasFeature(EngineFeature f) const { diff --git a/engines/sherlock/detection.cpp b/engines/sherlock/detection.cpp index 5a94b3485f..c6e632f999 100644 --- a/engines/sherlock/detection.cpp +++ b/engines/sherlock/detection.cpp @@ -199,7 +199,8 @@ bool SherlockMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSupportsLoadingDuringStartup) || (f == kSupportsDeleteSave) || (f == kSavesSupportMetaInfo) || - (f == kSavesSupportThumbnail); + (f == kSavesSupportThumbnail) || + (f == kSimpleSavesNames); } bool Sherlock::SherlockEngine::hasFeature(EngineFeature f) const { diff --git a/engines/sky/detection.cpp b/engines/sky/detection.cpp index 4b91f50a61..d86689e5d7 100644 --- a/engines/sky/detection.cpp +++ b/engines/sky/detection.cpp @@ -78,7 +78,7 @@ public: virtual bool hasFeature(MetaEngineFeature f) const; virtual GameList getSupportedGames() const; virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const; - virtual GameDescriptor findGame(const char *gameid) const; + virtual GameDescriptor findGame(const char *gameid) const; virtual GameList detectGames(const Common::FSList &fslist) const; virtual Common::Error createInstance(OSystem *syst, Engine **engine) const; diff --git a/engines/sword2/sword2.cpp b/engines/sword2/sword2.cpp index 44371bf6cf..4f3caa437e 100644 --- a/engines/sword2/sword2.cpp +++ b/engines/sword2/sword2.cpp @@ -107,7 +107,8 @@ bool Sword2MetaEngine::hasFeature(MetaEngineFeature f) const { return (f == kSupportsListSaves) || (f == kSupportsLoadingDuringStartup) || - (f == kSupportsDeleteSave); + (f == kSupportsDeleteSave) || + (f == kSimpleSavesNames); } bool Sword2::Sword2Engine::hasFeature(EngineFeature f) const { diff --git a/engines/testbed/cloud.cpp b/engines/testbed/cloud.cpp new file mode 100644 index 0000000000..a2d62733be --- /dev/null +++ b/engines/testbed/cloud.cpp @@ -0,0 +1,565 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#include "common/config-manager.h" +#include "common/stream.h" +#include "common/util.h" +#include "testbed/fs.h" +#include "testbed/cloud.h" +#include <backends/cloud/cloudmanager.h> + +namespace Testbed { + +CloudTestSuite::CloudTestSuite() { + // Cloud tests depend on CloudMan. + // If there is no Storage connected to it, disable this test suite. + if (CloudMan.getCurrentStorage() == nullptr) { + logPrintf("WARNING! : No Storage connected to CloudMan found. Skipping Cloud tests\n"); + Testsuite::enable(false); + } + + addTest("UserInfo", &CloudTests::testInfo, true); + addTest("ListDirectory", &CloudTests::testDirectoryListing, true); + addTest("CreateDirectory", &CloudTests::testDirectoryCreating, true); + addTest("FileUpload", &CloudTests::testUploading, true); + addTest("FileDownload", &CloudTests::testDownloading, true); + addTest("FolderDownload", &CloudTests::testFolderDownloading, true); + addTest("SyncSaves", &CloudTests::testSavesSync, true); +} + +/* +void CloudTestSuite::enable(bool flag) { + Testsuite::enable(ConfParams.isGameDataFound() ? flag : false); +} +*/ + +///// TESTS GO HERE ///// + +bool CloudTests::waitForCallback() { + const int TIMEOUT = 30; + + Common::Point pt; + pt.x = 10; pt.y = 10; + Testsuite::writeOnScreen("Waiting for callback...", pt); + + int left = TIMEOUT; + while (--left) { + if (ConfParams.isCloudTestCallbackCalled()) return true; + if (ConfParams.isCloudTestErrorCallbackCalled()) return true; + g_system->delayMillis(1000); + } + return false; +} + +bool CloudTests::waitForCallbackMore() { + while (!waitForCallback()) { + Common::String info = "It takes more time than expected. Do you want to skip the test or wait more?"; + if (Testsuite::handleInteractiveInput(info, "Wait", "Skip", kOptionRight)) { + Testsuite::logPrintf("Info! Skipping test : info()\n"); + return false; + } + } + return true; +} + +const char *CloudTests::getRemoteTestPath() { + if (CloudMan.getStorageIndex() == Cloud::kStorageDropboxId) + return "/testbed"; + return "testbed"; +} + +void CloudTests::infoCallback(Cloud::Storage::StorageInfoResponse response) { + ConfParams.setCloudTestCallbackCalled(true); + Testsuite::logPrintf("Info! User's ID: %s\n", response.value.uid().c_str()); + Testsuite::logPrintf("Info! User's email: %s\n", response.value.email().c_str()); + Testsuite::logPrintf("Info! User's name: %s\n", response.value.name().c_str()); + Testsuite::logPrintf("Info! User's quota: %lu bytes used / %lu bytes available\n", response.value.used(), response.value.available()); +} + +void CloudTests::directoryListedCallback(Cloud::Storage::FileArrayResponse response) { + ConfParams.setCloudTestCallbackCalled(true); + if (response.value.size() == 0) { + Testsuite::logPrintf("Warning! Directory is empty!\n"); + return; + } + + Common::String directory, file; + uint32 directories = 0, files = 0; + for (uint32 i = 0; i < response.value.size(); ++i) { + if (response.value[i].isDirectory()) { + if (++directories == 1) directory = response.value[i].path(); + } else { + if (++files == 1) file = response.value[i].name(); + } + } + + if (directories == 0) { + Testsuite::logPrintf("Info! %u files listed, first one is '%s'\n", files, file.c_str()); + } else if (files == 0) { + Testsuite::logPrintf("Info! %u directories listed, first one is '%s'\n", directories, directory.c_str()); + } else { + Testsuite::logPrintf("Info! %u directories and %u files listed\n", directories, files); + Testsuite::logPrintf("Info! First directory is '%s' and first file is '%s'\n", directory.c_str(), file.c_str()); + } +} + +void CloudTests::directoryCreatedCallback(Cloud::Storage::BoolResponse response) { + ConfParams.setCloudTestCallbackCalled(true); + if (response.value) { + Testsuite::logPrintf("Info! Directory created!\n"); + } else { + Testsuite::logPrintf("Info! Such directory already exists!\n"); + } +} + +void CloudTests::fileUploadedCallback(Cloud::Storage::UploadResponse response) { + ConfParams.setCloudTestCallbackCalled(true); + Testsuite::logPrintf("Info! Uploaded file into '%s'\n", response.value.path().c_str()); + Testsuite::logPrintf("Info! It's id = '%s' and size = '%u'\n", response.value.id().c_str(), response.value.size()); +} + +void CloudTests::fileDownloadedCallback(Cloud::Storage::BoolResponse response) { + ConfParams.setCloudTestCallbackCalled(true); + if (response.value) { + Testsuite::logPrintf("Info! File downloaded!\n"); + } else { + Testsuite::logPrintf("Info! Failed to download the file!\n"); + } +} + +void CloudTests::directoryDownloadedCallback(Cloud::Storage::FileArrayResponse response) { + ConfParams.setCloudTestCallbackCalled(true); + if (response.value.size() == 0) { + Testsuite::logPrintf("Info! Directory is downloaded successfully!\n"); + } else { + Testsuite::logPrintf("Warning! %u files were not downloaded during folder downloading!\n", response.value.size()); + } +} + +void CloudTests::savesSyncedCallback(Cloud::Storage::BoolResponse response) { + ConfParams.setCloudTestCallbackCalled(true); + if (response.value) { + Testsuite::logPrintf("Info! Saves are synced successfully!\n"); + } else { + Testsuite::logPrintf("Warning! Saves were not synced!\n"); + } +} + +void CloudTests::errorCallback(Networking::ErrorResponse response) { + ConfParams.setCloudTestErrorCallbackCalled(true); + Testsuite::logPrintf("Info! Error Callback was called\n"); + Testsuite::logPrintf("Info! code = %ld, message = %s\n", response.httpResponseCode, response.response.c_str()); +} + +/** This test calls Storage::info(). */ + +TestExitStatus CloudTests::testInfo() { + ConfParams.setCloudTestCallbackCalled(false); + ConfParams.setCloudTestErrorCallbackCalled(false); + + if (CloudMan.getCurrentStorage() == nullptr) { + Testsuite::logPrintf("Couldn't find connected Storage\n"); + return kTestFailed; + } + + Common::String info = Common::String::format( + "Welcome to the Cloud test suite!\n" + "We're going to use the %s cloud storage which is connected right now.\n\n" + "Testing Cloud Storage API info() method.\n" + "In this test we'll try to list user infomation.", + CloudMan.getCurrentStorage()->name().c_str() + ); + + if (Testsuite::handleInteractiveInput(info, "OK", "Skip", kOptionRight)) { + Testsuite::logPrintf("Info! Skipping test : info()\n"); + return kTestSkipped; + } + + if (CloudMan.info( + new Common::GlobalFunctionCallback<Cloud::Storage::StorageInfoResponse>(&infoCallback), + new Common::GlobalFunctionCallback<Networking::ErrorResponse>(&errorCallback) + ) == nullptr) { + Testsuite::logPrintf("Warning! No Request is returned!\n"); + } + + if (!waitForCallbackMore()) return kTestSkipped; + Testsuite::clearScreen(); + + if (ConfParams.isCloudTestErrorCallbackCalled()) { + Testsuite::logPrintf("Error callback was called\n"); + return kTestFailed; + } + + Testsuite::logDetailedPrintf("Info was displayed\n"); + return kTestPassed; +} + +TestExitStatus CloudTests::testDirectoryListing() { + ConfParams.setCloudTestCallbackCalled(false); + ConfParams.setCloudTestErrorCallbackCalled(false); + + if (CloudMan.getCurrentStorage() == nullptr) { + Testsuite::logPrintf("Couldn't find connected Storage\n"); + return kTestFailed; + } + + Common::String info = "Testing Cloud Storage API listDirectory() method.\n" + "In this test we'll try to list root directory."; + + if (Testsuite::handleInteractiveInput(info, "OK", "Skip", kOptionRight)) { + Testsuite::logPrintf("Info! Skipping test : listDirectory()\n"); + return kTestSkipped; + } + + if (CloudMan.listDirectory( + "", + new Common::GlobalFunctionCallback<Cloud::Storage::FileArrayResponse>(&directoryListedCallback), + new Common::GlobalFunctionCallback<Networking::ErrorResponse>(&errorCallback) + ) == nullptr) { + Testsuite::logPrintf("Warning! No Request is returned!\n"); + } + + if (!waitForCallbackMore()) return kTestSkipped; + Testsuite::clearScreen(); + + if (ConfParams.isCloudTestErrorCallbackCalled()) { + Testsuite::logPrintf("Error callback was called\n"); + return kTestFailed; + } + + Testsuite::logDetailedPrintf("Directory was listed\n"); + return kTestPassed; +} + +TestExitStatus CloudTests::testDirectoryCreating() { + ConfParams.setCloudTestCallbackCalled(false); + ConfParams.setCloudTestErrorCallbackCalled(false); + + if (CloudMan.getCurrentStorage() == nullptr) { + Testsuite::logPrintf("Couldn't find connected Storage\n"); + return kTestFailed; + } + + Common::String info = "Testing Cloud Storage API createDirectory() method.\n" + "In this test we'll try to create a 'testbed' directory."; + + if (Testsuite::handleInteractiveInput(info, "OK", "Skip", kOptionRight)) { + Testsuite::logPrintf("Info! Skipping test : createDirectory()\n"); + return kTestSkipped; + } + + Common::String info2 = "We'd list the root directory, create the directory and the list it again.\n" + "If all goes smoothly, you'd notice that there are more directories now."; + Testsuite::displayMessage(info2); + + // list root directory + if (CloudMan.listDirectory( + "", + new Common::GlobalFunctionCallback<Cloud::Storage::FileArrayResponse>(&directoryListedCallback), + new Common::GlobalFunctionCallback<Networking::ErrorResponse>(&errorCallback) + ) == nullptr) { + Testsuite::logPrintf("Warning! No Request is returned!\n"); + } + + if (!waitForCallbackMore()) return kTestSkipped; + Testsuite::clearScreen(); + + if (ConfParams.isCloudTestErrorCallbackCalled()) { + Testsuite::logPrintf("Error callback was called\n"); + return kTestFailed; + } + + ConfParams.setCloudTestCallbackCalled(false); + + // create 'testbed' + if (CloudMan.getCurrentStorage()->createDirectory( + getRemoteTestPath(), + new Common::GlobalFunctionCallback<Cloud::Storage::BoolResponse>(&directoryCreatedCallback), + new Common::GlobalFunctionCallback<Networking::ErrorResponse>(&errorCallback) + ) == nullptr) { + Testsuite::logPrintf("Warning! No Request is returned!\n"); + } + + if (!waitForCallbackMore()) return kTestSkipped; + Testsuite::clearScreen(); + + if (ConfParams.isCloudTestErrorCallbackCalled()) { + Testsuite::logPrintf("Error callback was called\n"); + return kTestFailed; + } + + ConfParams.setCloudTestCallbackCalled(false); + + // list it again + if (CloudMan.listDirectory( + "", + new Common::GlobalFunctionCallback<Cloud::Storage::FileArrayResponse>(&directoryListedCallback), + new Common::GlobalFunctionCallback<Networking::ErrorResponse>(&errorCallback) + ) == nullptr) { + Testsuite::logPrintf("Warning! No Request is returned!\n"); + } + + if (!waitForCallbackMore()) return kTestSkipped; + Testsuite::clearScreen(); + + if (ConfParams.isCloudTestErrorCallbackCalled()) { + Testsuite::logPrintf("Error callback was called\n"); + return kTestFailed; + } + + if (Testsuite::handleInteractiveInput("Was the CloudMan able to create a 'testbed' directory?", "Yes", "No", kOptionRight)) { + Testsuite::logDetailedPrintf("Error! Directory was not created!\n"); + return kTestFailed; + } + + Testsuite::logDetailedPrintf("Directory was created\n"); + return kTestPassed; +} + +TestExitStatus CloudTests::testUploading() { + ConfParams.setCloudTestCallbackCalled(false); + ConfParams.setCloudTestErrorCallbackCalled(false); + + if (CloudMan.getCurrentStorage() == nullptr) { + Testsuite::logPrintf("Couldn't find connected Storage\n"); + return kTestFailed; + } + + Common::String info = "Testing Cloud Storage API upload() method.\n" + "In this test we'll try to upload a 'test1/file.txt' file."; + + if (Testsuite::handleInteractiveInput(info, "OK", "Skip", kOptionRight)) { + Testsuite::logPrintf("Info! Skipping test : upload()\n"); + return kTestSkipped; + } + + if (!ConfParams.isGameDataFound()) { + Testsuite::logPrintf("Info! Couldn't find the game data, so skipping test : upload()\n"); + return kTestSkipped; + } + + const Common::String &path = ConfMan.get("path"); + Common::FSDirectory gameRoot(path); + Common::FSDirectory *directory = gameRoot.getSubDirectory("test1"); + Common::FSNode node = directory->getFSNode().getChild("file.txt"); + delete directory; + + if (CloudMan.getCurrentStorage()->uploadStreamSupported()) { + if (CloudMan.getCurrentStorage()->upload( + Common::String(getRemoteTestPath()) + "/testfile.txt", + node.createReadStream(), + new Common::GlobalFunctionCallback<Cloud::Storage::UploadResponse>(&fileUploadedCallback), + new Common::GlobalFunctionCallback<Networking::ErrorResponse>(&errorCallback) + ) == nullptr) { + Testsuite::logPrintf("Warning! No Request is returned!\n"); + } + } else { + Common::String filepath = node.getPath(); + if (CloudMan.getCurrentStorage()->upload( + Common::String(getRemoteTestPath()) + "/testfile.txt", + filepath.c_str(), + new Common::GlobalFunctionCallback<Cloud::Storage::UploadResponse>(&fileUploadedCallback), + new Common::GlobalFunctionCallback<Networking::ErrorResponse>(&errorCallback) + ) == nullptr) { + Testsuite::logPrintf("Warning! No Request is returned!\n"); + } + } + + if (!waitForCallbackMore()) return kTestSkipped; + Testsuite::clearScreen(); + + if (ConfParams.isCloudTestErrorCallbackCalled()) { + Testsuite::logPrintf("Error callback was called\n"); + return kTestFailed; + } + + Common::String info2 = "upload() is finished. Do you want to list '/testbed' directory?"; + + if (!Testsuite::handleInteractiveInput(info2, "Yes", "No", kOptionRight)) { + ConfParams.setCloudTestCallbackCalled(false); + + if (CloudMan.listDirectory( + getRemoteTestPath(), + new Common::GlobalFunctionCallback<Cloud::Storage::FileArrayResponse>(&directoryListedCallback), + new Common::GlobalFunctionCallback<Networking::ErrorResponse>(&errorCallback) + ) == nullptr) { + Testsuite::logPrintf("Warning! No Request is returned!\n"); + } + + if (!waitForCallbackMore()) return kTestSkipped; + Testsuite::clearScreen(); + + if (ConfParams.isCloudTestErrorCallbackCalled()) { + Testsuite::logPrintf("Error callback was called\n"); + return kTestFailed; + } + } + + if (Testsuite::handleInteractiveInput("Was the CloudMan able to upload into 'testbed/testfile.txt' file?", "Yes", "No", kOptionRight)) { + Testsuite::logDetailedPrintf("Error! File was not uploaded!\n"); + return kTestFailed; + } + + Testsuite::logDetailedPrintf("File was uploaded\n"); + return kTestPassed; +} + +TestExitStatus CloudTests::testDownloading() { + ConfParams.setCloudTestCallbackCalled(false); + ConfParams.setCloudTestErrorCallbackCalled(false); + + if (CloudMan.getCurrentStorage() == nullptr) { + Testsuite::logPrintf("Couldn't find connected Storage\n"); + return kTestFailed; + } + + Common::String info = "Testing Cloud Storage API download() method.\n" + "In this test we'll try to download that 'testbed/testfile.txt' file."; + + if (Testsuite::handleInteractiveInput(info, "OK", "Skip", kOptionRight)) { + Testsuite::logPrintf("Info! Skipping test : download()\n"); + return kTestSkipped; + } + + const Common::String &path = ConfMan.get("path"); + Common::FSDirectory gameRoot(path); + Common::FSNode node = gameRoot.getFSNode().getChild("downloaded_file.txt"); + Common::String filepath = node.getPath(); + if (CloudMan.getCurrentStorage()->download( + Common::String(getRemoteTestPath()) + "/testfile.txt", + filepath.c_str(), + new Common::GlobalFunctionCallback<Cloud::Storage::BoolResponse>(&fileDownloadedCallback), + new Common::GlobalFunctionCallback<Networking::ErrorResponse>(&errorCallback) + ) == nullptr) { + Testsuite::logPrintf("Warning! No Request is returned!\n"); + } + + if (!waitForCallbackMore()) return kTestSkipped; + Testsuite::clearScreen(); + + if (ConfParams.isCloudTestErrorCallbackCalled()) { + Testsuite::logPrintf("Error callback was called\n"); + return kTestFailed; + } + + if (Testsuite::handleInteractiveInput("Was the CloudMan able to download into 'testbed/downloaded_file.txt' file?", "Yes", "No", kOptionRight)) { + Testsuite::logDetailedPrintf("Error! File was not downloaded!\n"); + return kTestFailed; + } + + Testsuite::logDetailedPrintf("File was downloaded\n"); + return kTestPassed; +} + +TestExitStatus CloudTests::testFolderDownloading() { + ConfParams.setCloudTestCallbackCalled(false); + ConfParams.setCloudTestErrorCallbackCalled(false); + + if (CloudMan.getCurrentStorage() == nullptr) { + Testsuite::logPrintf("Couldn't find connected Storage\n"); + return kTestFailed; + } + + Common::String info = "Testing Cloud Storage API downloadFolder() method.\n" + "In this test we'll try to download remote 'testbed/' directory."; + + if (Testsuite::handleInteractiveInput(info, "OK", "Skip", kOptionRight)) { + Testsuite::logPrintf("Info! Skipping test : downloadFolder()\n"); + return kTestSkipped; + } + + const Common::String &path = ConfMan.get("path"); + Common::FSDirectory gameRoot(path); + Common::FSNode node = gameRoot.getFSNode().getChild("downloaded_directory"); + Common::String filepath = node.getPath(); + if (CloudMan.downloadFolder( + getRemoteTestPath(), + filepath.c_str(), + new Common::GlobalFunctionCallback<Cloud::Storage::FileArrayResponse>(&directoryDownloadedCallback), + new Common::GlobalFunctionCallback<Networking::ErrorResponse>(&errorCallback) + ) == nullptr) { + Testsuite::logPrintf("Warning! No Request is returned!\n"); + } + + if (!waitForCallbackMore()) return kTestSkipped; + Testsuite::clearScreen(); + + if (ConfParams.isCloudTestErrorCallbackCalled()) { + Testsuite::logPrintf("Error callback was called\n"); + return kTestFailed; + } + + if (Testsuite::handleInteractiveInput("Was the CloudMan able to download into 'testbed/downloaded_directory'?", "Yes", "No", kOptionRight)) { + Testsuite::logDetailedPrintf("Error! Directory was not downloaded!\n"); + return kTestFailed; + } + + Testsuite::logDetailedPrintf("Directory was downloaded\n"); + return kTestPassed; +} + +TestExitStatus CloudTests::testSavesSync() { + ConfParams.setCloudTestCallbackCalled(false); + ConfParams.setCloudTestErrorCallbackCalled(false); + + if (CloudMan.getCurrentStorage() == nullptr) { + Testsuite::logPrintf("Couldn't find connected Storage\n"); + return kTestFailed; + } + + Common::String info = "Testing Cloud Storage API syncSaves() method.\n" + "In this test we'll try to sync your saves."; + + if (Testsuite::handleInteractiveInput(info, "OK", "Skip", kOptionRight)) { + Testsuite::logPrintf("Info! Skipping test : syncSaves()\n"); + return kTestSkipped; + } + + const Common::String &path = ConfMan.get("path"); + Common::FSDirectory gameRoot(path); + Common::FSNode node = gameRoot.getFSNode().getChild("downloaded_directory"); + Common::String filepath = node.getPath(); + if (CloudMan.syncSaves( + new Common::GlobalFunctionCallback<Cloud::Storage::BoolResponse>(&savesSyncedCallback), + new Common::GlobalFunctionCallback<Networking::ErrorResponse>(&errorCallback) + ) == nullptr) { + Testsuite::logPrintf("Warning! No Request is returned!\n"); + } + + if (!waitForCallbackMore()) return kTestSkipped; + Testsuite::clearScreen(); + + if (ConfParams.isCloudTestErrorCallbackCalled()) { + Testsuite::logPrintf("Error callback was called\n"); + return kTestFailed; + } + + if (Testsuite::handleInteractiveInput("Was the CloudMan able to sync saves?", "Yes", "No", kOptionRight)) { + Testsuite::logDetailedPrintf("Error! Saves were not synced!\n"); + return kTestFailed; + } + + Testsuite::logDetailedPrintf("Saves were synced successfully\n"); + return kTestPassed; +} + +} // End of namespace Testbed diff --git a/engines/testbed/cloud.h b/engines/testbed/cloud.h new file mode 100644 index 0000000000..ed27d7da82 --- /dev/null +++ b/engines/testbed/cloud.h @@ -0,0 +1,83 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef TESTBED_CLOUD_H +#define TESTBED_CLOUD_H + +#include "testbed/testsuite.h" +#include <backends/cloud/storage.h> + +// This file can be used as template for header files of other newer testsuites. + +namespace Testbed { + +namespace CloudTests { + +// Helper functions for Cloud tests + +bool waitForCallback(); +bool waitForCallbackMore(); +const char *getRemoteTestPath(); +void infoCallback(Cloud::Storage::StorageInfoResponse response); +void directoryListedCallback(Cloud::Storage::FileArrayResponse response); +void directoryCreatedCallback(Cloud::Storage::BoolResponse response); +void fileUploadedCallback(Cloud::Storage::UploadResponse response); +void fileDownloadedCallback(Cloud::Storage::BoolResponse response); +void directoryDownloadedCallback(Cloud::Storage::FileArrayResponse response); +void savesSyncedCallback(Cloud::Storage::BoolResponse response); +void errorCallback(Networking::ErrorResponse response); + +TestExitStatus testInfo(); +TestExitStatus testDirectoryListing(); +TestExitStatus testDirectoryCreating(); +TestExitStatus testUploading(); +TestExitStatus testDownloading(); +TestExitStatus testFolderDownloading(); +TestExitStatus testSavesSync(); + +} // End of namespace CloudTests + +class CloudTestSuite : public Testsuite { +public: + /** + * The constructor for the CloudTestSuite + * 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() + */ + CloudTestSuite(); + ~CloudTestSuite() {} + const char *getName() const { + return "Cloud"; + } + + const char *getDescription() const { + return "CloudMan, Storage API tests"; + } + +}; + +} // End of namespace Testbed + +#endif // TESTBED_TEMPLATE_H diff --git a/engines/testbed/config-params.h b/engines/testbed/config-params.h index 89aae199b6..57fd099bf4 100644 --- a/engines/testbed/config-params.h +++ b/engines/testbed/config-params.h @@ -54,6 +54,10 @@ private: */ bool _isInteractive; bool _isGameDataFound; +#ifdef USE_LIBCURL + bool _isCloudTestCallbackCalled; + bool _isCloudTestErrorCallbackCalled; +#endif bool _rerunTests; TestbedConfigManager *_testbedConfMan; @@ -68,6 +72,14 @@ public: bool isGameDataFound() { return _isGameDataFound; } void setGameDataFound(bool status) { _isGameDataFound = status; } +#ifdef USE_LIBCURL + bool isCloudTestCallbackCalled() const { return _isCloudTestCallbackCalled; } + void setCloudTestCallbackCalled(bool status) { _isCloudTestCallbackCalled = status; } + + bool isCloudTestErrorCallbackCalled() const { return _isCloudTestErrorCallbackCalled; } + void setCloudTestErrorCallbackCalled(bool status) { _isCloudTestErrorCallbackCalled = status; } +#endif + TestbedConfigManager *getTestbedConfigManager() { return _testbedConfMan; } void setTestbedConfigManager(TestbedConfigManager* confMan) { _testbedConfMan = confMan; } diff --git a/engines/testbed/misc.cpp b/engines/testbed/misc.cpp index 5847a8d2e4..20651e76e6 100644 --- a/engines/testbed/misc.cpp +++ b/engines/testbed/misc.cpp @@ -22,6 +22,7 @@ #include "testbed/misc.h" #include "common/timer.h" +#include <backends/networking/browser/openurl.h> namespace Testbed { @@ -160,10 +161,34 @@ TestExitStatus MiscTests::testMutexes() { return kTestFailed; } +TestExitStatus MiscTests::testOpenUrl() { + Common::String info = "Testing openUrl() method.\n" + "In this test we'll try to open scummvm.org in your default browser."; + + if (Testsuite::handleInteractiveInput(info, "OK", "Skip", kOptionRight)) { + Testsuite::logPrintf("Info! Skipping test : openUrl()\n"); + return kTestSkipped; + } + + if (!Networking::Browser::openUrl("http://scummvm.org/")) { + Testsuite::logPrintf("Info! openUrl() says it couldn't open the url (probably not supported on this platform)\n"); + return kTestFailed; + } + + if (Testsuite::handleInteractiveInput("Was ScummVM able to open 'http://scummvm.org/' in your default browser?", "Yes", "No", kOptionRight)) { + Testsuite::logDetailedPrintf("Error! openUrl() is not working!\n"); + return kTestFailed; + } + + Testsuite::logDetailedPrintf("openUrl() is OK\n"); + return kTestPassed; +} + MiscTestSuite::MiscTestSuite() { addTest("Datetime", &MiscTests::testDateTime, false); addTest("Timers", &MiscTests::testTimers, false); addTest("Mutexes", &MiscTests::testMutexes, false); + addTest("openUrl", &MiscTests::testOpenUrl, true); } } // End of namespace Testbed diff --git a/engines/testbed/misc.h b/engines/testbed/misc.h index 23e303d676..adfc322d9f 100644 --- a/engines/testbed/misc.h +++ b/engines/testbed/misc.h @@ -49,6 +49,7 @@ void criticalSection(void *arg); TestExitStatus testDateTime(); TestExitStatus testTimers(); TestExitStatus testMutexes(); +TestExitStatus testOpenUrl(); // add more here } // End of namespace MiscTests @@ -69,7 +70,7 @@ public: return "Misc"; } const char *getDescription() const { - return "Miscellaneous: Timers/Mutexes/Datetime"; + return "Miscellaneous: Timers/Mutexes/Datetime/openUrl"; } }; diff --git a/engines/testbed/module.mk b/engines/testbed/module.mk index ce78a48bc5..99e6157cde 100644 --- a/engines/testbed/module.mk +++ b/engines/testbed/module.mk @@ -14,6 +14,16 @@ MODULE_OBJS := \ testbed.o \ testsuite.o +ifdef USE_LIBCURL +MODULE_OBJS += \ + cloud.o +endif + +ifdef USE_SDL_NET +MODULE_OBJS += \ + webserver.o +endif + MODULE_DIRS += \ engines/testbed diff --git a/engines/testbed/testbed.cpp b/engines/testbed/testbed.cpp index 885429cafd..5943d47c58 100644 --- a/engines/testbed/testbed.cpp +++ b/engines/testbed/testbed.cpp @@ -39,6 +39,12 @@ #include "testbed/savegame.h" #include "testbed/sound.h" #include "testbed/testbed.h" +#ifdef USE_LIBCURL +#include "testbed/cloud.h" +#endif +#ifdef USE_SDL_NET +#include "testbed/webserver.h" +#endif namespace Testbed { @@ -134,6 +140,16 @@ TestbedEngine::TestbedEngine(OSystem *syst) // Midi ts = new MidiTestSuite(); _testsuiteList.push_back(ts); +#ifdef USE_LIBCURL + // Cloud + ts = new CloudTestSuite(); + _testsuiteList.push_back(ts); +#endif +#ifdef USE_SDL_NET + // Webserver + ts = new WebserverTestSuite(); + _testsuiteList.push_back(ts); +#endif } TestbedEngine::~TestbedEngine() { diff --git a/engines/testbed/webserver.cpp b/engines/testbed/webserver.cpp new file mode 100644 index 0000000000..feb2911704 --- /dev/null +++ b/engines/testbed/webserver.cpp @@ -0,0 +1,237 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#include "testbed/webserver.h" +#include "backends/networking/sdl_net/localwebserver.h" +#include "common/config-manager.h" +#include <backends/networking/browser/openurl.h> + +namespace Testbed { + +WebserverTestSuite::WebserverTestSuite() { + addTest("ResolveIP", &WebserverTests::testIP, true); + addTest("IndexPage", &WebserverTests::testIndexPage, true); + addTest("FilesPage", &WebserverTests::testFilesPageInvalidParameterValue, true); + addTest("CreateDirectory", &WebserverTests::testFilesPageCreateDirectory, true); + addTest("UploadFile", &WebserverTests::testFilesPageUploadFile, true); + addTest("UploadDirectory", &WebserverTests::testFilesPageUploadDirectory, true); + addTest("DownloadFile", &WebserverTests::testFilesPageDownloadFile, true); +} + +///// TESTS GO HERE ///// + +/** This test calls Storage::info(). */ + +bool WebserverTests::startServer() { + Common::Point pt; + pt.x = 10; pt.y = 10; + Testsuite::writeOnScreen("Starting webserver...", pt); + LocalServer.start(); + g_system->delayMillis(500); + Testsuite::clearScreen(); + return LocalServer.isRunning(); +} + +TestExitStatus WebserverTests::testIP() { + if (!startServer()) { + Testsuite::logPrintf("Error! Can't start local webserver!\n"); + return kTestFailed; + } + + Common::String info = "Welcome to the Webserver test suite!\n" + "You would be visiting different server's pages and saying whether they work like they should.\n\n" + "Testing Webserver's IP resolving.\n" + "In this test we'll try to resolve server's IP."; + + if (Testsuite::handleInteractiveInput(info, "OK", "Skip", kOptionRight)) { + Testsuite::logPrintf("Info! Skipping test : IP resolving\n"); + return kTestSkipped; + } + + if (Testsuite::handleInteractiveInput( + Common::String::format("Is this your machine's IP?\n%s", LocalServer.getAddress().c_str()), + "Yes", "No", kOptionRight)) { + Testsuite::logDetailedPrintf("Error! IP was not resolved!\n"); + return kTestFailed; + } + + Testsuite::logDetailedPrintf("IP was resolved\n"); + return kTestPassed; +} + +TestExitStatus WebserverTests::testIndexPage() { + if (!startServer()) { + Testsuite::logPrintf("Error! Can't start local webserver!\n"); + return kTestFailed; + } + + Common::String info = "Testing Webserver's index page.\n" + "In this test we'll try to open server's index page."; + + if (Testsuite::handleInteractiveInput(info, "OK", "Skip", kOptionRight)) { + Testsuite::logPrintf("Info! Skipping test : index page\n"); + return kTestSkipped; + } + + Networking::Browser::openUrl(LocalServer.getAddress()); + if (Testsuite::handleInteractiveInput( + Common::String::format("The %s page opens well?", LocalServer.getAddress().c_str()), + "Yes", "No", kOptionRight)) { + Testsuite::logDetailedPrintf("Error! Couldn't open server's index page!\n"); + return kTestFailed; + } + + Testsuite::logDetailedPrintf("Server's index page is OK\n"); + return kTestPassed; +} + +TestExitStatus WebserverTests::testFilesPageInvalidParameterValue() { + if (!startServer()) { + Testsuite::logPrintf("Error! Can't start local webserver!\n"); + return kTestFailed; + } + + Common::String info = "Testing Webserver's files page.\n" + "In this test we'll try to pass invalid parameter to files page."; + + if (Testsuite::handleInteractiveInput(info, "OK", "Skip", kOptionRight)) { + Testsuite::logPrintf("Info! Skipping test : files page (invalid parameter)\n"); + return kTestSkipped; + } + + Networking::Browser::openUrl(LocalServer.getAddress()+"files?path=error"); + if (Testsuite::handleInteractiveInput( + Common::String::format("The %sfiles?path=error page displays error message?", LocalServer.getAddress().c_str()), + "Yes", "No", kOptionRight)) { + Testsuite::logDetailedPrintf("Error! No error message on invalid parameter in '/files'!\n"); + return kTestFailed; + } + + Testsuite::logDetailedPrintf("Server's files page detects invalid paramters fine\n"); + return kTestPassed; +} + +TestExitStatus WebserverTests::testFilesPageCreateDirectory() { + if (!startServer()) { + Testsuite::logPrintf("Error! Can't start local webserver!\n"); + return kTestFailed; + } + + Common::String info = "Testing Webserver's files page Create Directory feature.\n" + "In this test you'll try to create directory."; + + if (Testsuite::handleInteractiveInput(info, "OK", "Skip", kOptionRight)) { + Testsuite::logPrintf("Info! Skipping test : files page create directory\n"); + return kTestSkipped; + } + + Networking::Browser::openUrl(LocalServer.getAddress() + "files?path=/root/"); + if (Testsuite::handleInteractiveInput( + Common::String::format("You could go to %sfiles page, navigate to some directory with write access and create a directory there?", LocalServer.getAddress().c_str()), + "Yes", "No", kOptionRight)) { + Testsuite::logDetailedPrintf("Error! Create Directory is not working!\n"); + return kTestFailed; + } + + Testsuite::logDetailedPrintf("Create Directory is OK\n"); + return kTestPassed; +} + +TestExitStatus WebserverTests::testFilesPageUploadFile() { + if (!startServer()) { + Testsuite::logPrintf("Error! Can't start local webserver!\n"); + return kTestFailed; + } + + Common::String info = "Testing Webserver's files page Upload Files feature.\n" + "In this test you'll try to upload a file."; + + if (Testsuite::handleInteractiveInput(info, "OK", "Skip", kOptionRight)) { + Testsuite::logPrintf("Info! Skipping test : files page file upload\n"); + return kTestSkipped; + } + + Networking::Browser::openUrl(LocalServer.getAddress() + "files?path=/root/"); + if (Testsuite::handleInteractiveInput( + Common::String::format("You're able to upload a file in some directory with write access through %sfiles page?", LocalServer.getAddress().c_str()), + "Yes", "No", kOptionRight)) { + Testsuite::logDetailedPrintf("Error! Upload Files is not working!\n"); + return kTestFailed; + } + + Testsuite::logDetailedPrintf("Upload Files is OK\n"); + return kTestPassed; +} + +TestExitStatus WebserverTests::testFilesPageUploadDirectory() { + if (!startServer()) { + Testsuite::logPrintf("Error! Can't start local webserver!\n"); + return kTestFailed; + } + + Common::String info = "Testing Webserver's files page Upload Directory feature.\n" + "In this test you'll try to upload a directory (works in Chrome only)."; + + if (Testsuite::handleInteractiveInput(info, "OK", "Skip", kOptionRight)) { + Testsuite::logPrintf("Info! Skipping test : files page directory upload\n"); + return kTestSkipped; + } + + Networking::Browser::openUrl(LocalServer.getAddress() + "files?path=/root/"); + if (Testsuite::handleInteractiveInput( + Common::String::format("You're able to upload a directory into some directory with write access through %sfiles page using Chrome?", LocalServer.getAddress().c_str()), + "Yes", "No", kOptionRight)) { + Testsuite::logDetailedPrintf("Error! Upload Directory is not working!\n"); + return kTestFailed; + } + + Testsuite::logDetailedPrintf("Upload Directory is OK\n"); + return kTestPassed; +} + +TestExitStatus WebserverTests::testFilesPageDownloadFile() { + if (!startServer()) { + Testsuite::logPrintf("Error! Can't start local webserver!\n"); + return kTestFailed; + } + + Common::String info = "Testing Webserver's files downloading feature.\n" + "In this test you'll try to download a file."; + + if (Testsuite::handleInteractiveInput(info, "OK", "Skip", kOptionRight)) { + Testsuite::logPrintf("Info! Skipping test : files page download\n"); + return kTestSkipped; + } + + Networking::Browser::openUrl(LocalServer.getAddress() + "files?path=/root/"); + if (Testsuite::handleInteractiveInput( + Common::String::format("You're able to download a file through %sfiles page?", LocalServer.getAddress().c_str()), + "Yes", "No", kOptionRight)) { + Testsuite::logDetailedPrintf("Error! Files downloading is not working!\n"); + return kTestFailed; + } + + Testsuite::logDetailedPrintf("Files downloading is OK\n"); + return kTestPassed; +} + +} // End of namespace Testbed diff --git a/engines/testbed/webserver.h b/engines/testbed/webserver.h new file mode 100644 index 0000000000..3f3083469e --- /dev/null +++ b/engines/testbed/webserver.h @@ -0,0 +1,69 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef TESTBED_WEBSERVER_H +#define TESTBED_WEBSERVER_H + +#include "testbed/testsuite.h" + +namespace Testbed { + +namespace WebserverTests { + +// Helper functions for Webserver tests + +bool startServer(); +TestExitStatus testIP(); +TestExitStatus testIndexPage(); +TestExitStatus testFilesPageInvalidParameterValue(); +TestExitStatus testFilesPageCreateDirectory(); +TestExitStatus testFilesPageUploadFile(); +TestExitStatus testFilesPageUploadDirectory(); +TestExitStatus testFilesPageDownloadFile(); + +} // End of namespace WebserverTests + +class WebserverTestSuite : public Testsuite { +public: + /** + * The constructor for the WebserverTestSuite + * 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() + */ + WebserverTestSuite(); + ~WebserverTestSuite() {} + const char *getName() const { + return "Webserver"; + } + + const char *getDescription() const { + return "Webserver tests"; + } + +}; + +} // End of namespace Testbed + +#endif // TESTBED_TEMPLATE_H diff --git a/engines/tinsel/detection.cpp b/engines/tinsel/detection.cpp index c44f1f4ef3..d6bcfe5ea0 100644 --- a/engines/tinsel/detection.cpp +++ b/engines/tinsel/detection.cpp @@ -109,7 +109,8 @@ bool TinselMetaEngine::hasFeature(MetaEngineFeature f) const { return (f == kSupportsListSaves) || (f == kSupportsLoadingDuringStartup) || - (f == kSupportsDeleteSave); + (f == kSupportsDeleteSave) || + (f == kSimpleSavesNames); } bool Tinsel::TinselEngine::hasFeature(EngineFeature f) const { diff --git a/engines/titanic/support/simple_file.h b/engines/titanic/support/simple_file.h index f5d0bc7c1b..01aaa86925 100644 --- a/engines/titanic/support/simple_file.h +++ b/engines/titanic/support/simple_file.h @@ -278,7 +278,7 @@ public: * Set up a stream for write access */ virtual void open(Common::OutSaveFile *stream) { - SimpleFile::open(Common::wrapCompressedWriteStream(stream)); + SimpleFile::open(new Common::OutSaveFile(Common::wrapCompressedWriteStream(stream))); } }; diff --git a/engines/toltecs/detection.cpp b/engines/toltecs/detection.cpp index 7c707895e6..cc27341e10 100644 --- a/engines/toltecs/detection.cpp +++ b/engines/toltecs/detection.cpp @@ -234,7 +234,8 @@ bool ToltecsMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSavesSupportMetaInfo) || (f == kSavesSupportThumbnail) || (f == kSavesSupportCreationDate) || - (f == kSavesSupportPlayTime); + (f == kSavesSupportPlayTime) || + (f == kSimpleSavesNames); } bool Toltecs::ToltecsEngine::hasFeature(EngineFeature f) const { diff --git a/engines/toon/detection.cpp b/engines/toon/detection.cpp index 5d2e0a9bca..e93d676d87 100644 --- a/engines/toon/detection.cpp +++ b/engines/toon/detection.cpp @@ -159,7 +159,8 @@ bool ToonMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSupportsDeleteSave) || (f == kSavesSupportMetaInfo) || (f == kSavesSupportThumbnail) || - (f == kSavesSupportCreationDate); + (f == kSavesSupportCreationDate) || + (f == kSimpleSavesNames); } void ToonMetaEngine::removeSaveState(const char *target, int slot) const { diff --git a/engines/tsage/detection.cpp b/engines/tsage/detection.cpp index 584ad87742..e476391f71 100644 --- a/engines/tsage/detection.cpp +++ b/engines/tsage/detection.cpp @@ -95,6 +95,7 @@ public: case kSavesSupportThumbnail: case kSavesSupportCreationDate: case kSavesSupportPlayTime: + case kSimpleSavesNames: return true; default: return false; diff --git a/engines/tsage/stP1kAlM b/engines/tsage/stP1kAlM Binary files differnew file mode 100644 index 0000000000..dfbb3b9786 --- /dev/null +++ b/engines/tsage/stP1kAlM diff --git a/engines/voyeur/detection.cpp b/engines/voyeur/detection.cpp index 7b9fa6722e..eefe174e94 100644 --- a/engines/voyeur/detection.cpp +++ b/engines/voyeur/detection.cpp @@ -92,7 +92,8 @@ bool VoyeurMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSupportsLoadingDuringStartup) || (f == kSupportsDeleteSave) || (f == kSavesSupportMetaInfo) || - (f == kSavesSupportThumbnail); + (f == kSavesSupportThumbnail) || + (f == kSimpleSavesNames); } bool Voyeur::VoyeurEngine::hasFeature(EngineFeature f) const { diff --git a/engines/wage/detection.cpp b/engines/wage/detection.cpp index a27bfd7fde..778cd3c7a7 100644 --- a/engines/wage/detection.cpp +++ b/engines/wage/detection.cpp @@ -78,7 +78,8 @@ bool WageMetaEngine::hasFeature(MetaEngineFeature f) const { return (f == kSupportsListSaves) || (f == kSupportsLoadingDuringStartup) || - (f == kSupportsDeleteSave); + (f == kSupportsDeleteSave) || + (f == kSimpleSavesNames); } bool Wage::WageEngine::hasFeature(EngineFeature f) const { diff --git a/engines/zvision/detection.cpp b/engines/zvision/detection.cpp index cc967070d9..5e535a9954 100644 --- a/engines/zvision/detection.cpp +++ b/engines/zvision/detection.cpp @@ -87,7 +87,8 @@ bool ZVisionMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSupportsDeleteSave) || (f == kSavesSupportMetaInfo) || (f == kSavesSupportThumbnail) || - (f == kSavesSupportCreationDate); + (f == kSavesSupportCreationDate) || + (f == kSimpleSavesNames); //(f == kSavesSupportPlayTime); } |