Skip to content

Commit 11297d7

Browse files
committed
ENH: Refactor metadata handling in tests
Initial resolution for addressing ambiguitiy in 'char' signed behavior desicribed in issue Related to: #5779 `VerifyMetaData` function to eliminate redundant metadata handling code in `HDF5ImageIOTest` and `MetaDataDictionaryGTest`. This simplifies test logic and improves maintainability. Reduce duplication of common testing. Provide more failure diagnostics to assist with pin-pointing the failure locations. Replace `dynamic_cast` with `static_cast` and explicit type information checks for clearer and more efficient metadata handling. On linux-arm <char> and <unsigned char> are the same types. On most other platforms, <char> is the same as <signed char>.
1 parent 6aff639 commit 11297d7

File tree

6 files changed

+493
-159
lines changed

6 files changed

+493
-159
lines changed

Modules/Core/Common/test/itkMetaDataDictionaryGTest.cxx

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include "itkMetaDataDictionary.h"
2222
#include "itkMetaDataObject.h"
23+
#include "itkTestVerifyMetaData.h"
2324

2425
#include <iterator>
2526
#include <numeric> // For iota.
@@ -44,6 +45,112 @@ createMetaDataDictionary()
4445
return metaDataDictionary;
4546
}
4647

48+
49+
template <typename T>
50+
static int
51+
CheckMetaData(itk::MetaDataDictionary & metaDict, const std::string & key, const T & knownValue)
52+
{
53+
itk::EncapsulateMetaData<T>(metaDict, key, knownValue);
54+
return itk::VerifyMetaDataPrivateTestingUtility<T>(metaDict, key, knownValue);
55+
}
56+
57+
58+
static int
59+
doExposeMetaDatas()
60+
{
61+
// Simplified version of tests found in HDF5 reading/writing
62+
// that are broken out here to improve localization of bugs
63+
// found during linux-arm building
64+
itk::MetaDataDictionary metaDict;
65+
int success = EXIT_SUCCESS;
66+
67+
if (CheckMetaData<bool>(metaDict, "TestBool", false) != EXIT_SUCCESS)
68+
{
69+
success = EXIT_FAILURE;
70+
}
71+
#if !defined(ITK_FUTURE_LEGACY_REMOVE)
72+
if (CheckMetaData<char>(metaDict, "TestChar", 'c') != EXIT_SUCCESS)
73+
{
74+
success = EXIT_FAILURE;
75+
}
76+
#endif
77+
if (CheckMetaData<unsigned char>(metaDict, "TestUChar", 'u') != EXIT_SUCCESS)
78+
{
79+
success = EXIT_FAILURE;
80+
}
81+
if (CheckMetaData<short>(metaDict, "TestShort", 1) != EXIT_SUCCESS)
82+
{
83+
success = EXIT_FAILURE;
84+
}
85+
if (CheckMetaData<unsigned short>(metaDict, "TestUShort", 3) != EXIT_SUCCESS)
86+
{
87+
success = EXIT_FAILURE;
88+
}
89+
if (CheckMetaData<int>(metaDict, "TestInt", 5) != EXIT_SUCCESS)
90+
{
91+
success = EXIT_FAILURE;
92+
}
93+
if (CheckMetaData<unsigned int>(metaDict, "TestUInt", 7) != EXIT_SUCCESS)
94+
{
95+
success = EXIT_FAILURE;
96+
}
97+
if (CheckMetaData<long>(metaDict, "TestLong", 5) != EXIT_SUCCESS)
98+
{
99+
success = EXIT_FAILURE;
100+
}
101+
if (CheckMetaData<unsigned long>(metaDict, "TestULong", 7) != EXIT_SUCCESS)
102+
{
103+
success = EXIT_FAILURE;
104+
}
105+
if (CheckMetaData<long long>(metaDict, "TestLLong", -5) != EXIT_SUCCESS)
106+
{
107+
success = EXIT_FAILURE;
108+
}
109+
if (CheckMetaData<unsigned long long>(metaDict, "TestULLong", 7ull) != EXIT_SUCCESS)
110+
{
111+
success = EXIT_FAILURE;
112+
}
113+
if (CheckMetaData<float>(metaDict, "TestFloat", 1.23456f) != EXIT_SUCCESS)
114+
{
115+
success = EXIT_FAILURE;
116+
}
117+
if (CheckMetaData<double>(metaDict, "TestDouble", 1.23456) != EXIT_SUCCESS)
118+
{
119+
success = EXIT_FAILURE;
120+
}
121+
122+
#if !defined(ITK_FUTURE_LEGACY_REMOVE)
123+
itk::Array<char> metaDataCharArray(5);
124+
metaDataCharArray[0] = 'h';
125+
metaDataCharArray[1] = 'e';
126+
metaDataCharArray[2] = 'l';
127+
metaDataCharArray[3] = 'l';
128+
metaDataCharArray[4] = 'o';
129+
if (CheckMetaData<itk::Array<char>>(metaDict, "TestCharArray", metaDataCharArray) != EXIT_SUCCESS)
130+
{
131+
success = EXIT_FAILURE;
132+
}
133+
#endif
134+
135+
itk::Array<double> metaDataDoubleArray(5);
136+
metaDataDoubleArray[0] = 3.0;
137+
metaDataDoubleArray[1] = 1.0;
138+
metaDataDoubleArray[2] = 4.0;
139+
metaDataDoubleArray[3] = 5.0;
140+
metaDataDoubleArray[4] = 2.0;
141+
if (CheckMetaData<itk::Array<double>>(metaDict, "TestDoubleArray", metaDataDoubleArray) != EXIT_SUCCESS)
142+
{
143+
success = EXIT_FAILURE;
144+
}
145+
146+
if (CheckMetaData<std::string>(metaDict, "StdString", "Test std::string") != EXIT_SUCCESS)
147+
{
148+
success = EXIT_FAILURE;
149+
}
150+
return success;
151+
}
152+
153+
47154
template <typename T>
48155
itk::MetaDataObjectBase::Pointer
49156
createMetaDataObject(const T & invalue)
@@ -56,6 +163,9 @@ createMetaDataObject(const T & invalue)
56163

