Newer
Older
#ifndef MANTID_KERNEL_DATASERVICETEST_H_
#define MANTID_KERNEL_DATASERVICETEST_H_
#include "MantidKernel/DataService.h"
#include <cxxtest/TestSuite.h>
#include <Poco/NObserver.h>
#include <boost/make_shared.hpp>
using namespace Mantid;
using namespace Mantid::Kernel;
/// A simple data service
class FakeDataService : public DataService<int> {
FakeDataService() : DataService<int>("FakeDataService") {}
class DataServiceTest : public CxxTest::TestSuite {
private:
// A data service storing an int
FakeDataService svc;
int notificationFlag; // A flag to help with testing notifications
std::vector<int> vector;
public:
static DataServiceTest *createSuite() { return new DataServiceTest(); }
static void destroySuite(DataServiceTest *suite) { delete suite; }
notificationFlag = 0;
ConfigService::Instance().setString("MantidOptions.InvisibleWorkspaces",
"0");
}
// Handler for an observer, called each time an object is added
void handleAddNotification(
const Poco::AutoPtr<FakeDataService::AddNotification> &) {
std::lock_guard<std::mutex> _lock(m_vectorMutex);
vector.push_back(123);
++notificationFlag;
void test_add() {
Poco::NObserver<DataServiceTest, FakeDataService::AddNotification> observer(
*this, &DataServiceTest::handleAddNotification);
svc.notificationCenter.addObserver(observer);
auto one = boost::make_shared<int>(1);
// Add and check that it is in there
TS_ASSERT_THROWS_NOTHING(svc.add("one", one););
TS_ASSERT_EQUALS(svc.size(), 1);
TS_ASSERT(svc.doesExist("one"));
TS_ASSERT(svc.retrieve("one") == one);
// Same object can go in with different name
svc.add("anotherOne", one);
TS_ASSERT_EQUALS(svc.retrieve("anotherOne"), one);
// Can't re-add the same name
TS_ASSERT_THROWS(svc.add("one", one), std::runtime_error);
// Can't add blank name
TS_ASSERT_THROWS(svc.add("", one), std::runtime_error);
// Can't add empty pointer
TS_ASSERT_THROWS(svc.add("Null", boost::shared_ptr<int>()),
std::runtime_error);
svc.add("__hidden", boost::make_shared<int>(99));
TS_ASSERT_EQUALS(notificationFlag, 3)
svc.notificationCenter.removeObserver(observer);
}
void handlePreDeleteNotification(const Poco::AutoPtr<
FakeDataService::PreDeleteNotification> ¬ification) {
TS_ASSERT_EQUALS(notification->objectName(), "one");
TS_ASSERT_EQUALS(*notification->object(), 1);
++notificationFlag;
}
void handlePostDeleteNotification(const Poco::AutoPtr<
FakeDataService::PostDeleteNotification> ¬ification) {
TS_ASSERT_EQUALS(notification->objectName(), "one");
++notificationFlag;
void test_remove() {
Poco::NObserver<DataServiceTest, FakeDataService::PreDeleteNotification>
observer(*this, &DataServiceTest::handlePreDeleteNotification);
svc.notificationCenter.addObserver(observer);
Poco::NObserver<DataServiceTest, FakeDataService::PreDeleteNotification>
postobserver(*this, &DataServiceTest::handlePreDeleteNotification);
svc.notificationCenter.addObserver(postobserver);
TS_ASSERT_THROWS_NOTHING(svc.add("one", boost::make_shared<int>(1)););
TS_ASSERT_EQUALS(svc.size(), 1);
TS_ASSERT_THROWS_NOTHING(
svc.remove("two")); // Nothing happens if the workspace isn't there
TS_ASSERT_THROWS_NOTHING(svc.remove("one"));
TS_ASSERT_EQUALS(svc.size(), 0);
TS_ASSERT_EQUALS(notificationFlag, 2);
svc.notificationCenter.removeObserver(observer);
svc.notificationCenter.removeObserver(postobserver);
void test_addOrReplace() {
TS_ASSERT_EQUALS(svc.size(), 0);
TS_ASSERT_THROWS_NOTHING(svc.add("one", boost::make_shared<int>(1)););
TS_ASSERT_EQUALS(svc.size(), 1);
// Does it replace?
boost::shared_ptr<int> two = boost::make_shared<int>(2);
TS_ASSERT_THROWS_NOTHING(svc.addOrReplace("one", two););
TS_ASSERT_EQUALS(svc.size(), 1);
TS_ASSERT(svc.doesExist("one"));
// Was the name replaced? One equals two, what funny math!!!
TS_ASSERT(svc.retrieve("one") == two);
TS_ASSERT_EQUALS(*svc.retrieve("one"), 2);
// Can't add blank names
TS_ASSERT_THROWS(svc.addOrReplace("", two), std::runtime_error);
// Can't add empty pointer
TS_ASSERT_THROWS(svc.addOrReplace("one", boost::shared_ptr<int>()),
std::runtime_error);
void handleBeforeReplaceNotification(
const Poco::AutoPtr<FakeDataService::BeforeReplaceNotification> &) {
++notificationFlag;
void handleRenameNotification(
const Poco::AutoPtr<FakeDataService::RenameNotification> &) {
++notificationFlag;
}
Poco::NObserver<DataServiceTest, FakeDataService::BeforeReplaceNotification>
observer(*this, &DataServiceTest::handleBeforeReplaceNotification);
svc.notificationCenter.addObserver(observer);
Poco::NObserver<DataServiceTest, FakeDataService::RenameNotification>
observer2(*this, &DataServiceTest::handleRenameNotification);
svc.notificationCenter.addObserver(observer2);
auto one = boost::make_shared<int>(1);
auto two = boost::make_shared<int>(2);
svc.add("One", one);
svc.add("Two", two);
TS_ASSERT_EQUALS(svc.size(), 2);
TSM_ASSERT_THROWS_NOTHING("Nothing should happen if the names match",
svc.rename("One", "One"));
TSM_ASSERT_THROWS_NOTHING("Should be just a warning if object not there",
svc.rename("NotThere", "NewName"));
// We aren't doing anything so no notifications should post
TSM_ASSERT_EQUALS("No notifications should have been posted",
notificationFlag, 0);
svc.rename(
"one",
"anotherOne"); // Note: Rename is case-insensitive on the old name
TS_ASSERT_EQUALS(svc.size(), 2);
TSM_ASSERT_THROWS("One should have been renamed to anotherOne",
svc.retrieve("one"), Exception::NotFoundError);
TSM_ASSERT_EQUALS("One should have been renamed to anotherOne",
svc.retrieve("anotherOne"), one);
TSM_ASSERT_EQUALS("The observers should have been called once",
notificationFlag, 1);
svc.rename("Two", "anotherOne");
TS_ASSERT_EQUALS(svc.size(), 1);
TSM_ASSERT_THROWS("Two should have been renamed to anotherOne",
svc.retrieve("two"), Exception::NotFoundError);
TSM_ASSERT_EQUALS("Two should have been renamed to anotherOne",
svc.retrieve("anotherOne"), two);
// As we are renaming to an existing workspace there should be 2
// notifications
TSM_ASSERT_EQUALS("The observers should have been called 2 times in total",
notificationFlag, 2);
svc.notificationCenter.removeObserver(observer);
svc.notificationCenter.removeObserver(observer2);
TS_ASSERT_THROWS(svc.rename("anotherOne", ""), std::runtime_error);
TSM_ASSERT_THROWS_NOTHING("'AnotherOne' should still be there",
svc.retrieve("anotherOne"));
void handleClearNotification(
const Poco::AutoPtr<FakeDataService::ClearNotification> &) {
++notificationFlag;
}
void test_clear() {
svc.add("something", boost::make_shared<int>(10));
TSM_ASSERT_LESS_THAN("Size should be 1", 0, svc.size());
svc.clear();
TSM_ASSERT_EQUALS("DataService should be empty", svc.size(), 0);
TSM_ASSERT("handleClearNotification should not have been called",
!notificationFlag);
Poco::NObserver<DataServiceTest, FakeDataService::ClearNotification>
observer(*this, &DataServiceTest::handleClearNotification);
svc.notificationCenter.addObserver(observer);
svc.add("something", boost::make_shared<int>(10));
svc.clear();
TSM_ASSERT_EQUALS("DataService should be empty", svc.size(), 0);
TSM_ASSERT("handleClearNotification should have been called",
notificationFlag);
svc.notificationCenter.removeObserver(observer);
}
void test_retrieve_and_doesExist() {
auto one = boost::make_shared<int>(1);
TS_ASSERT_EQUALS(svc.retrieve("one"), one);
TSM_ASSERT_EQUALS("Retrieval should be case-insensitive",
svc.retrieve("oNE"), one);
TS_ASSERT_THROWS(svc.retrieve("NOTone"), Exception::NotFoundError);
TS_ASSERT(svc.doesExist("one"));
TSM_ASSERT("doesExist should be case-insensitive", svc.doesExist("oNE"));
TS_ASSERT(!svc.doesExist("NOTone"));
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
void test_does_all_exist() {
auto one = boost::make_shared<int>(1);
auto two = boost::make_shared<int>(2);
const std::string oneName = "one";
const std::string twoName = "two";
svc.add(oneName, one);
svc.add(twoName, two);
std::vector<std::string> expectedNames{ oneName, twoName };
TS_ASSERT(svc.doAllWsExist(expectedNames));
}
void test_does_all_exist_partial() {
auto one = boost::make_shared<int>(1);
const std::string oneName = "one";
svc.add(oneName, one);
std::vector<std::string> expectedNames{ oneName };
TS_ASSERT(svc.doAllWsExist(expectedNames));
}
void test_does_all_exist_missing_ws() {
auto one = boost::make_shared<int>(1);
auto two = boost::make_shared<int>(2);
const std::string oneName = "one";
const std::string twoName = "two";
const std::string threeName = "three";
svc.add(oneName, one);
svc.add(twoName, two);
std::vector<std::string> expectedNames{ oneName, twoName, threeName };
TS_ASSERT(!svc.doAllWsExist(expectedNames));
}
void test_size() {
TS_ASSERT_EQUALS(svc.size(), 0);
svc.add("something", boost::make_shared<int>(-1));
TS_ASSERT_EQUALS(svc.size(), 1);
svc.add("__hidden", boost::make_shared<int>(1));
TSM_ASSERT_EQUALS("Hidden workspaces should not be counted", svc.size(), 1);
ConfigService::Instance().setString("MantidOptions.InvisibleWorkspaces",
"1");
TS_ASSERT_EQUALS(svc.size(), 2);
void test_getObjectNames_and_getObjects() {
auto one = boost::make_shared<int>(1);
auto two = boost::make_shared<int>(2);
auto three = boost::make_shared<int>(3);
svc.add("One", one);
svc.add("Two", two);
svc.add("TwoAgain",
two); // Same pointer again - should appear twice in getObjects()
svc.add("__Three", three);
auto names = svc.getObjectNames();
auto objects = svc.getObjects();
TSM_ASSERT_EQUALS("Hidden entries should not be returned", names.size(), 3);
TSM_ASSERT_EQUALS("Hidden entries should not be returned", objects.size(),
3);
TS_ASSERT_DIFFERS(std::find(names.cbegin(), names.cend(), "One"),
names.end());
TS_ASSERT_DIFFERS(std::find(names.cbegin(), names.cend(), "Two"),
names.end());
TS_ASSERT_DIFFERS(std::find(names.cbegin(), names.cend(), "TwoAgain"),
names.end());
TS_ASSERT_EQUALS(std::find(names.cbegin(), names.cend(), "__Three"),
names.end());
TSM_ASSERT_EQUALS("Hidden entries should not be returned",
std::find(names.cbegin(), names.cend(), "__Three"),
names.end());
TS_ASSERT_EQUALS(objects.at(0), one);
TS_ASSERT_EQUALS(objects.at(1), two);
TS_ASSERT_EQUALS(objects.at(2), two);
auto allNamesSize = svc.getObjectNames().size();
ConfigService::Instance().setString("MantidOptions.InvisibleWorkspaces",
"1");
TS_ASSERT_EQUALS(allNamesSize, 3)
names = svc.getObjectNames();
objects = svc.getObjects();
TS_ASSERT_EQUALS(names.size(), 4);
TS_ASSERT_EQUALS(objects.size(), 4);
auto cit = std::find(names.cbegin(), names.cend(), "__Three");
TS_ASSERT_DIFFERS(cit, names.cend());
TS_ASSERT_EQUALS(objects.at(std::distance(names.cbegin(), cit)), three);
void test_sortedAndHiddenGetNames() {
auto one = boost::make_shared<int>(1);
auto two = boost::make_shared<int>(2);
auto three = boost::make_shared<int>(3);
auto four = boost::make_shared<int>(4);
// This time add them in a random order
svc.add("One", one);
svc.add("__Three", three);
svc.add("Four", four);
svc.add("Two", two);
using sortedEnum = Mantid::Kernel::DataServiceSort;
using hiddenEnum = Mantid::Kernel::DataServiceHidden;
// First assert that sort does not impact size
TS_ASSERT_EQUALS(svc.getObjectNames(sortedEnum::Sorted).size(),
svc.getObjectNames(sortedEnum::Unsorted).size());
// Get unsorted and sort the manually
auto sortReference = svc.getObjectNames();
std::sort(sortReference.begin(), sortReference.end());
TS_ASSERT_EQUALS(svc.getObjectNames(sortedEnum::Sorted), sortReference);
// Next assert that Hidden flags behave
TS_ASSERT_EQUALS(
svc.getObjectNames(sortedEnum::Unsorted, hiddenEnum::Exclude).size(),
3);
TS_ASSERT_EQUALS(
svc.getObjectNames(sortedEnum::Unsorted, hiddenEnum::Include).size(),
4);
}
// This starts observing the notifications of "add"
Poco::NObserver<DataServiceTest, FakeDataService::AddNotification> observer(
*this, &DataServiceTest::handleAddNotification);
svc.notificationCenter.addObserver(observer);
vector.clear();
svc.add("object1", boost::make_shared<int>(12345));
int num = 5000;
PARALLEL_FOR_NO_WSP_CHECK()
boost::shared_ptr<int> object = boost::make_shared<int>(i);
std::ostringstream mess;
mess << "item" << i;
// Adding/replacing some items
svc.addOrReplace(mess.str(), object);
// And retrieving some at the same time
boost::shared_ptr<int> retrieved = svc.retrieve("object1");
TS_ASSERT_EQUALS(*retrieved, 12345);
// Also add then remove another object
std::string otherName = "other_" + mess.str();
boost::shared_ptr<int> other = boost::make_shared<int>(i);
svc.add(otherName, other);
svc.remove(otherName);
TS_ASSERT_EQUALS(svc.size(), size_t(num + 1));
// Vector was append twice per loop
TS_ASSERT_EQUALS(vector.size(), size_t(num * 2 + 1));
// Try a few random items, check that they are there
TS_ASSERT_EQUALS(*svc.retrieve("item19"), 19);
TS_ASSERT_EQUALS(*svc.retrieve("item765"), 765);
TS_ASSERT_EQUALS(*svc.retrieve("item2345"), 2345);
void test_prefixToHide() {
TS_ASSERT_EQUALS(FakeDataService::prefixToHide(), "__");
void test_isHiddenDataServiceObject() {
TS_ASSERT(FakeDataService::isHiddenDataServiceObject("__hidden"));
TS_ASSERT(FakeDataService::isHiddenDataServiceObject("__HIDDEN"));
TS_ASSERT(!FakeDataService::isHiddenDataServiceObject("NotHidden"));
TS_ASSERT(!FakeDataService::isHiddenDataServiceObject("_NotHidden"));
TS_ASSERT(!FakeDataService::isHiddenDataServiceObject("NotHidden__"));
TS_ASSERT(!FakeDataService::isHiddenDataServiceObject("Not__Hidden"));
void test_showingHiddenObjects() {
TS_ASSERT(!FakeDataService::showingHiddenObjects());
ConfigService::Instance().setString("MantidOptions.InvisibleWorkspaces",
"1");
TS_ASSERT(FakeDataService::showingHiddenObjects());
// Check behaviour if it's set to some invalid values
ConfigService::Instance().setString("MantidOptions.InvisibleWorkspaces",
"invalid");
TS_ASSERT(!FakeDataService::showingHiddenObjects());
ConfigService::Instance().setString("MantidOptions.InvisibleWorkspaces",
"-1");
TS_ASSERT(!FakeDataService::showingHiddenObjects());
ConfigService::Instance().setString("MantidOptions.InvisibleWorkspaces",
"2");
TS_ASSERT(!FakeDataService::showingHiddenObjects());
ConfigService::Instance().setString("MantidOptions.InvisibleWorkspaces",
"^~");
TS_ASSERT(!FakeDataService::showingHiddenObjects());
};
#endif /* MANTID_KERNEL_DATASERVICETEST_H_ */