ComponentInfoTest.h 18.2 KB
Newer Older
Owen Arnold's avatar
Owen Arnold committed
1
2
#ifndef MANTID_GEOMETRY_COMPONENTINFOTEST_H_
#define MANTID_GEOMETRY_COMPONENTINFOTEST_H_
Owen Arnold's avatar
Owen Arnold committed
3
4
5

#include <cxxtest/TestSuite.h>

Owen Arnold's avatar
Owen Arnold committed
6
#include "MantidGeometry/Instrument/ComponentInfo.h"
7
#include "MantidGeometry/Instrument/DetectorInfo.h"
Owen Arnold's avatar
Owen Arnold committed
8
9
#include "MantidBeamline/ComponentInfo.h"
#include "MantidGeometry/IComponent.h"
10
#include "MantidGeometry/Instrument/InstrumentVisitor.h"
Owen Arnold's avatar
Owen Arnold committed
11
#include "MantidGeometry/Instrument/ObjComponent.h"
12
#include "MantidGeometry/Objects/CSGObject.h"
Owen Arnold's avatar
Owen Arnold committed
13
14
15
16
#include "MantidGeometry/Surfaces/Cylinder.h"
#include "MantidGeometry/Surfaces/Plane.h"
#include "MantidGeometry/Surfaces/Surface.h"
#include "MantidGeometry/Surfaces/Sphere.h"
17
#include "MantidKernel/Exception.h"
18
#include "MantidKernel/EigenConversionHelpers.h"
19
#include "MantidKernel/make_unique.h"
Owen Arnold's avatar
Owen Arnold committed
20
#include "MantidTestHelpers/ComponentCreationHelper.h"
Simon Heybrock's avatar
Simon Heybrock committed
21
#include <boost/make_shared.hpp>
Owen Arnold's avatar
Owen Arnold committed
22
#include <Eigen/Geometry>
Simon Heybrock's avatar
Simon Heybrock committed
23

24
25
using namespace Mantid;
using namespace Mantid::Kernel;
Owen Arnold's avatar
Owen Arnold committed
26
using namespace Mantid::Geometry;
27

