aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorEugene Sandulenko2016-08-30 13:54:12 +0200
committerGitHub2016-08-30 13:54:12 +0200
commitbfbfbd3e1a8397cc3b1c9eaff6c7754abe3ddc3d (patch)
tree68851bdc99b78b4b1902944c1df3c3ee5d4f4489 /engines
parent7df744c291e5fcf5dc7afd3b21189c2c56810f8e (diff)
parent368f664c813075f8b8cb2c572dce65f60128eda4 (diff)
downloadscummvm-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')
-rw-r--r--engines/access/detection.cpp3
-rw-r--r--engines/adl/detection.cpp1
-rw-r--r--engines/agi/detection.cpp3
-rw-r--r--engines/agos/detection.cpp3
-rw-r--r--engines/avalanche/detection.cpp3
-rw-r--r--engines/bbvs/detection.cpp3
-rw-r--r--engines/cge/detection.cpp3
-rw-r--r--engines/cge2/detection.cpp3
-rw-r--r--engines/drascula/detection.cpp3
-rw-r--r--engines/gnap/detection.cpp3
-rw-r--r--engines/hopkins/detection.cpp3
-rw-r--r--engines/kyra/detection.cpp3
-rw-r--r--engines/kyra/kyra_v1.h3
-rw-r--r--engines/kyra/saveload.cpp4
-rw-r--r--engines/kyra/saveload_eob.cpp2
-rw-r--r--engines/lab/detection.cpp3
-rw-r--r--engines/mads/detection.cpp3
-rw-r--r--engines/metaengine.h14
-rw-r--r--engines/mortevielle/detection.cpp1
-rw-r--r--engines/neverhood/detection.cpp3
-rw-r--r--engines/prince/detection.cpp3
-rw-r--r--engines/saga/detection.cpp3
-rw-r--r--engines/savestate.cpp4
-rw-r--r--engines/savestate.h23
-rw-r--r--engines/scumm/detection.cpp3
-rw-r--r--engines/sherlock/detection.cpp3
-rw-r--r--engines/sky/detection.cpp2
-rw-r--r--engines/sword2/sword2.cpp3
-rw-r--r--engines/testbed/cloud.cpp565
-rw-r--r--engines/testbed/cloud.h83
-rw-r--r--engines/testbed/config-params.h12
-rw-r--r--engines/testbed/misc.cpp25
-rw-r--r--engines/testbed/misc.h3
-rw-r--r--engines/testbed/module.mk10
-rw-r--r--engines/testbed/testbed.cpp16
-rw-r--r--engines/testbed/webserver.cpp237
-rw-r--r--engines/testbed/webserver.h69
-rw-r--r--engines/tinsel/detection.cpp3
-rw-r--r--engines/titanic/support/simple_file.h2
-rw-r--r--engines/toltecs/detection.cpp3
-rw-r--r--engines/toon/detection.cpp3
-rw-r--r--engines/tsage/detection.cpp1
-rw-r--r--engines/tsage/stP1kAlMbin0 -> 24604948 bytes
-rw-r--r--engines/voyeur/detection.cpp3
-rw-r--r--engines/wage/detection.cpp3
-rw-r--r--engines/zvision/detection.cpp3
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
new file mode 100644
index 0000000000..dfbb3b9786
--- /dev/null
+++ b/engines/tsage/stP1kAlM
Binary files differ
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);
}