Skip to content
Snippets Groups Projects
DynamicFactoryTest.h 7.23 KiB
Newer Older
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
//     NScD Oak Ridge National Laboratory, European Spallation Source
//     & Institut Laue - Langevin
// SPDX - License - Identifier: GPL - 3.0 +
#ifndef DYNAMICFACTORYTEST_H_
#define DYNAMICFACTORYTEST_H_

#include "MantidKernel/DynamicFactory.h"
#include <boost/shared_ptr.hpp>
#include <string>
#include <vector>
class IntFactory : public DynamicFactory<int> {};
class CaseSensitiveIntFactory
    : public DynamicFactory<int, CaseSensitiveStringComparator> {};
class DynamicFactoryTest : public CxxTest::TestSuite {
  using int_ptr = boost::shared_ptr<int>;
  // This pair of boilerplate methods prevent the suite being created statically
  // This means the constructor isn't called when running other tests
  static DynamicFactoryTest *createSuite() { return new DynamicFactoryTest(); }
  static void destroySuite(DynamicFactoryTest *suite) { delete suite; }
  DynamicFactoryTest()
      : CxxTest::TestSuite(), factory(),
        m_notificationObserver(*this, &DynamicFactoryTest::handleFactoryUpdate),
        m_updateNoticeReceived(false) {
    factory.notificationCenter.addObserver(m_notificationObserver);
  }

  ~DynamicFactoryTest() override {
    factory.notificationCenter.removeObserver(m_notificationObserver);
  }