28
29
namespace {

30
31
32
33
/*
 Helper function to create an ID -> index map from an ordered collection of IDs.
 First ID gets index of 0, subsequent ID entries increment index by 1.
*/
34
35
boost::shared_ptr<
    const std::unordered_map<Mantid::Geometry::ComponentID, size_t>>
36
37
38
39
40
41
42
43
44
45
makeComponentIDMap(const boost::shared_ptr<
    const std::vector<Mantid::Geometry::ComponentID>> &componentIds) {
  auto idMap = boost::make_shared<
      std::unordered_map<Mantid::Geometry::ComponentID, size_t>>();

  for (size_t i = 0; i < componentIds->size(); ++i) {
    (*idMap)[(*componentIds)[i]] = i;
  }
  return idMap;
}
Owen Arnold's avatar
Owen Arnold committed
46

47
boost::shared_ptr<CSGObject> createCappedCylinder() {
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  std::string C31 = "cx 0.5"; // cylinder x-axis radius 0.5
  std::string C32 = "px 1.2";
  std::string C33 = "px -3.2";

  // First create some surfaces
  std::map<int, boost::shared_ptr<Surface>> CylSurMap;
  CylSurMap[31] = boost::make_shared<Cylinder>();
  CylSurMap[32] = boost::make_shared<Plane>();
  CylSurMap[33] = boost::make_shared<Plane>();

  CylSurMap[31]->setSurface(C31);
  CylSurMap[32]->setSurface(C32);
  CylSurMap[33]->setSurface(C33);
  CylSurMap[31]->setName(31);
  CylSurMap[32]->setName(32);
  CylSurMap[33]->setName(33);

  // Capped cylinder (id 21)
  // using surface ids: 31 (cylinder) 32 (plane (top) ) and 33 (plane (base))
  std::string ObjCapCylinder = "-31 -32 33";

69
  auto retVal = boost::make_shared<CSGObject>();
70
71
72
73
74
75
  retVal->setObject(21, ObjCapCylinder);
  retVal->populate(CylSurMap);

  return retVal;
}

Owen Arnold's avatar
Owen Arnold committed
76
// Make a Beamline ComponentInfo for a single component
77
std::unique_ptr<Beamline::ComponentInfo> makeSingleBeamlineComponentInfo(
78
79
80
    Eigen::Vector3d position = Eigen::Vector3d{1, 1, 1},
    Eigen::Quaterniond rotation =
        Eigen::Quaterniond(Eigen::Affine3d::Identity().rotation()),
Owen Arnold's avatar
Owen Arnold committed
81
82
83
84
85
86
87
88
89
90
91
92
93
94
    Eigen::Vector3d scaleFactor = Eigen::Vector3d{1, 1, 1}) {

  auto detectorIndices =
      boost::make_shared<std::vector<size_t>>(); // No detectors in this example
  auto detectorRanges =
      boost::make_shared<std::vector<std::pair<size_t, size_t>>>();
  detectorRanges->push_back(
      std::make_pair(0, 0)); // One component with no detectors

  auto componentIndices = boost::make_shared<std::vector<size_t>>(
      std::vector<size_t>{0}); // No detectors in this example
  auto componentRanges =
      boost::make_shared<std::vector<std::pair<size_t, size_t>>>();
  componentRanges->push_back(
95
      std::make_pair(0, 1)); // One component with no sub-components
Owen Arnold's avatar
Owen Arnold committed
96
97
98
99
100
101
102
103
104
105
106

  auto parentIndices = boost::make_shared<const std::vector<size_t>>(
      std::vector<size_t>()); // These indices are invalid, but that's
                              // ok as not being tested here

  auto positions =
      boost::make_shared<std::vector<Eigen::Vector3d>>(1, position);
  auto rotations =
      boost::make_shared<std::vector<Eigen::Quaterniond>>(1, rotation);
  auto scaleFactors =
      boost::make_shared<std::vector<Eigen::Vector3d>>(1, scaleFactor);
107
  auto isStructuredBank = boost::make_shared<std::vector<bool>>(1, false);
Owen Arnold's avatar
Owen Arnold committed
108
109
  return Kernel::make_unique<Beamline::ComponentInfo>(
      detectorIndices, detectorRanges, componentIndices, componentRanges,
110
      parentIndices, positions, rotations, scaleFactors, isStructuredBank, -1,
111
      -1);
Owen Arnold's avatar
Owen Arnold committed
112
}
113
}
Owen Arnold's avatar
Owen Arnold committed
114
115
116

