LogManagerTest.h 21.4 KB
Newer Older
1
2
3
4
#ifndef LOG_MANAGER_TEST_H_
#define LOG_MANAGER_TEST_H_

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

using namespace Mantid::Kernel;
using namespace Mantid::API;
using namespace Mantid::Geometry;
19
using namespace Mantid::Types;
20
21

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

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

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

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

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

89
  void testRemoveLogData() {
90
    LogManager runInfo;
91

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

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

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

144
  void testEndTime() {
145
146
    LogManager runInfo;
    // Nothing there yet
147
    TS_ASSERT_THROWS(runInfo.endTime(), std::runtime_error);
148
149
    // Add run_end and see that get picked up
    const std::string run_end("2013-12-19T13:38:00");
150
    auto run_end_prop = new PropertyWithValue<std::string>("run_end", run_end);
151
    runInfo.addProperty(run_end_prop);
152
153
    TS_ASSERT_EQUALS(runInfo.endTime(),
                     DateAndTimeHelpers::createFromISO8601(run_end));
154
155
    // Add end_time and see that get picked up in preference
    const std::string end_time("2013-12-19T13:40:00");
156
157
    auto end_time_prop =
        new PropertyWithValue<std::string>("end_time", end_time);
158
    runInfo.addProperty(end_time_prop);
159
160
    TS_ASSERT_EQUALS(runInfo.endTime(),
                     DateAndTimeHelpers::createFromISO8601(end_time));
161
162
163
164

    // Set run_end back to valid value and make end_time contain nonsense
    run_end_prop->setValue(run_end);
    end_time_prop->setValue("__");
165
166
    TS_ASSERT_EQUALS(runInfo.endTime(),
                     DateAndTimeHelpers::createFromISO8601(run_end));
167
168
    // Now make end_time a completely different property type
    runInfo.removeProperty("end_time");
169
    runInfo.addProperty(new PropertyWithValue<double>("end_time", 3.33));
170
171
    TS_ASSERT_EQUALS(runInfo.endTime(),
                     DateAndTimeHelpers::createFromISO8601(run_end));
172
173
    // Now make run_end something invalid
    run_end_prop->setValue("notADate");
174
    TS_ASSERT_THROWS(runInfo.endTime(), std::runtime_error);
175
176
    // And check things if it's the wrong property type
    runInfo.removeProperty("run_end");
177
178
    addTimeSeriesEntry(runInfo, "run_end", 4.44);
    TS_ASSERT_THROWS(runInfo.endTime(), std::runtime_error);
179
180
  }

181
  void testMemory() {
182
    LogManager runInfo;
183
184
    TS_ASSERT_EQUALS(runInfo.getMemorySize(), 0);

185
186
187
    Property *p = new ConcreteProperty();
    runInfo.addProperty(p);

188
189
    TS_ASSERT_EQUALS(runInfo.getMemorySize(),
                     sizeof(ConcreteProperty) + sizeof(void *));
190
191
  }

192
  void test_GetTimeSeriesProperty_Returns_TSP_When_Log_Exists() {
193
    LogManager runInfo;
194
    const std::string &name = "double_time_series";
195
196
197
    const double value = 10.9;
    addTimeSeriesEntry(runInfo, name, value);

198
    TimeSeriesProperty<double> *tsp(NULL);
199
200
201
202
    TS_ASSERT_THROWS_NOTHING(tsp = runInfo.getTimeSeriesProperty<double>(name));
    TS_ASSERT_DELTA(tsp->firstValue(), value, 1e-12);
  }

203
  void test_GetTimeSeriesProperty_Throws_When_Log_Does_Not_Exist() {
204
    LogManager runInfo;
205
206
    TS_ASSERT_THROWS(runInfo.getTimeSeriesProperty<double>("not_a_log"),
                     Exception::NotFoundError);
207
208
  }

209
210
  void
  test_GetTimeSeriesProperty_Throws_When_Log_Exists_But_Is_Not_Correct_Type() {
211
    LogManager runInfo;
212
    const std::string &name = "double_prop";
213
214
    runInfo.addProperty(name, 5.6); // Standard double property

215
216
    TS_ASSERT_THROWS(runInfo.getTimeSeriesProperty<double>(name),
                     std::invalid_argument);
217
218
  }

219
  void test_GetPropertyAsType_Throws_When_Property_Does_Not_Exist() {
220
    LogManager runInfo;
221
222
    TS_ASSERT_THROWS(runInfo.getPropertyValueAsType<double>("not_a_log"),
                     Exception::NotFoundError);
223
224
  }

225
  void test_GetPropertyAsType_Returns_Expected_Value_When_Type_Is_Correct() {
226
    LogManager runInfo;
227
    const std::string &name = "double_prop";
228
229
230
231
    const double value = 5.6;
    runInfo.addProperty(name, value); // Standard double property

    double retrieved(0.0);
232
233
    TS_ASSERT_THROWS_NOTHING(retrieved =
                                 runInfo.getPropertyValueAsType<double>(name));
234
235
236
    TS_ASSERT_DELTA(retrieved, value, 1e-12);
  }

237
  void test_GetPropertyAsType_Throws_When_Requested_Type_Does_Not_Match() {
238
239
240
    LogManager runInfo;
    runInfo.addProperty("double_prop", 6.7); // Standard double property

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

269
  void test_GetPropertyAsSingleValue_SingleValue_StringType() {
270
271
272
273
274
    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));
275
    TS_ASSERT_DELTA(1.0, result, 1e-12);
276
277
  }

