LogManagerTest.h 21 KB
Newer Older
1
2
3
4
5
6
7
8
9
#ifndef LOG_MANAGER_TEST_H_
#define LOG_MANAGER_TEST_H_

#include "MantidAPI/LogManager.h"
#include "MantidKernel/Exception.h"
#include "MantidKernel/Matrix.h"
#include "MantidKernel/Property.h"
#include "MantidKernel/TimeSeriesProperty.h"
#include "MantidKernel/V3D.h"
10
#include <cxxtest/TestSuite.h>
11
#include "MantidTestHelpers/NexusTestHelper.h"
12
#include "MantidGeometry/Instrument/Goniometer.h"
13
#include <cmath>
14
15
16
17

using namespace Mantid::Kernel;
using namespace Mantid::API;
using namespace Mantid::Geometry;
18
using Mantid::Types::Core::DateAndTime;
19
20

// Helper class
21
22
23
24
namespace {
class ConcreteProperty : public Property {
public:
  ConcreteProperty() : Property("Test", typeid(int)) {}
25
26
27
28
29
  ConcreteProperty *clone() const override {
    return new ConcreteProperty(*this);
  }
  bool isDefault() const override { return true; }
  std::string getDefault() const override {
30
    return "getDefault() is not implemented in this class";
31
  }
32
33
34
35
36
37
38
  std::string value() const override { return "Nothing"; }
  std::string setValue(const std::string &) override { return ""; }
  std::string setValueFromProperty(const Property &) override { return ""; }
  std::string setDataItem(const boost::shared_ptr<DataItem>) override {
    return "";
  }
  Property &operator+=(Property const *) override { return *this; }
39
40
};

41
template <typename T>
42
void addTestTimeSeries(LogManager &run, const std::string &name) {
43
  auto timeSeries = new TimeSeriesProperty<T>(name);
44
45
46
47
48
49
50
51
52
53
54
55
  timeSeries->addValue("2012-07-19T16:17:00", 2);
  timeSeries->addValue("2012-07-19T16:17:10", 3);
  timeSeries->addValue("2012-07-19T16:17:20", 4);
  timeSeries->addValue("2012-07-19T16:17:30", 5);
  timeSeries->addValue("2012-07-19T16:17:40", 6);
  timeSeries->addValue("2012-07-19T16:17:50", 20);
  timeSeries->addValue("2012-07-19T16:18:00", 21);
  timeSeries->addValue("2012-07-19T16:18:10", 22);
  timeSeries->addValue("2012-07-19T16:19:20", 23);
  timeSeries->addValue("2012-07-19T16:19:20", 24);
  run.addProperty(timeSeries);
}
56
}
57

58
59
60
61
62
63
64
65
void addTimeSeriesEntry(LogManager &runInfo, std::string name, double val) {
  TimeSeriesProperty<double> *tsp;
  tsp = new TimeSeriesProperty<double>(name);
  tsp->addValue("2011-05-24T00:00:00", val);
  runInfo.addProperty(tsp);
}