class ComponentInfoTest : public CxxTest::TestSuite {
public:
117
118
  // This pair of boilerplate methods prevent the suite being created
  // statically
Owen Arnold's avatar
Owen Arnold committed
119
120
121
122
  // This means the constructor isn't called when running other tests
  static ComponentInfoTest *createSuite() { return new ComponentInfoTest(); }
  static void destroySuite(ComponentInfoTest *suite) { delete suite; }

Owen Arnold's avatar
Owen Arnold committed
123
  void test_indexOf() {
124
125
    auto detectorIndices = boost::make_shared<
        std::vector<size_t>>(); // No detectors in this example
Owen Arnold's avatar
Owen Arnold committed
126
127
128
129
    auto detectorRanges =
        boost::make_shared<std::vector<std::pair<size_t, size_t>>>();
    detectorRanges->push_back(
        std::make_pair(0, 0)); // One component with no detectors
Owen Arnold's avatar
Owen Arnold committed
130
    detectorRanges->push_back(
Owen Arnold's avatar
Owen Arnold committed
131
        std::make_pair(0, 0)); // Another component with no detectors
132

133
134
135
136
137
138
    auto componentIndices = boost::make_shared<std::vector<size_t>>(
        std::vector<size_t>{0, 1}); // No detectors in this example
    auto componentRanges =
        boost::make_shared<std::vector<std::pair<size_t, size_t>>>();
    componentRanges->push_back(
        std::make_pair(0, 0)); // One component with no sub-components
Owen Arnold's avatar
Owen Arnold committed
139
140
    componentRanges->push_back(
        std::make_pair(0, 0)); // Another component with no subcomponents
141

Owen Arnold's avatar
Owen Arnold committed
142
143
144
145
    auto parentIndices = boost::make_shared<const std::vector<size_t>>(
        std::vector<size_t>{9, 9, 9}); // These indices are invalid, but that's
                                       // ok as not being tested here

146
147
    auto positions = boost::make_shared<std::vector<Eigen::Vector3d>>(2);
    auto rotations = boost::make_shared<std::vector<Eigen::Quaterniond>>(2);
148
    auto scaleFactors = boost::make_shared<std::vector<Eigen::Vector3d>>(2);
149
    auto isRectBank = boost::make_shared<std::vector<bool>>(2);
150
    auto internalInfo = Kernel::make_unique<Beamline::ComponentInfo>(
151
        detectorIndices, detectorRanges, componentIndices, componentRanges,
152
        parentIndices, positions, rotations, scaleFactors, isRectBank, -1, -1);
Owen Arnold's avatar
Owen Arnold committed
153
154
    Mantid::Geometry::ObjComponent comp1("component1");
    Mantid::Geometry::ObjComponent comp2("component2");
Owen Arnold's avatar
Owen Arnold committed
155

156
    auto componentIds =
157
        boost::make_shared<std::vector<Mantid::Geometry::ComponentID>>(
158
            std::vector<Mantid::Geometry::ComponentID>{&comp1, &comp2});
159
160

    auto shapes = boost::make_shared<
161
162
163
        std::vector<boost::shared_ptr<const Geometry::CSGObject>>>();
    shapes->push_back(boost::make_shared<const Geometry::CSGObject>());
    shapes->push_back(boost::make_shared<const Geometry::CSGObject>());
164

165
    ComponentInfo info(std::move(internalInfo), componentIds,
166
                       makeComponentIDMap(componentIds), shapes);
Owen Arnold's avatar
Owen Arnold committed
167
168
169
    TS_ASSERT_EQUALS(info.indexOf(comp1.getComponentID()), 0);
    TS_ASSERT_EQUALS(info.indexOf(comp2.getComponentID()), 1);
  }
Owen Arnold's avatar
Owen Arnold committed
170

171
  void test_copy_construction() {
Owen Arnold's avatar
Owen Arnold committed
172
    auto internalInfo = makeSingleBeamlineComponentInfo();
173
174
175
176
177
178
179
    Mantid::Geometry::ObjComponent comp1("component1", createCappedCylinder());

    auto componentIds =
        boost::make_shared<std::vector<Mantid::Geometry::ComponentID>>(
            std::vector<Mantid::Geometry::ComponentID>{&comp1});

    auto shapes = boost::make_shared<
180
        std::vector<boost::shared_ptr<const Geometry::CSGObject>>>();
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
    shapes->push_back(createCappedCylinder());

    ComponentInfo a(std::move(internalInfo), componentIds,
                    makeComponentIDMap(componentIds), shapes);

    // Make the copy
    ComponentInfo b = a;

    // Compare sizes
    TS_ASSERT_EQUALS(b.size(), a.size());
    // Shapes are the same
    TS_ASSERT_EQUALS(&b.shape(0), &a.shape(0));
    // IDs are the same
    TS_ASSERT_EQUALS(b.indexOf(&comp1), a.indexOf(&comp1));
  }