  void testCreate() {
    TS_ASSERT_THROWS(factory.create("testEntry"), const std::runtime_error &)
    factory.subscribe<int>("testEntry");
    TS_ASSERT_THROWS_NOTHING(int_ptr i = factory.create("testEntry"));
    TS_ASSERT_THROWS_NOTHING(int_ptr i = factory.create("TESTENTRY"));
  void testCreateCaseSensitive() {
    TS_ASSERT_THROWS(caseSensitiveFactory.create("testEntryCaseSensitive"),
    caseSensitiveFactory.subscribe<int>("testEntryCaseSensitive");
Samuel Jones's avatar
Samuel Jones committed
    TS_ASSERT_THROWS(int_ptr i =
                         caseSensitiveFactory.create("testEntryCaseSENSITIVE"),
                     const std::runtime_error
                         &); // case error on a case sensitive dynamic factory
    TS_ASSERT_THROWS_NOTHING(
        int_ptr i2 = caseSensitiveFactory.create("testEntryCaseSensitive"));
    caseSensitiveFactory.unsubscribe("testEntryCaseSensitive");
  }

  void testCreateUnwrapped() {
    TS_ASSERT_THROWS(factory.createUnwrapped("testUnrappedEntry"),
    factory.subscribe<int>("testUnwrappedEntry");
    int *i = nullptr;
    TS_ASSERT_THROWS_NOTHING(i = factory.createUnwrapped("testUnwrappedEntry"));
    int *j = nullptr;
    TS_ASSERT_THROWS_NOTHING(j = factory.createUnwrapped("TESTUnwrappedEntry"));
    factory.unsubscribe("testUnwrappedEntry");
  }

  void testCreateUnwrappedCaseSensitive() {
    TS_ASSERT_THROWS(
        caseSensitiveFactory.create("testUnrappedEntryCaseSensitive"),
    caseSensitiveFactory.subscribe<int>("testUnrappedEntryCaseSensitive");
    int *i = nullptr;
Samuel Jones's avatar
Samuel Jones committed
    TS_ASSERT_THROWS(i = caseSensitiveFactory.createUnwrapped(
                         "testUnrappedentrycaseSENSITIVE"),
                     const std::runtime_error
                         &); // case error on a case sensitive dynamic factory
    TS_ASSERT_THROWS_NOTHING(i = caseSensitiveFactory.createUnwrapped(
                                 "testUnrappedEntryCaseSensitive"));
    delete i;
    caseSensitiveFactory.unsubscribe("testUnrappedEntryCaseSensitive");
  }

  void testSubscribeWithEmptyNameThrowsInvalidArgument() {
    TS_ASSERT_THROWS(factory.subscribe<int>(""), const std::invalid_argument &);
  void
  testSubscribeWithReplaceEqualsErrorIfExistsThrowsRegisteringMatchingClass() {
    TS_ASSERT_THROWS_NOTHING(
        factory.subscribe("int", std::make_unique<Instantiator<int, int>>()));
    TS_ASSERT_THROWS(
        factory.subscribe("int", std::make_unique<Instantiator<int, int>>(),
                          IntFactory::ErrorIfExists),
        const std::runtime_error &);
  void testSubscribeWithReplaceEqualsOverwriteCurrentReplacesMatchingClass() {
    TS_ASSERT_THROWS_NOTHING(
        factory.subscribe("int", std::make_unique<Instantiator<int, int>>()));
    TS_ASSERT_THROWS_NOTHING(
        factory.subscribe("int", std::make_unique<Instantiator<int, int>>(),
                          IntFactory::OverwriteCurrent));
  void testSubscribeByDefaultDoesNotNotify() {
    TS_ASSERT_THROWS_NOTHING(factory.subscribe<int>("int"));
    TS_ASSERT_EQUALS(m_updateNoticeReceived, false)
  void testSubscribeNotifiesIfTheyAreSwitchedOn() {
    m_updateNoticeReceived = false;
    factory.enableNotifications();
    TS_ASSERT_THROWS_NOTHING(factory.subscribe<int>("intWithNotice"));
    TS_ASSERT_EQUALS(m_updateNoticeReceived, true)
    TS_ASSERT_THROWS_NOTHING(factory.unsubscribe("intWithNotice"));
  }
  void testUnsubscribeByDefaultDoesNotNotify() {
    TS_ASSERT_THROWS(factory.unsubscribe("tester"), const std::runtime_error &);
    factory.subscribe<int>("tester");
    m_updateNoticeReceived = false;
    TS_ASSERT_THROWS_NOTHING(factory.unsubscribe("tester"));
    TS_ASSERT_EQUALS(m_updateNoticeReceived, false)
  void testUnsubscribeNotifiesIfTheyAreSwitchedOn() {
    TS_ASSERT_THROWS_NOTHING(factory.subscribe<int>("intWithNotice"));
    factory.enableNotifications();
    m_updateNoticeReceived = false;
    TS_ASSERT_THROWS_NOTHING(factory.unsubscribe("intWithNotice"));
    TS_ASSERT_EQUALS(m_updateNoticeReceived, true)

    factory.disableNotifications();
    m_updateNoticeReceived = false;
  void testExists() {
    TS_ASSERT(!factory.exists("testing"));
    factory.subscribe<int>("testing");
    TS_ASSERT(factory.exists("testing"));
    TS_ASSERT(factory.exists("TESTING"));

  void testGetKeys() {
    std::string testKey = "testGetKeys";
    // check it is not already present
    TS_ASSERT_THROWS(factory.create(testKey), const std::runtime_error &)
    factory.subscribe<int>(testKey);

    std::vector<std::string> keys = factory.getKeys();

    TSM_ASSERT("Could not find the test key in the returned vector.",
               std::find(keys.begin(), keys.end(), testKey) !=
                   keys.end()) // check the case is correct
    TS_ASSERT(!keys.empty());
  void testGetKeysRetainsCase() {
    std::string testKey = "testGetKeysRetainsCase";
    // check it is not already present
    TS_ASSERT_THROWS(factory.create(testKey), const std::runtime_error &)
    factory.subscribe<int>(testKey);

    std::vector<std::string> keys = factory.getKeys();

    factory.unsubscribe(testKey);
  void
  handleFactoryUpdate(const Poco::AutoPtr<IntFactory::UpdateNotification> &) {
  CaseSensitiveIntFactory caseSensitiveFactory;
  Poco::NObserver<DynamicFactoryTest, IntFactory::UpdateNotification>
      m_notificationObserver;