278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
  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);
  }

308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
  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>();
  }

332
  void test_GetPropertyAsSingleValue_Throws_If_String_Is_Invalid() {
333
    LogManager runInfo;
334
    const std::string name = "string_prop";
335
336
337
338
339
340
341
342
343
344
345
346
    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
347

348
349
    TS_ASSERT_THROWS(runInfo.getPropertyAsSingleValue(name),
                     std::invalid_argument);
350
351
  }

352
353
  void
  test_GetPropertyAsSingleValue_Returns_Simple_Mean_By_Default_For_Time_Series() {
354
355
    LogManager runInfo;
    const std::string name = "series";
356
    addTestTimeSeries<double>(runInfo, name);
357
358

    const double expectedValue(13.0);
359
360
    TS_ASSERT_DELTA(runInfo.getPropertyAsSingleValue(name), expectedValue,
                    1e-12);
361
362
  }

363
364
  void
  test_GetPropertyAsSingleValue_Returns_Correct_SingleValue_For_Each_StatisticType() {
365
366
    LogManager runInfo;
    const std::string name = "series";
367
    addTestTimeSeries<double>(runInfo, name);
368
369
370
371
372
373
374
375
376
377
378
379
380

    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);
381
382
  }

383
384
  void
  test_GetPropertyAsSingleValue_Returns_Expected_Single_Value_On_Successive_Calls_With_Different_Stat_Types() {
385
386
    LogManager run;
    const std::string name = "series";
387
    addTestTimeSeries<double>(run, name);
388

389
390
391
392
    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);
393
394
  }

395
396
  void
  test_GetPropertyAsSingleValue_Returns_Correct_Value_On_Second_Call_When_Log_Has_Been_Replaced() {
397
398
399
400
401
402
403
404
405
    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;
406
    runInfo.addProperty(name, value, /*overwrite*/ true);
407
408
409
410

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

411
412
413
  void test_clear() {
    // Set up a Run object with 3 properties in it (1 time series, 2 single
    // value)
414
415
416
    LogManager runInfo;
    const std::string stringProp("aStringProp");
    const std::string stringVal("testing");
417
    runInfo.addProperty(stringProp, stringVal);
418
    const std::string intProp("anIntProp");
419
    runInfo.addProperty(intProp, 99);
420
    const std::string tspProp("tsp");
421
    addTestTimeSeries<double>(runInfo, "tsp");
422
423

    // Check it's set up right
424
    TS_ASSERT_EQUALS(runInfo.getProperties().size(), 3);
425
    auto tsp = runInfo.getTimeSeriesProperty<double>(tspProp);
426
    TS_ASSERT_EQUALS(tsp->realSize(), 10)
427
428

    // Do the clearing work
429
    TS_ASSERT_THROWS_NOTHING(runInfo.clearTimeSeriesLogs());
430
431

    // Check the time-series property is empty, but not the others
432
433
434
435
436
    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);
437
438
  }