  void test_has_shape() {
Owen Arnold's avatar
Owen Arnold committed
198
    auto internalInfo = makeSingleBeamlineComponentInfo();
199
200
201
202
203
204
205
    Mantid::Geometry::ObjComponent comp1("component1", createCappedCylinder());

    auto componentIds =
        boost::make_shared<std::vector<Mantid::Geometry::ComponentID>>(
            std::vector<Mantid::Geometry::ComponentID>{&comp1});

    auto shapes = boost::make_shared<
206
        std::vector<boost::shared_ptr<const Geometry::CSGObject>>>();
207
208
209
210
211
212
213
    shapes->push_back(createCappedCylinder());

    ComponentInfo compInfo(std::move(internalInfo), componentIds,
                           makeComponentIDMap(componentIds), shapes);

    TS_ASSERT(compInfo.hasShape(0));
    // Nullify the shape of the component
214
    shapes->at(0) = boost::shared_ptr<const Geometry::CSGObject>(nullptr);
215
216
217
218
219
    TS_ASSERT(!compInfo.hasShape(0));
    TS_ASSERT_THROWS(compInfo.solidAngle(0, V3D{1, 1, 1}),
                     Mantid::Kernel::Exception::NullPointerException &);
  }

Owen Arnold's avatar
Owen Arnold committed
220
221
222
  void test_simple_solidAngle() {
    auto position = Eigen::Vector3d{0, 0, 0};
    // No rotation
223
    const double radius = 1.0;
Owen Arnold's avatar
Owen Arnold committed
224
    auto rotation = Eigen::Quaterniond(Eigen::Affine3d::Identity().rotation());
225

Owen Arnold's avatar
Owen Arnold committed
226
    auto internalInfo = makeSingleBeamlineComponentInfo(position, rotation);
Owen Arnold's avatar
Owen Arnold committed
227
    Mantid::Geometry::ObjComponent comp1("component1", createCappedCylinder());
228

Owen Arnold's avatar
Owen Arnold committed
229
230
231
232
233
    auto componentIds =
        boost::make_shared<std::vector<Mantid::Geometry::ComponentID>>(
            std::vector<Mantid::Geometry::ComponentID>{&comp1});

    auto shapes = boost::make_shared<
234
        std::vector<boost::shared_ptr<const Geometry::CSGObject>>>();
Owen Arnold's avatar
Owen Arnold committed
235
236
237
238
239
240
241
242
243
244
245
246
247
248
    shapes->push_back(ComponentCreationHelper::createSphere(radius));

    ComponentInfo info(std::move(internalInfo), componentIds,
                       makeComponentIDMap(componentIds), shapes);

    double satol = 1e-9; // tolerance for solid angle

    // Put observer on surface of sphere and solid angle is 2PI
    V3D observer{radius, 0, 0};
    TS_ASSERT_DELTA(info.solidAngle(0, observer), 2 * M_PI, satol);
    // Put observer at center of sphere and solid angle is full 4PI square
    // radians
    observer = V3D{0, 0, 0};
    TS_ASSERT_DELTA(info.solidAngle(0, observer), 4 * M_PI, satol);
249
    // Nullify  the shape and retest solid angle
250
    shapes->at(0) = boost::shared_ptr<const Geometry::CSGObject>(nullptr);
251
252
    TS_ASSERT_THROWS(info.solidAngle(0, observer),
                     Mantid::Kernel::Exception::NullPointerException &);
Owen Arnold's avatar
Owen Arnold committed
253
254
255
256
257
258
259
260
  }

  // Test adapted from ObjComponentTest
  void test_solidAngle() {

    auto position = Eigen::Vector3d{10, 0, 0};
    auto rotation = Eigen::Quaterniond(
        Eigen::AngleAxisd(M_PI / 2, Eigen::Vector3d::UnitZ()));
Owen Arnold's avatar
Owen Arnold committed
261
    auto internalInfo = makeSingleBeamlineComponentInfo(position, rotation);
Owen Arnold's avatar
Owen Arnold committed
262
263
264
265
266
267
268
    Mantid::Geometry::ObjComponent comp1("component1", createCappedCylinder());

    auto componentIds =
        boost::make_shared<std::vector<Mantid::Geometry::ComponentID>>(
            std::vector<Mantid::Geometry::ComponentID>{&comp1});

    auto shapes = boost::make_shared<
269
        std::vector<boost::shared_ptr<const Geometry::CSGObject>>>();
Owen Arnold's avatar
Owen Arnold committed
270
271
272
273
274
275
276
277
    shapes->push_back(createCappedCylinder());

    ComponentInfo info(std::move(internalInfo), componentIds,
                       makeComponentIDMap(componentIds), shapes);

    double satol = 2e-2; // tolerance for solid angle
    TS_ASSERT_DELTA(info.solidAngle(0, V3D(10, 1.7, 0)), 1.840302, satol);
  }
278

279
  void test_boundingBox_single_component() {
280

281
282
    const double radius = 2;
    Eigen::Vector3d position{1, 1, 1};
283
    auto internalInfo = makeSingleBeamlineComponentInfo(position);
284
285
    Mantid::Geometry::ObjComponent comp1(
        "component1", ComponentCreationHelper::createSphere(radius));
286

287
288
289
290
291
    auto componentIds =
        boost::make_shared<std::vector<Mantid::Geometry::ComponentID>>(
            std::vector<Mantid::Geometry::ComponentID>{&comp1});

    auto shapes = boost::make_shared<
292
        std::vector<boost::shared_ptr<const Geometry::CSGObject>>>();
293
294
295
296
297
    shapes->push_back(ComponentCreationHelper::createSphere(radius));

    ComponentInfo componentInfo(std::move(internalInfo), componentIds,
                                makeComponentIDMap(componentIds), shapes);

298
    BoundingBox boundingBox = componentInfo.boundingBox(0 /*componentIndex*/);
299
300
301
302
303
304
305

    TS_ASSERT((boundingBox.minPoint() -
               (Kernel::V3D{position[0] - radius, position[1] - radius,
                            position[2] - radius})).norm() < 1e-9);
    TS_ASSERT((boundingBox.maxPoint() -
               (Kernel::V3D{position[0] + radius, position[1] + radius,
                            position[2] + radius})).norm() < 1e-9);
306
    // Nullify shape and retest BoundingBox
307
    shapes->at(0) = boost::shared_ptr<const Geometry::CSGObject>(nullptr);
308
    boundingBox = componentInfo.boundingBox(0);
309
    TS_ASSERT(boundingBox.isNull());
310
311
312
  }