57164
TEST(MetaDataDictionary, Basic)
58165
{
166+
// Isolate
167+
EXPECT_EQ(doExposeMetaDatas(), EXIT_SUCCESS);
168+
59169
// This test exercises and checks the non-constant interface
60170
itk::MetaDataDictionary dic = createMetaDataDictionary();
61171

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*=========================================================================
2+
*
3+
* Copyright NumFOCUS
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* https://www.apache.org/licenses/LICENSE-2.0.txt
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*=========================================================================*/
18+
#ifndef itkTestVerifyMetaData_h
19+
#define itkTestVerifyMetaData_h
20+
21+
#include "itkMetaDataDictionary.h"
22+
#include "itkMetaDataObject.h"
23+
namespace itk
24+
{
25+
/* A utility function used for testing, this is not intended to be part of the public interface */
26+
/* Used only to avoid duplicate code in itkMetaDictionaryGTest.cxx and itkHDF5ImageIOTest.cxx */
27+
template <typename T>
28+
int
29+
VerifyMetaDataPrivateTestingUtility(const itk::MetaDataDictionary & metaDict,
30+
const std::string & key,
31+
const T & knownValue)
32+
{
33+
int status = EXIT_SUCCESS;
34+
T exposedValue{};
35+
36+
#if defined ITK_FUTURE_LEGACY_REMOVE
37+
static_assert(
38+
!std::is_same_v<itk::Array<char>, T>,
39+
"Should not use the ambiguous 'char' stored in meta data, because it is not-cross platform consistent.");
40+
static_assert(
41+
!std::is_same_v<char, T>,
42+
"Should not use the ambiguous 'char' stored in meta data, because it is not-cross platform consistent.");
43+
if (!itk::ExposeMetaData<T>(metaDict, key, exposedValue))
44+
{
45+
std::cerr << "Failure ExposeMetaData for key '" << key << "'" << std::endl;
46+
status = EXIT_FAILURE;
47+
}
48+
#else
49+
if constexpr (std::is_same_v<itk::Array<char>, T>)
50+
{
51+
// If Encapsulate and Expose Metadata is all in core memory operations,
52+
// the type of char may be preserved.
53+
if (!itk::ExposeMetaData<itk::Array<char>>(metaDict, key, exposedValue))
54+
{
55+
// If Encapsulate and Expose Metadata is written to disk and
56+
// possibly shared across platforms, then 'char' may have been
57+
// stored in an intermediate format (aka file on disk) with explicit
58+
// signed or unsigned characteristics
59+
if constexpr (std::is_signed_v<char>)
60+
{
61+
itk::Array<signed char> temp_value{};
62+
if (!itk::ExposeMetaData<itk::Array<signed char>>(metaDict, key, temp_value))
63+
{
64+
std::cerr << "Failure ExposeMetaData '" << key << "'" << std::endl;
65+
status = EXIT_FAILURE;
66+
}
67+
exposedValue = temp_value;
68+
}
69+
else
70+
{
71+
itk::Array<unsigned char> temp_value{};
72+
if (!itk::ExposeMetaData<itk::Array<unsigned char>>(metaDict, key, temp_value))
73+
{
74+
std::cerr << "Failure ExposeMetaData '" << key << "'" << std::endl;
75+
status = EXIT_FAILURE;
76+
}
77+
exposedValue = temp_value;
78+
}
79+
}
80+
}
81+
else if constexpr (std::is_same_v<char, T>)
82+
{
83+
// If Encapsulate and Expose Metadata is all in core memory operations,
84+
// the type of char may be preserved.
85+
if (!itk::ExposeMetaData<char>(metaDict, key, exposedValue))
86+
{
87+
// If Encapsulate and Expose Metadata is written to disk and
88+
// possibly shared across platforms, then 'char' may have been
89+
// stored in an intermediate format (aka file on disk) with explicit
90+
// signed or unsigned characteristics
91+
if constexpr (std::is_signed_v<char>)
92+
{
93+
signed char temp_value{};
94+
95+
if (!itk::ExposeMetaData<signed char>(metaDict, key, temp_value))
96+
{
97+
std::cerr << "Failure ExposeMetaData '" << key << "'" << std::endl;
98+
status = EXIT_FAILURE;
99+
}
100+
exposedValue = static_cast<T>(temp_value);
101+
}
102+
else
103+
{
104+
unsigned char temp_value{};
105+
if (!itk::ExposeMetaData<unsigned char>(metaDict, key, temp_value))
106+
{
107+
std::cerr << "Failure ExposeMetaData '" << key << "'" << std::endl;
108+
status = EXIT_FAILURE;
109+
}
110+
exposedValue = static_cast<T>(temp_value);
111+
}
112+
}
113+
}
114+
else if (!itk::ExposeMetaData<T>(metaDict, key, exposedValue))
115+
{
116+
std::cerr << "Failure ExposeMetaData of boolean type '" << key << "'" << std::endl;
117+
status = EXIT_FAILURE;
118+
}
119+
#endif
120+
121+
122+
if constexpr (std::is_floating_point_v<T>)
123+
{
124+
if (itk::Math::NotAlmostEquals(exposedValue, knownValue))
125+
{
126+
std::cerr << "Incorrect meta value read in for " << key << " '" << exposedValue << "' != '" << knownValue << "'"
127+
<< std::endl;
128+
status = EXIT_FAILURE;
129+
}
130+
}
131+
else
132+
{
133+
if (exposedValue != knownValue)
134+
{
135+
std::cerr << "Incorrect meta value read in for " << key << " '" << exposedValue << "' != '" << knownValue << "'"
136+
<< std::endl;
137+
status = EXIT_FAILURE;
138+
}
139+
}
140+
if (status == EXIT_FAILURE)
141+
{
142+
std::cerr << "========================================" << std::endl;
143+
metaDict.Print(std::cerr);
144+
std::cerr << "========================================" << std::endl;
145+
}
146+
return status;
147+
}
148+
} // namespace itk
149+
150+
#endif // itkTestVerifyMetaData_h

0 commit comments

Comments
 (0)