439
440
441
  void clearOutdatedTimeSeriesLogValues() {
    // Set up a Run object with 3 properties in it (1 time series, 2 single
    // value)
442
443
444
    LogManager runInfo;
    const std::string stringProp("aStringProp");
    const std::string stringVal("testing");
445
    runInfo.addProperty(stringProp, stringVal);
446
    const std::string intProp("anIntProp");
447
    runInfo.addProperty(intProp, 99);
448
    const std::string tspProp("tsp");
449
    addTestTimeSeries<double>(runInfo, "tsp");
450

451
    // Check it's set up right
452
    TS_ASSERT_EQUALS(runInfo.getProperties().size(), 3);
453
    auto tsp = runInfo.getTimeSeriesProperty<double>(tspProp);
454
    TS_ASSERT_EQUALS(tsp->realSize(), 10);
455
456
457
458
459

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

    // Do the clearing work
460
    TS_ASSERT_THROWS_NOTHING(runInfo.clearOutdatedTimeSeriesLogValues());
461
462

    // Check the time-series property has 1 entry, & the others are unchanged
463
464
465
466
467
468
469
    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);
470
  }
471
472

  /** Save and load to NXS file */
473
  void test_nexus() {
474
475
476
477
478
    NexusTestHelper th(true);
    th.createFile("LogManagerTest.nxs");

    LogManager run1;
    addTimeSeriesEntry(run1, "double_series", 45.0);
479
480
481
482
    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));
483
484
485
486
487
488
489
490
491
492
493
494
495
496
    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");
497
498
499
500
    TS_ASSERT(run2.hasProperty("double_series"));
    TS_ASSERT(run2.hasProperty("int_val"));
    TS_ASSERT(run2.hasProperty("string_val"));
    TS_ASSERT(run2.hasProperty("double_val"));
501
502
    // This test both uses the goniometer axes AND looks up some values.

503
504
    // Reload without opening the group (for backwards-compatible reading of old
    // files)
505
506
507
    LogManager run3;
    th.file->openGroup("logs", "NXgroup");
    run3.loadNexus(th.file, "");
508
509
510
511
    TS_ASSERT(run3.hasProperty("double_series"));
    TS_ASSERT(run3.hasProperty("int_val"));
    TS_ASSERT(run3.hasProperty("string_val"));
    TS_ASSERT(run3.hasProperty("double_val"));
512
513
514
  }

  /** Check for loading the old way of saving proton_charge */
515
  void test_legacy_nexus() {
516
517
518
519
520
521
522
523
524
    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, "");
  }
525
526
527
528
529
530
531
532
533
534
535

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));
  }
536
537
538
539
540

  template <typename T> void doTest_GetPropertyAsSingleValue_TimeSeriesType() {
    LogManager runInfo;
    const std::string name = "T_series";
    addTestTimeSeries<T>(runInfo, name);
541
    const double expectedValue(13.0);
542
    TS_ASSERT_DELTA(
543
        runInfo.getPropertyAsSingleValue(name, Mantid::Kernel::Math::Mean),
544
        expectedValue, 1e-12);
545
  }
546
547
548
549
550
551
552
553
554
555

  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));
  }
556
557
558
559
560
561
};

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

562
class LogManagerTestPerformance : public CxxTest::TestSuite {
563
564
565
public:
  // This pair of boilerplate methods prevent the suite being created statically
  // This means the constructor isn't called when running other tests
566
567
568
569
  static LogManagerTestPerformance *createSuite() {
    return new LogManagerTestPerformance();
  }
  static void destroySuite(LogManagerTestPerformance *suite) { delete suite; }
570

571
  LogManagerTestPerformance() : m_testRun(), m_propName("test") {
572
    addTestTimeSeries<double>(m_testRun, m_propName);
573
574
  }

575
  void test_Accessing_Single_Value_From_Times_Series_A_Large_Number_Of_Times() {
576
    double value(0.0);
577
    for (size_t i = 0; i < 20000; ++i) {
578
579
580
581
582
583
584
585
586
587
588
      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