class LogManagerTest : public CxxTest::TestSuite {
66
public:
67
  void testAddGetData() {
68
69
70
    LogManager runInfo;

    Property *p = new ConcreteProperty();
71
    TS_ASSERT_THROWS_NOTHING(runInfo.addProperty(p));
72

73
    Property *pp = nullptr;
74
75
76
77
78
79
80
81
82
83
84
85
    TS_ASSERT_THROWS_NOTHING(pp = runInfo.getProperty("Test"));
    TS_ASSERT_EQUALS(p, pp);
    TS_ASSERT(!pp->name().compare("Test"));
    TS_ASSERT(dynamic_cast<ConcreteProperty *>(pp));
    TS_ASSERT_THROWS(pp = runInfo.getProperty("NotThere"),
                     Exception::NotFoundError);

    std::vector<Property *> props = runInfo.getProperties();
    TS_ASSERT(!props.empty());
    TS_ASSERT_EQUALS(props.size(), 1);
    TS_ASSERT(!props[0]->name().compare("Test"));
    TS_ASSERT(dynamic_cast<ConcreteProperty *>(props[0]));
86
87
  }

88
  void testRemoveLogData() {
89
    LogManager runInfo;
90

91
    Property *p = new ConcreteProperty();
92
93
94
    TS_ASSERT_THROWS_NOTHING(runInfo.addProperty(p));
    TS_ASSERT_THROWS_NOTHING(runInfo.removeProperty("Test"));
    TS_ASSERT_EQUALS(runInfo.getProperties().size(), 0);
95
96
  }

97
  void testStartTime() {
98
99
    LogManager runInfo;
    // Nothing there yet
100
    TS_ASSERT_THROWS(runInfo.startTime(), std::runtime_error);
101
102
    // Add run_start and see that get picked up
    const std::string run_start("2013-12-19T13:38:00");
103
104
    auto run_start_prop =
        new PropertyWithValue<std::string>("run_start", run_start);
105
    runInfo.addProperty(run_start_prop);
106
    TS_ASSERT_EQUALS(runInfo.startTime(), DateAndTime(run_start));
107
108
    // Add start_time and see that get picked up in preference
    const std::string start_time("2013-12-19T13:40:00");
109
110
    auto start_time_prop =
        new PropertyWithValue<std::string>("start_time", start_time);
111
    runInfo.addProperty(start_time_prop);
112
    TS_ASSERT_EQUALS(runInfo.startTime(), DateAndTime(start_time));
113
114
115
    // But get back run_start again if start_time is equal to the epoch
    const std::string epoch("1990-01-01T00:00:00");
    start_time_prop->setValue(epoch);
116
    TS_ASSERT_EQUALS(runInfo.startTime(), DateAndTime(run_start));
117
118
    // And back to failure if they're both that
    run_start_prop->setValue(epoch);
119
    TS_ASSERT_THROWS(runInfo.startTime(), std::runtime_error);
120
121
122
123

    // Set run_start back to valid value and make start_time contain nonsense
    run_start_prop->setValue(run_start);
    start_time_prop->setValue("__");
124
    TS_ASSERT_EQUALS(runInfo.startTime(), DateAndTime(run_start));
125
126
    // Now make start_time a completely different property type
    runInfo.removeProperty("start_time");
127
    runInfo.addProperty(new PropertyWithValue<double>("start_time", 3.33));
128
    TS_ASSERT_EQUALS(runInfo.startTime(), DateAndTime(run_start));
129
130
    // Now make run_start something invalid
    run_start_prop->setValue("notADate");
131
    TS_ASSERT_THROWS(runInfo.startTime(), std::runtime_error);
132
133
    // And check things if it's the wrong property type
    runInfo.removeProperty("run_start");
134
135
    addTimeSeriesEntry(runInfo, "run_start", 4.44);
    TS_ASSERT_THROWS(runInfo.startTime(), std::runtime_error);
136
  }
137

138
  void testEndTime() {
139
140
    LogManager runInfo;
    // Nothing there yet
141
    TS_ASSERT_THROWS(runInfo.endTime(), std::runtime_error);
142
143
    // Add run_end and see that get picked up
    const std::string run_end("2013-12-19T13:38:00");
144
    auto run_end_prop = new PropertyWithValue<std::string>("run_end", run_end);
145
    runInfo.addProperty(run_end_prop);
146
    TS_ASSERT_EQUALS(runInfo.endTime(), DateAndTime(run_end));
147
148
    // Add end_time and see that get picked up in preference
    const std::string end_time("2013-12-19T13:40:00");
149
150
    auto end_time_prop =
        new PropertyWithValue<std::string>("end_time", end_time);
151
    runInfo.addProperty(end_time_prop);
152
    TS_ASSERT_EQUALS(runInfo.endTime(), DateAndTime(end_time));
153
154
155
156

    // Set run_end back to valid value and make end_time contain nonsense
    run_end_prop->setValue(run_end);
    end_time_prop->setValue("__");
157
    TS_ASSERT_EQUALS(runInfo.endTime(), DateAndTime(run_end));
158
159
    // Now make end_time a completely different property type
    runInfo.removeProperty("end_time");
160
    runInfo.addProperty(new PropertyWithValue<double>("end_time", 3.33));
161
    TS_ASSERT_EQUALS(runInfo.endTime(), DateAndTime(run_end));
162
163
    // Now make run_end something invalid
    run_end_prop->setValue("notADate");
164
    TS_ASSERT_THROWS(runInfo.endTime(), std::runtime_error);
165
166
    // And check things if it's the wrong property type
    runInfo.removeProperty("run_end");
167
168
    addTimeSeriesEntry(runInfo, "run_end", 4.44);
    TS_ASSERT_THROWS(runInfo.endTime(), std::runtime_error);
169
170
  }

171
  void testMemory() {
172
    LogManager runInfo;
173
174
    TS_ASSERT_EQUALS(runInfo.getMemorySize(), 0);

175
176
177
    Property *p = new ConcreteProperty();
    runInfo.addProperty(p);

178
179
    TS_ASSERT_EQUALS(runInfo.getMemorySize(),
                     sizeof(ConcreteProperty) + sizeof(void *));
180
181
  }

182
  void test_GetTimeSeriesProperty_Returns_TSP_When_Log_Exists() {
183
    LogManager runInfo;
184
    const std::string &name = "double_time_series";
185
186
187
    const double value = 10.9;
    addTimeSeriesEntry(runInfo, name, value);

188
    TimeSeriesProperty<double> *tsp(nullptr);
189
190
191
192
    TS_ASSERT_THROWS_NOTHING(tsp = runInfo.getTimeSeriesProperty<double>(name));
    TS_ASSERT_DELTA(tsp->firstValue(), value, 1e-12);
  }

193
  void test_GetTimeSeriesProperty_Throws_When_Log_Does_Not_Exist() {
194
    LogManager runInfo;
195
196
    TS_ASSERT_THROWS(runInfo.getTimeSeriesProperty<double>("not_a_log"),
                     Exception::NotFoundError);
197
198
  }

199
200
  void
  test_GetTimeSeriesProperty_Throws_When_Log_Exists_But_Is_Not_Correct_Type() {
201
    LogManager runInfo;
202
    const std::string &name = "double_prop";
203
204
    runInfo.addProperty(name, 5.6); // Standard double property

205
206
    TS_ASSERT_THROWS(runInfo.getTimeSeriesProperty<double>(name),
                     std::invalid_argument);
207
208
  }

209
  void test_GetPropertyAsType_Throws_When_Property_Does_Not_Exist() {
210
    LogManager runInfo;
211
212
    TS_ASSERT_THROWS(runInfo.getPropertyValueAsType<double>("not_a_log"),
                     Exception::NotFoundError);
213
214
  }

215
  void test_GetPropertyAsType_Returns_Expected_Value_When_Type_Is_Correct() {
216
    LogManager runInfo;
217
    const std::string &name = "double_prop";
218
219
220
221
    const double value = 5.6;
    runInfo.addProperty(name, value); // Standard double property

    double retrieved(0.0);
222
223
    TS_ASSERT_THROWS_NOTHING(retrieved =
                                 runInfo.getPropertyValueAsType<double>(name));
224
225
226
    TS_ASSERT_DELTA(retrieved, value, 1e-12);
  }

227
  void test_GetPropertyAsType_Throws_When_Requested_Type_Does_Not_Match() {
228
229
230
    LogManager runInfo;
    runInfo.addProperty("double_prop", 6.7); // Standard double property

231
232
    TS_ASSERT_THROWS(runInfo.getPropertyValueAsType<int>("double_prop"),
                     std::invalid_argument);
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
  void test_GetPropertyAsSingleValue_SingleValue_DoubleType() {
    doTest_GetPropertyAsSingleValue_SingleType<double>(1.0);
  }

  void test_GetPropertyAsSingleValue_SingleValue_FloatType() {
    doTest_GetPropertyAsSingleValue_SingleType<float>(1.0F);
  }

  void test_GetPropertyAsSingleValue_SingleValue_Int32Type() {
    doTest_GetPropertyAsSingleValue_SingleType<int32_t>(1);
  }

  void test_GetPropertyAsSingleValue_SingleValue_Int64Type() {
    doTest_GetPropertyAsSingleValue_SingleType<int64_t>(1L);
  }

  void test_GetPropertyAsSingleValue_SingleValue_Uint32Type() {
    doTest_GetPropertyAsSingleValue_SingleType<uint32_t>(1U);
  }

  void test_GetPropertyAsSingleValue_SingleValue_Uint64Type() {
    doTest_GetPropertyAsSingleValue_SingleType<uint64_t>(1UL);
  }

259
  void test_GetPropertyAsSingleValue_SingleValue_StringType() {
260
261
262
263
264
    LogManager runInfo;
    const std::string name = "string_prop", value = "1";
    runInfo.addProperty<std::string>(name, value);
    double result = std::nan("1");
    TS_ASSERT_THROWS_NOTHING(result = runInfo.getPropertyAsSingleValue(name));
265
    TS_ASSERT_DELTA(1.0, result, 1e-12);
266
267
  }

268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
  void test_GetPropertyAsIntegerValue_SingleValue_Int32Type() {
    doTest_GetPropertyAsIntegerValue<int32_t>(1);
  }

  void test_GetPropertyAsIntegerValue_SingleValue_Int64Type() {
    doTest_GetPropertyAsIntegerValue<int64_t>(1L);
  }

  void test_GetPropertyAsIntegerValue_SingleValue_Uint32Type() {
    doTest_GetPropertyAsIntegerValue<uint32_t>(1U);
  }

  void test_GetPropertyAsIntegerValue_SingleValue_Uint64Type() {
    doTest_GetPropertyAsIntegerValue<uint64_t>(1UL);
  }

  void test_GetPropertyAsSingleInteger_DoubleType_Throws() {
    LogManager runInfo;
    const std::string name = "T_prop";
    runInfo.addProperty<double>(name, 1.0);
    TS_ASSERT_THROWS(runInfo.getPropertyAsIntegerValue(name),
                     std::invalid_argument);
  }

  void test_GetPropertyAsSingleInteger_Throws_for_nonexistant_property() {
    LogManager runInfo;
    TS_ASSERT_THROWS(runInfo.getPropertyAsIntegerValue("T_prop"),
                     Exception::NotFoundError);
  }

298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
  void test_GetPropertyAsSingleValue_TimeSeries_DoubleType() {
    doTest_GetPropertyAsSingleValue_TimeSeriesType<double>();
  }

  void test_GetPropertyAsSingleValue_TimeSeries_FloatType() {
    doTest_GetPropertyAsSingleValue_TimeSeriesType<float>();
  }

  void test_GetPropertyAsSingleValue_TimeSeries_Int32Type() {
    doTest_GetPropertyAsSingleValue_TimeSeriesType<int32_t>();
  }

  void test_GetPropertyAsSingleValue_TimeSeries_Int64Type() {
    doTest_GetPropertyAsSingleValue_TimeSeriesType<int64_t>();
  }

  void test_GetPropertyAsSingleValue_TimeSeries_Uint32Type() {
    doTest_GetPropertyAsSingleValue_TimeSeriesType<uint32_t>();
  }

  void test_GetPropertyAsSingleValue_TimeSeries_Uint64Type() {
    doTest_GetPropertyAsSingleValue_TimeSeriesType<uint64_t>();
  }

322
  void test_GetPropertyAsSingleValue_Throws_If_String_Is_Invalid() {
323
    LogManager runInfo;
324
    const std::string name = "string_prop";
325
326
327
328
329
330
331
332
333
334
335
336
    runInfo.addProperty<std::string>(name, "hello"); // not a number

    TS_ASSERT_THROWS(runInfo.getPropertyAsSingleValue(name),
                     std::invalid_argument);
  }

  void
  test_GetPropertyAsSingleValue_Throws_If_Type_Is_Not_Numeric_Or_TimeSeries_Numeric_Or_Valid_String() {
    LogManager runInfo;
    const std::string name = "bool_prop";
    const bool value(false);
    runInfo.addProperty<bool>(name, value); // Adds a bool property
337

338
339
    TS_ASSERT_THROWS(runInfo.getPropertyAsSingleValue(name),
                     std::invalid_argument);
340
341
  }

342
343
  void
  test_GetPropertyAsSingleValue_Returns_Simple_Mean_By_Default_For_Time_Series() {
344
345
    LogManager runInfo;
    const std::string name = "series";
346
    addTestTimeSeries<double>(runInfo, name);
347
348

    const double expectedValue(13.0);
349
350
    TS_ASSERT_DELTA(runInfo.getPropertyAsSingleValue(name), expectedValue,
                    1e-12);
351
352
  }

353
354
  void
  test_GetPropertyAsSingleValue_Returns_Correct_SingleValue_For_Each_StatisticType() {
355
356
    LogManager runInfo;
    const std::string name = "series";
357
    addTestTimeSeries<double>(runInfo, name);
358
359
360
361
362
363
364
365
366
367
368
369
370

    TS_ASSERT_DELTA(runInfo.getPropertyAsSingleValue(name, Math::Mean), 13.0,
                    1e-12);
    TS_ASSERT_DELTA(runInfo.getPropertyAsSingleValue(name, Math::Minimum), 2.0,
                    1e-12);
    TS_ASSERT_DELTA(runInfo.getPropertyAsSingleValue(name, Math::Maximum), 24.0,
                    1e-12);
    TS_ASSERT_DELTA(runInfo.getPropertyAsSingleValue(name, Math::FirstValue),
                    2.0, 1e-12);
    TS_ASSERT_DELTA(runInfo.getPropertyAsSingleValue(name, Math::LastValue),
                    24.0, 1e-12);
    TS_ASSERT_DELTA(runInfo.getPropertyAsSingleValue(name, Math::Median), 13.0,
                    1e-12);
371
372
  }

373
374
  void
  test_GetPropertyAsSingleValue_Returns_Expected_Single_Value_On_Successive_Calls_With_Different_Stat_Types() {
375
376
    LogManager run;
    const std::string name = "series";
377
    addTestTimeSeries<double>(run, name);
378

379
380
381
382
    TS_ASSERT_EQUALS(run.getPropertyAsSingleValue(name, Math::Mean), 13.0);
    TS_ASSERT_EQUALS(run.getPropertyAsSingleValue(name, Math::Mean), 13.0);
    TS_ASSERT_EQUALS(run.getPropertyAsSingleValue(name, Math::Minimum), 2.0);
    TS_ASSERT_EQUALS(run.getPropertyAsSingleValue(name, Math::Minimum), 2.0);
383
384
  }

385
386
  void
  test_GetPropertyAsSingleValue_Returns_Correct_Value_On_Second_Call_When_Log_Has_Been_Replaced() {
387
388
389
390
391
392
393
394
395
    LogManager runInfo;
    const std::string name = "double";
    double value(5.1);
    runInfo.addProperty(name, value);

    TS_ASSERT_EQUALS(runInfo.getPropertyAsSingleValue(name), value);

    // Replace the log with a different value
    value = 10.3;
396
    runInfo.addProperty(name, value, /*overwrite*/ true);
397
398
399
400

    TS_ASSERT_EQUALS(runInfo.getPropertyAsSingleValue(name), value);
  }

401
402
403
  void test_clear() {
    // Set up a Run object with 3 properties in it (1 time series, 2 single
    // value)
404
405
406
    LogManager runInfo;
    const std::string stringProp("aStringProp");
    const std::string stringVal("testing");
407
    runInfo.addProperty(stringProp, stringVal);
408
    const std::string intProp("anIntProp");
409
    runInfo.addProperty(intProp, 99);
410
    const std::string tspProp("tsp");
411
    addTestTimeSeries<double>(runInfo, "tsp");
412
413

    // Check it's set up right
414
    TS_ASSERT_EQUALS(runInfo.getProperties().size(), 3);
415
    auto tsp = runInfo.getTimeSeriesProperty<double>(tspProp);
416
    TS_ASSERT_EQUALS(tsp->realSize(), 10)
417
418

    // Do the clearing work
419
    TS_ASSERT_THROWS_NOTHING(runInfo.clearTimeSeriesLogs());
420
421

    // Check the time-series property is empty, but not the others
422
423
424
425
426
    TS_ASSERT_EQUALS(runInfo.getProperties().size(), 3);
    TS_ASSERT_EQUALS(tsp->realSize(), 0)
    TS_ASSERT_EQUALS(runInfo.getPropertyValueAsType<std::string>(stringProp),
                     stringVal);
    TS_ASSERT_EQUALS(runInfo.getPropertyValueAsType<int>(intProp), 99);
427
428
  }

429
430
431
  void clearOutdatedTimeSeriesLogValues() {
    // Set up a Run object with 3 properties in it (1 time series, 2 single
    // value)
432
433
434
    LogManager runInfo;
    const std::string stringProp("aStringProp");
    const std::string stringVal("testing");
435
    runInfo.addProperty(stringProp, stringVal);
436
    const std::string intProp("anIntProp");
437
    runInfo.addProperty(intProp, 99);
438
    const std::string tspProp("tsp");
439
    addTestTimeSeries<double>(runInfo, "tsp");
440

441
    // Check it's set up right
442
    TS_ASSERT_EQUALS(runInfo.getProperties().size(), 3);
443
    auto tsp = runInfo.getTimeSeriesProperty<double>(tspProp);
444
    TS_ASSERT_EQUALS(tsp->realSize(), 10);
445
446
447
448
449

    auto lastTime = tsp->lastTime();
    auto lastValue = tsp->lastValue();

    // Do the clearing work
450
    TS_ASSERT_THROWS_NOTHING(runInfo.clearOutdatedTimeSeriesLogValues());
451
452

    // Check the time-series property has 1 entry, & the others are unchanged
453
454
455
456
457
458
459
    TS_ASSERT_EQUALS(runInfo.getProperties().size(), 3);
    TS_ASSERT_EQUALS(tsp->realSize(), 1);
    TS_ASSERT_EQUALS(tsp->firstTime(), lastTime);
    TS_ASSERT_EQUALS(tsp->firstValue(), lastValue);
    TS_ASSERT_EQUALS(runInfo.getPropertyValueAsType<std::string>(stringProp),
                     stringVal);
    TS_ASSERT_EQUALS(runInfo.getPropertyValueAsType<int>(intProp), 99);
460
  }
461
462

  /** Save and load to NXS file */
463
  void test_nexus() {
464
465
466
467
468
    NexusTestHelper th(true);
    th.createFile("LogManagerTest.nxs");

    LogManager run1;
    addTimeSeriesEntry(run1, "double_series", 45.0);
469
470
471
472
    run1.addProperty(new PropertyWithValue<int>("int_val", 1234));
    run1.addProperty(new PropertyWithValue<std::string>(
        "string_val", "help_im_stuck_in_a_log_file"));
    run1.addProperty(new PropertyWithValue<double>("double_val", 5678.9));
473
474
475
476
477
478
479
480
481
482
483
484
485
486
    addTimeSeriesEntry(run1, "phi", 12.3);
    addTimeSeriesEntry(run1, "chi", 45.6);
    addTimeSeriesEntry(run1, "omega", 78.9);
    addTimeSeriesEntry(run1, "proton_charge", 78.9);

    run1.saveNexus(th.file, "logs");
    th.file->openGroup("logs", "NXgroup");
    th.file->makeGroup("junk_to_ignore", "NXmaterial");
    th.file->makeGroup("more_junk_to_ignore", "NXsample");

    // ---- Now re-load the same and compare ------
    th.reopenFile();
    LogManager run2;
    run2.loadNexus(th.file, "logs");
487
488
489
490
    TS_ASSERT(run2.hasProperty("double_series"));
    TS_ASSERT(run2.hasProperty("int_val"));
    TS_ASSERT(run2.hasProperty("string_val"));
    TS_ASSERT(run2.hasProperty("double_val"));
491
492
    // This test both uses the goniometer axes AND looks up some values.

493
494
    // Reload without opening the group (for backwards-compatible reading of old
    // files)
495
496
497
    LogManager run3;
    th.file->openGroup("logs", "NXgroup");
    run3.loadNexus(th.file, "");
498
499
500
501
    TS_ASSERT(run3.hasProperty("double_series"));
    TS_ASSERT(run3.hasProperty("int_val"));
    TS_ASSERT(run3.hasProperty("string_val"));
    TS_ASSERT(run3.hasProperty("double_val"));
502
503
504
  }

  /** Check for loading the old way of saving proton_charge */
505
  void test_legacy_nexus() {
506
507
508
509
510
511
512
513
514
    NexusTestHelper th(true);
    th.createFile("LogManagerTest.nxs");
    th.file->makeGroup("sample", "NXsample", 1);
    th.file->writeData("proton_charge", 1.234);
    th.reopenFile();
    th.file->openGroup("sample", "NXsample");
    LogManager run3;
    run3.loadNexus(th.file, "");
  }
515
516
517
518
519
520
521
522
523
524
525

private:
  template <typename T>
  void doTest_GetPropertyAsSingleValue_SingleType(const T value) {
    LogManager runInfo;
    const std::string name = "T_prop";
    runInfo.addProperty<T>(name, value);
    double result = std::nan("1");
    TS_ASSERT_THROWS_NOTHING(result = runInfo.getPropertyAsSingleValue(name));
    TS_ASSERT_EQUALS(value, static_cast<T>(result));
  }
526
527
528
529
530

  template <typename T> void doTest_GetPropertyAsSingleValue_TimeSeriesType() {
    LogManager runInfo;
    const std::string name = "T_series";
    addTestTimeSeries<T>(runInfo, name);
531
    const double expectedValue(13.0);
532
    TS_ASSERT_DELTA(
533
        runInfo.getPropertyAsSingleValue(name, Mantid::Kernel::Math::Mean),
534
        expectedValue, 1e-12);
535
  }
536
537
538
539
540
541
542
543
544
545

  template <typename T> void doTest_GetPropertyAsIntegerValue(const T value) {
    LogManager runInfo;
    const std::string name = "T_prop";
    runInfo.addProperty<T>(name, value);
    int result(-1);
    result = runInfo.getPropertyAsIntegerValue(name);
    TS_ASSERT_THROWS_NOTHING(result = runInfo.getPropertyAsIntegerValue(name));
    TS_ASSERT_EQUALS(value, static_cast<T>(result));
  }
546
547
548
549
550
551
};

//---------------------------------------------------------------------------------------
// Performance test
//---------------------------------------------------------------------------------------

552
class LogManagerTestPerformance : public CxxTest::TestSuite {
553
554
555
public:
  // This pair of boilerplate methods prevent the suite being created statically
  // This means the constructor isn't called when running other tests
556
557
558
559
  static LogManagerTestPerformance *createSuite() {
    return new LogManagerTestPerformance();
  }
  static void destroySuite(LogManagerTestPerformance *suite) { delete suite; }
560

561
  LogManagerTestPerformance() : m_testRun(), m_propName("test") {
562
    addTestTimeSeries<double>(m_testRun, m_propName);
563
564
  }

565
  void test_Accessing_Single_Value_From_Times_Series_A_Large_Number_Of_Times() {
566
    double value(0.0);
567
    for (size_t i = 0; i < 20000; ++i) {
568
569
570
571
572
573
574
575
576
577
578
      value = m_testRun.getPropertyAsSingleValue(m_propName);
    }
    // Enure variable is used so that it is not optimised away by the compiler
    value += 1.0;
  }

  LogManager m_testRun;
  std::string m_propName;
};

#endif