  void test_boundingBox_complex() {
313
314
    const V3D sourcePos(-1, 0, 0);
    const V3D samplePos(0, 0, 0);
315
316
317
318
319
320
    const V3D detectorPos(11, 0, 0);
    const double radius = 0.01; // See helper creation method for definition
    // Create a very basic real instrument to visit
    auto instrument = ComponentCreationHelper::createMinimalInstrument(
        sourcePos, samplePos, detectorPos);

321
322
323
324
    // CompAssembly (and hence Instrument 1.0) has getter and setter for
    // position!
    instrument->setPos(samplePos);

325
326
327
    auto wrappers = InstrumentVisitor::makeWrappers(*instrument);
    const auto &componentInfo = std::get<0>(wrappers);
    // Check bounding box of detector
328
    auto boundingBox = componentInfo->boundingBox(0 /*detector index*/);
329
330
331
332
333
334
335
336
    TS_ASSERT((boundingBox.minPoint() -
               (Kernel::V3D{detectorPos[0] - radius, detectorPos[1] - radius,
                            detectorPos[2] - radius})).norm() < 1e-9);
    TS_ASSERT((boundingBox.maxPoint() -
               (Kernel::V3D{detectorPos[0] + radius, detectorPos[1] + radius,
                            detectorPos[2] + radius})).norm() < 1e-9);

    // Check bounding box of root (instrument)
337
    boundingBox = componentInfo->boundingBox(componentInfo->root() /*Root*/);
338
339
340

    // min in the sample (source is ignored by design in instrument 1.0 and
    // instrument 2.0).
341
    TS_ASSERT((boundingBox.minPoint() -
342
343
               (Kernel::V3D{samplePos[0] - radius, samplePos[1] - radius,
                            samplePos[2] - radius})).norm() < 1e-9);
344
345
346
347
348
    // max is the detector
    TS_ASSERT((boundingBox.maxPoint() -
               (Kernel::V3D{detectorPos[0] + radius, detectorPos[1] + radius,
                            detectorPos[2] + radius})).norm() < 1e-9);
  }
349

350
  void test_boundingBox_around_rectangular_bank() {
351
352
353
354
355
356
357
358
359
360
361

    auto instrument = ComponentCreationHelper::createTestInstrumentRectangular(
        1 /*1 bank*/, 10 /*10 by 10*/);

    // CompAssembly (and hence Instrument 1.0) has getter and setter for
    // position!
    instrument->setPos(instrument->getSample()->getPos());

    auto wrappers = InstrumentVisitor::makeWrappers(*instrument);
    const auto &componentInfo = std::get<0>(wrappers);
    // Check bounding box of root (instrument)
362
363
364
    auto boundingBoxRoot =
        componentInfo->boundingBox(componentInfo->root() /*Root*/
                                   );
365
    // min Z in the sample
366
367
    auto boundingBoxSample =
        componentInfo->boundingBox(componentInfo->sample());
368
369
370
371
372
    TS_ASSERT((boundingBoxRoot.minPoint().Z() -
               boundingBoxSample.minPoint().Z()) < 1e-9);

    // max is the Rectangular bank
    auto bankIndex = componentInfo->root() - 3;
373
    TS_ASSERT(componentInfo->isStructuredBank(bankIndex));
374
    auto boundingBoxBank = componentInfo->boundingBox(bankIndex);
375
376
377
    TS_ASSERT((boundingBoxRoot.maxPoint() - boundingBoxBank.maxPoint()).norm() <
              1e-9);
  }
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433

