LogManagerTest.h 20.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
#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"
#include <cxxtest/TestSuite.h>
11
#include "MantidTestHelpers/NexusTestHelper.h"
12
#include "MantidGeometry/Instrument/Goniometer.h"
13
#include <cmath>
14
15
16
17
18
19

using namespace Mantid::Kernel;
using namespace Mantid::API;
using namespace Mantid::Geometry;

// Helper class
20
21
22
23
namespace {
class ConcreteProperty : public Property {
public:
  ConcreteProperty() : Property("Test", typeid(int)) {}
24
25
26
27
28
  ConcreteProperty *clone() const override {
    return new ConcreteProperty(*this);
  }
  bool isDefault() const override { return true; }
  std::string getDefault() const override {
29
    return "getDefault() is not implemented in this class";
30
  }
31
32
33
34
35
36
37
  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; }
38
39
};

40
template <typename T>
41
void addTestTimeSeries(LogManager &run, const std::string &name) {
42
  auto timeSeries = new TimeSeriesProperty<T>(name);
43
44
45
46
47
48
49
50
51
52
53
54
  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);
}
55
56
}

57
58
59
60
61
62
63
64
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 {
65
public:
66
  void testAddGetData() {
67
68
69
    LogManager runInfo;

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

    Property *pp = NULL;
73
74
75
76
77
78
79
80
81
82
83
84
    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]));
85
86
  }

87
  void testRemoveLogData() {
88
    LogManager runInfo;
89

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

230
231
    TS_ASSERT_THROWS(runInfo.getPropertyValueAsType<int>("double_prop"),
                     std::invalid_argument);
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
  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);
  }

258
  void test_GetPropertyAsSingleValue_SingleValue_StringType() {
259
260
261
262
263
    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));
264
    TS_ASSERT_DELTA(1.0, result, 1e-12);
265
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
  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);
  }

297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
  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>();
  }

321
  void test_GetPropertyAsSingleValue_Throws_If_String_Is_Invalid() {
322
    LogManager runInfo;
323
    const std::string name = "string_prop";
324
325
326
327
328
329
330
331
332
333
334
335
    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
336

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

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

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

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

    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);
370
371
  }

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

378
379
380
381
    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);
382
383
  }

384
385
  void
  test_GetPropertyAsSingleValue_Returns_Correct_Value_On_Second_Call_When_Log_Has_Been_Replaced() {
386
387
388
389
390
391
392
393
394
    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;
395
    runInfo.addProperty(name, value, /*overwrite*/ true);
396
397
398
399

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

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

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

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

    // Check the time-series property is empty, but not the others
421
422
423
424
425
    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);
426
427
  }

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

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

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

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

    // Check the time-series property has 1 entry, & the others are unchanged
452
453
454
455
456
457
458
    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);
459
  }
460
461

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

    LogManager run1;
    addTimeSeriesEntry(run1, "double_series", 45.0);
468
469
470
471
    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));
472
473
474
475
476
477
478
479
480
481
482
483
484
485
    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");
486
487
488
489
    TS_ASSERT(run2.hasProperty("double_series"));
    TS_ASSERT(run2.hasProperty("int_val"));
    TS_ASSERT(run2.hasProperty("string_val"));
    TS_ASSERT(run2.hasProperty("double_val"));
490
491
    // This test both uses the goniometer axes AND looks up some values.

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

  /** Check for loading the old way of saving proton_charge */
504
  void test_legacy_nexus() {
505
506
507
508
509
510
511
512
513
    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, "");
  }
514
515
516
517
518
519
520
521
522
523
524

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));
  }
525
526
527
528
529

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

  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));
  }
545
546
547
548
549
550
};

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

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

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

564
  void test_Accessing_Single_Value_From_Times_Series_A_Large_Number_Of_Times() {
565
    double value(0.0);
566
    for (size_t i = 0; i < 20000; ++i) {
567
568
569
570
571
572
573
574
575
576
577
      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