Newer
Older
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2019 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source,
// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
#pragma once
#include "../../../ISISReflectometry/GUI/MainWindow/MainWindowPresenter.h"
#include "../../../ISISReflectometry/TestHelpers/ModelCreationHelper.h"
#include "../Batch/MockBatchView.h"
#include "../ReflMockObjects.h"
#include "MantidAPI/FrameworkManager.h"
#include "MantidGeometry/Instrument_fwd.h"
#include "MantidKernel/ConfigService.h"
#include "MantidQtWidgets/Common/MockSlitCalculator.h"
#include "MockMainWindowView.h"
#include <cxxtest/TestSuite.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using namespace MantidQt::CustomInterfaces::ISISReflectometry;
using namespace MantidQt::CustomInterfaces::ISISReflectometry::
ModelCreationHelper;
using MantidQt::API::IConfiguredAlgorithm_sptr;
using MantidQt::MantidWidgets::ISlitCalculator;
using testing::AtLeast;
using testing::Mock;
using testing::NiceMock;
using testing::Return;
using testing::ReturnRef;
class MainWindowPresenterTest : public CxxTest::TestSuite {
public:
// This pair of boilerplate methods prevent the suite being created statically
// This means the constructor isn't called when running other tests
static MainWindowPresenterTest *createSuite() {
return new MainWindowPresenterTest();
}
static void destroySuite(MainWindowPresenterTest *suite) { delete suite; }
MainWindowPresenterTest() : m_view(), m_messageHandler() {
Mantid::API::FrameworkManager::Instance();
// Get the view to return a couple of batches by default
m_batchViews.emplace_back(new MockBatchView);
m_batchViews.emplace_back(new MockBatchView);
ON_CALL(m_view, batches()).WillByDefault(Return(m_batchViews));
}
void setUp() override {
auto &config = Mantid::Kernel::ConfigService::Instance();
backup_facility = config.getString("default.facility");
backup_instrument = config.getString("default.instrument");
}
void tearDown() override {
auto &config = Mantid::Kernel::ConfigService::Instance();
config.setString("default.facility", backup_facility);
config.setString("default.instrument", backup_instrument);
}
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
void testPresenterSubscribesToView() {
EXPECT_CALL(m_view, subscribe(_)).Times(1);
auto presenter = makePresenter();
verifyAndClear();
}
void testConstructorAddsBatchPresenterForAllBatchViews() {
EXPECT_CALL(m_view, batches()).Times(1);
for (auto batchPresenter : m_batchPresenters)
expectBatchAdded(batchPresenter);
auto presenter = makePresenter();
TS_ASSERT_EQUALS(presenter.m_batchPresenters.size(), m_batchViews.size());
verifyAndClear();
}
void testBatchPresenterAddedWhenNewBatchRequested() {
auto presenter = makePresenter();
auto batchView = new NiceMock<MockBatchView>();
EXPECT_CALL(m_view, newBatch())
.Times(1)
.WillOnce(Return(dynamic_cast<IBatchView *>(batchView)));
auto batchPresenter = new NiceMock<MockBatchPresenter>();
EXPECT_CALL(*m_makeBatchPresenter, makeProxy(batchView))
.Times(1)
.WillOnce(Return(batchPresenter));
expectBatchAdded(batchPresenter);
presenter.notifyNewBatchRequested();
verifyAndClear();
}
void testBatchRemovedWhenCloseBatchRequested() {
auto presenter = makePresenter();
auto const batchIndex = 0;
expectBatchCanBeClosed(batchIndex);
expectBatchRemovedFromView(batchIndex);
presenter.notifyCloseBatchRequested(batchIndex);
assertFirstBatchWasRemovedFromModel(presenter);
verifyAndClear();
}
void testBatchNotRemovedIfRequestCloseFailed() {
auto presenter = makePresenter();
auto const batchIndex = 0;
expectRequestCloseBatchFailed(batchIndex);
expectBatchNotRemovedFromView(batchIndex);
presenter.notifyCloseBatchRequested(batchIndex);
assertBatchNotRemovedFromModel(presenter);
verifyAndClear();
}
void testBatchNotRemovedIfAutoreducing() {
auto presenter = makePresenter();
auto const batchIndex = 0;
expectBatchIsAutoreducing(batchIndex);
expectBatchNotRemovedFromView(batchIndex);
presenter.notifyCloseBatchRequested(batchIndex);
assertBatchNotRemovedFromModel(presenter);
verifyAndClear();
}
void testBatchNotRemovedIfProcessing() {
auto presenter = makePresenter();
auto const batchIndex = 0;
expectBatchIsProcessing(batchIndex);
expectBatchNotRemovedFromView(batchIndex);
presenter.notifyCloseBatchRequested(batchIndex);
assertBatchNotRemovedFromModel(presenter);
verifyAndClear();
}
void testWarningGivenIfRemoveBatchWhileAutoreducing() {
auto presenter = makePresenter();
auto const batchIndex = 0;
expectBatchIsAutoreducing(batchIndex);
expectCannotCloseBatchWarning();
presenter.notifyCloseBatchRequested(batchIndex);
verifyAndClear();
}
void testWarningGivenIfRemoveBatchWhileProcessing() {
auto presenter = makePresenter();
auto const batchIndex = 0;
expectBatchIsProcessing(batchIndex);
expectCannotCloseBatchWarning();
presenter.notifyCloseBatchRequested(batchIndex);
verifyAndClear();
}
void testReductionResumedNotifiesAllBatchPresenters() {
auto presenter = makePresenter();
for (auto batchPresenter : m_batchPresenters)
EXPECT_CALL(*batchPresenter, notifyAnyBatchReductionResumed());
presenter.notifyAnyBatchReductionResumed();
verifyAndClear();
}
void testReductionPausedNotifiesAllBatchPresenters() {
auto presenter = makePresenter();
for (auto batchPresenter : m_batchPresenters)
EXPECT_CALL(*batchPresenter, notifyAnyBatchReductionPaused());
presenter.notifyAnyBatchReductionPaused();
verifyAndClear();
}
void testShowOptionsOpensDialog() {
auto presenter = makePresenter();
// TODO Add test when options dialog is impelemented
// EXPECT_CALL(*m_optionsDialog, show()).Times(1);
presenter.notifyShowOptionsRequested();
verifyAndClear();
}
void testShowSlitCalculatorSetsInstrument() {
auto presenter = makePresenter();
auto const instrument = setupInstrument(presenter, "TEST_INSTRUMENT");
expectSlitCalculatorInstrumentUpdated(instrument);
presenter.notifyShowSlitCalculatorRequested();
verifyAndClear();
}
void testShowSlitCalculatorOpensDialog() {
auto presenter = makePresenter();
EXPECT_CALL(*m_slitCalculator, show()).Times(1);
presenter.notifyShowSlitCalculatorRequested();
verifyAndClear();
}
void testAutoreductionResumedNotifiesAllBatchPresenters() {
auto presenter = makePresenter();
for (auto batchPresenter : m_batchPresenters)
EXPECT_CALL(*batchPresenter, notifyAnyBatchAutoreductionResumed());
presenter.notifyAnyBatchAutoreductionResumed();
verifyAndClear();
}
void testAutoreductionPausedNotifiesAllBatchPresenters() {
auto presenter = makePresenter();
for (auto batchPresenter : m_batchPresenters)
EXPECT_CALL(*batchPresenter, notifyAnyBatchAutoreductionPaused());
presenter.notifyAnyBatchAutoreductionPaused();
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
verifyAndClear();
}
void testAnyBatchIsProcessing() {
auto presenter = makePresenter();
expectBatchIsNotProcessing(0);
expectBatchIsProcessing(1);
auto isProcessing = presenter.isAnyBatchProcessing();
TS_ASSERT_EQUALS(isProcessing, true);
verifyAndClear();
}
void testNoBatchesAreProcessing() {
auto presenter = makePresenter();
expectBatchIsNotProcessing(0);
expectBatchIsNotProcessing(1);
auto isProcessing = presenter.isAnyBatchProcessing();
TS_ASSERT_EQUALS(isProcessing, false);
verifyAndClear();
}
void testAnyBatchIsAutoreducing() {
auto presenter = makePresenter();
expectBatchIsNotAutoreducing(0);
expectBatchIsAutoreducing(1);
auto isAutoreducing = presenter.isAnyBatchAutoreducing();
TS_ASSERT_EQUALS(isAutoreducing, true);
verifyAndClear();
}
void testNoBatchesAreAutoreducing() {
auto presenter = makePresenter();
expectBatchIsNotAutoreducing(0);
expectBatchIsNotAutoreducing(1);
auto isAutoreducing = presenter.isAnyBatchAutoreducing();
TS_ASSERT_EQUALS(isAutoreducing, false);
verifyAndClear();
}
void testChangeInstrumentRequestedUpdatesInstrumentInModel() {
auto presenter = makePresenter();
auto const instrument = std::string("POLREF");
presenter.notifyChangeInstrumentRequested(instrument);
TS_ASSERT_EQUALS(presenter.instrumentName(), instrument);
verifyAndClear();
}
void testChangeInstrumentRequestedUpdatesInstrumentInChildPresenters() {
setupInstrument(presenter, "INTER");
auto const instrument = std::string("POLREF");
EXPECT_CALL(*m_batchPresenters[0], notifyInstrumentChanged(instrument))
.Times(1);
EXPECT_CALL(*m_batchPresenters[1], notifyInstrumentChanged(instrument))
.Times(1);
presenter.notifyChangeInstrumentRequested(instrument);
void testChangeInstrumentRequestedDoesNotUpdateInstrumentIfNotChanged() {
auto const instrument = setupInstrument(presenter, "POLREF");
EXPECT_CALL(*m_batchPresenters[0], notifyInstrumentChanged(instrument))
EXPECT_CALL(*m_batchPresenters[1], notifyInstrumentChanged(instrument))
.Times(0);
presenter.notifyChangeInstrumentRequested(instrument);
verifyAndClear();
}
void testUpdateInstrumentDoesNotUpdateInstrumentInChildPresenters() {
auto presenter = makePresenter();
auto const instrument = setupInstrument(presenter, "POLREF");
EXPECT_CALL(*m_batchPresenters[0], notifyInstrumentChanged(instrument))
.Times(0);
EXPECT_CALL(*m_batchPresenters[1], notifyInstrumentChanged(instrument))
.Times(0);
presenter.notifyUpdateInstrumentRequested();
verifyAndClear();
}
void testUpdateInstrumentUpdatesInstrumentInSlitCalculator() {
auto presenter = makePresenter();
auto const instrument = setupInstrument(presenter, "POLREF");
expectSlitCalculatorInstrumentUpdated(instrument);
presenter.notifyUpdateInstrumentRequested();
verifyAndClear();
}
void testUpdateInstrumentDoesNotChangeInstrumentName() {
auto const instrument = setupInstrument(presenter, "POLREF");
presenter.notifyUpdateInstrumentRequested();
TS_ASSERT_EQUALS(presenter.instrumentName(), instrument);
verifyAndClear();
}
void testUpdateInstrumentThrowsIfInstrumentNotSet() {
auto presenter = makePresenter();
TS_ASSERT_THROWS_ANYTHING(presenter.notifyUpdateInstrumentRequested());
verifyAndClear();
}
void testUpdateInstrumentSetsFacilityInConfig() {
auto presenter = makePresenter();
auto const instrument = setupInstrument(presenter, "POLREF");
auto &config = Mantid::Kernel::ConfigService::Instance();
config.setString("default.facility", "OLD_FACILITY");
presenter.notifyUpdateInstrumentRequested();
TS_ASSERT_EQUALS(config.getString("default.facility"), "ISIS");
verifyAndClear();
}
void testUpdateInstrumentSetsInstrumentInConfig() {
auto presenter = makePresenter();
auto const instrument = setupInstrument(presenter, "POLREF");
auto &config = Mantid::Kernel::ConfigService::Instance();
config.setString("default.instrument", "OLD_INSTRUMENT");
presenter.notifyUpdateInstrumentRequested();
TS_ASSERT_EQUALS(config.getString("default.instrument"), instrument);
verifyAndClear();
}
expectBatchIsSavedToFile(batchIndex);
presenter.notifySaveBatchRequested(batchIndex);
expectBatchIsLoadedFromFile(batchIndex);
presenter.notifyLoadBatchRequested(batchIndex);
private:
NiceMock<MockMainWindowView> m_view;
NiceMock<MockMessageHandler> m_messageHandler;
NiceMock<MockEncoder> *m_encoder;
NiceMock<MockDecoder> *m_decoder;
std::vector<IBatchView *> m_batchViews;
std::vector<NiceMock<MockBatchPresenter> *> m_batchPresenters;
NiceMock<MockBatchPresenterFactory> *m_makeBatchPresenter;
NiceMock<MockSlitCalculator> *m_slitCalculator;
class MainWindowPresenterFriend : public MainWindowPresenter {
friend class MainWindowPresenterTest;
public:
MainWindowPresenterFriend(
IMainWindowView *view, IMessageHandler *messageHandler,
IFileHandler *fileHandler, std::unique_ptr<IEncoder> encoder,
std::unique_ptr<IDecoder> decoder,
std::unique_ptr<ISlitCalculator> slitCalculator,
std::unique_ptr<IBatchPresenterFactory> makeBatchPresenter)
: MainWindowPresenter(view, messageHandler, fileHandler,
std::move(encoder), std::move(decoder),
std::move(makeBatchPresenter)) {}
};
MainWindowPresenterFriend makePresenter() {
auto encoder = std::make_unique<NiceMock<MockEncoder>>();
m_encoder = encoder.get();
auto decoder = std::make_unique<NiceMock<MockDecoder>>();
m_decoder = decoder.get();
auto slitCalculator = std::make_unique<NiceMock<MockSlitCalculator>>();
m_slitCalculator = slitCalculator.get();
auto makeBatchPresenter =
std::make_unique<NiceMock<MockBatchPresenterFactory>>();
m_makeBatchPresenter = makeBatchPresenter.get();
// Set up a mock batch presenter for each view to be returned from the
// factory
for (auto batchView : m_batchViews) {
auto batchPresenter = new NiceMock<MockBatchPresenter>();
m_batchPresenters.emplace_back(batchPresenter);
ON_CALL(*m_makeBatchPresenter, makeProxy(batchView))
.WillByDefault(Return(batchPresenter));
}
// Make the presenter
auto presenter = MainWindowPresenterFriend(
&m_view, &m_messageHandler, &m_fileHandler, std::move(encoder),
std::move(decoder), std::move(slitCalculator),
return presenter;
}
void verifyAndClear() {
TS_ASSERT(Mock::VerifyAndClearExpectations(&m_view));
TS_ASSERT(Mock::VerifyAndClearExpectations(&m_messageHandler));
TS_ASSERT(Mock::VerifyAndClearExpectations(&m_fileHandler));
TS_ASSERT(Mock::VerifyAndClearExpectations(&m_encoder));
TS_ASSERT(Mock::VerifyAndClearExpectations(&m_decoder));
for (auto batchPresenter : m_batchPresenters)
TS_ASSERT(Mock::VerifyAndClearExpectations(batchPresenter));
m_batchPresenters.clear();
}
std::string setupInstrument(MainWindowPresenterFriend &presenter,
presenter.m_instrument =
boost::make_shared<Mantid::Geometry::Instrument>(instrumentName);
return presenter.instrumentName();
}
void expectBatchAdded(MockBatchPresenter *batchPresenter) {
EXPECT_CALL(*batchPresenter, acceptMainPresenter(_)).Times(1);
EXPECT_CALL(*batchPresenter, initInstrumentList()).Times(1);
EXPECT_CALL(*batchPresenter, notifyInstrumentChanged(_)).Times(1);
EXPECT_CALL(*batchPresenter, notifyReductionPaused()).Times(1);
EXPECT_CALL(*batchPresenter, notifyAnyBatchAutoreductionPaused()).Times(1);
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
}
void expectBatchCanBeClosed(int batchIndex) {
EXPECT_CALL(*m_batchPresenters[batchIndex], isAutoreducing())
.Times(1)
.WillOnce(Return(false));
EXPECT_CALL(*m_batchPresenters[batchIndex], isProcessing())
.Times(1)
.WillOnce(Return(false));
EXPECT_CALL(*m_batchPresenters[batchIndex], requestClose())
.Times(1)
.WillOnce(Return(true));
}
void expectBatchIsAutoreducing(int batchIndex) {
EXPECT_CALL(*m_batchPresenters[batchIndex], isAutoreducing())
.Times(1)
.WillOnce(Return(true));
}
void expectBatchIsProcessing(int batchIndex) {
EXPECT_CALL(*m_batchPresenters[batchIndex], isProcessing())
.Times(1)
.WillOnce(Return(true));
}
void expectBatchIsNotAutoreducing(int batchIndex) {
EXPECT_CALL(*m_batchPresenters[batchIndex], isAutoreducing())
.Times(1)
.WillOnce(Return(false));
}
void expectBatchIsNotProcessing(int batchIndex) {
EXPECT_CALL(*m_batchPresenters[batchIndex], isProcessing())
.Times(1)
.WillOnce(Return(false));
}
void expectRequestCloseBatchFailed(int batchIndex) {
EXPECT_CALL(*m_batchPresenters[batchIndex], requestClose())
.Times(1)
.WillOnce(Return(false));
}
void expectBatchRemovedFromView(int batchIndex) {
EXPECT_CALL(m_view, removeBatch(batchIndex)).Times(1);
}
void expectBatchNotRemovedFromView(int batchIndex) {
EXPECT_CALL(m_view, removeBatch(batchIndex)).Times(0);
}
void expectCannotCloseBatchWarning() {
EXPECT_CALL(m_messageHandler,
giveUserCritical("Cannot close batch while processing or "
"autoprocessing is in progress",
"Error"))
.Times(1);
}
void expectSlitCalculatorInstrumentUpdated(std::string const &instrument) {
EXPECT_CALL(*m_slitCalculator, setCurrentInstrumentName(instrument))
.Times(1);
EXPECT_CALL(*m_slitCalculator, processInstrumentHasBeenChanged()).Times(1);
}
void expectBatchIsSavedToFile(int batchIndex) {
auto const filename = std::string("test.json");
auto const map = QMap<QString, QVariant>();
EXPECT_CALL(m_messageHandler, askUserForSaveFileName("JSON (*.json)"))
.Times(1)
.WillOnce(Return(filename));
EXPECT_CALL(*m_encoder, encodeBatch(&m_view, batchIndex, false))
.Times(1)
.WillOnce(Return(map));
EXPECT_CALL(m_fileHandler, saveJSONToFile(filename, map)).Times(1);
}
void expectBatchIsLoadedFromFile(int batchIndex) {
auto const filename = std::string("test.json");
auto const map = QMap<QString, QVariant>();
EXPECT_CALL(m_messageHandler, askUserForLoadFileName("JSON (*.json)"))
.Times(1)
.WillOnce(Return(filename));
EXPECT_CALL(m_fileHandler, loadJSONFromFile(filename))
.Times(1)
.WillOnce(Return(map));
EXPECT_CALL(*m_decoder, decodeBatch(&m_view, batchIndex, map)).Times(1);
}
void assertFirstBatchWasRemovedFromModel(
MainWindowPresenterFriend const &presenter) {
TS_ASSERT_EQUALS(presenter.m_batchPresenters.size(), 1);
// Note that our local list of raw pointers is not updated so
// the first item is invalid and the second item is now the
// only remaining batch presenter in the model
TS_ASSERT_EQUALS(presenter.m_batchPresenters[0].get(),
m_batchPresenters[1]);
}
void
assertBatchNotRemovedFromModel(MainWindowPresenterFriend const &presenter) {
TS_ASSERT_EQUALS(presenter.m_batchPresenters.size(),
m_batchPresenters.size());
for (size_t index = 0; index < m_batchPresenters.size(); ++index)
TS_ASSERT_EQUALS(presenter.m_batchPresenters[index].get(),
m_batchPresenters[index]);
}
private:
std::string backup_facility;
std::string backup_instrument;