  void test_boundingBox_complex_rectangular_bank_setup() {

    /* y
     * |
     * |---z                        bank1
     *            source    sample              det
     *                                   bank2
     */

    Mantid::Geometry::Instrument instrument;

    int pixels = 10; // 10*10 total
    double pixelSpacing = 0;
    Mantid::Kernel::Quat bankRot{}; // No rotation

    // Add a rectangular bank
    int idStart = 0;
    std::string bankName = "bank1";
    Mantid::Kernel::V3D bankPos{0, 1, 1};
    ComponentCreationHelper::addRectangularBank(
        instrument, idStart, pixels, pixelSpacing, bankName, bankPos, bankRot);

    // A source
    ObjComponent *source = new ObjComponent("source");
    source->setPos(V3D{0, 0, -10});
    instrument.add(source);
    instrument.markAsSource(source);

    // A sample
    ObjComponent *sample = new ObjComponent("some-surface-holder");
    sample->setPos(V3D{0, 0, 0});
    sample->setShape(
        ComponentCreationHelper::createSphere(0.01 /*1cm*/, V3D(0, 0, 0), "1"));
    instrument.add(sample);
    instrument.markAsSamplePos(sample);

    // A detector
    Detector *det = new Detector(
        "point-detector", (2 * pixels * pixels) + 1 /*detector id*/, nullptr);
    det->setPos(V3D{0, 0, 3});
    det->setShape(
        ComponentCreationHelper::createSphere(0.01 /*1cm*/, V3D(0, 0, 0), "1"));
    instrument.add(det);
    instrument.markAsDetector(det);

    // Add another rectangular bank
    idStart = pixels * pixels;
    bankName = "bank2";
    bankPos = Mantid::Kernel::V3D{0, -1, 2};
    ComponentCreationHelper::addRectangularBank(
        instrument, idStart, pixels, pixelSpacing, bankName, bankPos, bankRot);

    auto wrappers = InstrumentVisitor::makeWrappers(instrument);
    const auto &componentInfo = std::get<0>(wrappers);
    // Check bounding box of root (instrument)
434
435
    auto boundingBoxRoot =
        componentInfo->boundingBox(componentInfo->root() /*Root*/);
436
437
438
439
440
441
442
443
444

    // Check free detector not ignored because it's sandwidged between banks.
    // Should not be skipped over.
    const double detRadius = 0.01; // See test helper for value
    TS_ASSERT_DELTA(boundingBoxRoot.maxPoint().Z(),
                    det->getPos().Z() + detRadius, 1e-9);

    // Check bank1 represents max point in y
    const size_t bank1Index = componentInfo->root() - 4 - 10;
445
    auto boundingBoxBank1 = componentInfo->boundingBox(bank1Index);
446
    TS_ASSERT(componentInfo->isStructuredBank(bank1Index));
447
448
449
450
451
    TS_ASSERT_DELTA(boundingBoxRoot.maxPoint().Y(),
                    boundingBoxBank1.maxPoint().Y(), 1e-9);

    // Check bank2 represents min point in y
    const size_t bank2Index = componentInfo->root() - 1;
452
    auto boundingBoxBank2 = componentInfo->boundingBox(bank2Index);
453
    TS_ASSERT(componentInfo->isStructuredBank(bank2Index));
454
455
456
    TS_ASSERT_DELTA(boundingBoxRoot.minPoint().Y(),
                    boundingBoxBank2.minPoint().Y(), 1e-9);
  }
Owen Arnold's avatar
Owen Arnold committed
457
};
Owen Arnold's avatar
Owen Arnold committed
458

Owen Arnold's avatar
Owen Arnold committed
459
#endif /* MANTID_GEOMETRY_COMPONENTINFOTEST_H_ */