40 #include <visp3/core/vpConfig.h>
42 #if defined(VISP_HAVE_NLOHMANN_JSON) && defined(VISP_HAVE_CATCH2)
45 #include <visp3/core/vpArray2D.h>
46 #include <visp3/core/vpIoTools.h>
48 #include <nlohmann/json.hpp>
49 using json = nlohmann::json;
51 #define CATCH_CONFIG_RUNNER
54 #ifdef ENABLE_VISP_NAMESPACE
60 using StringMatcherBase = Catch::Matchers::StdString::StringMatcherBase;
61 class vpExceptionMatcher :
public Catch::Matchers::Impl::MatcherBase<vpException>
64 const StringMatcherBase &m_messageMatcher;
68 : m_type(type), m_messageMatcher(messageMatcher)
73 return m_type == in.getCode() && m_messageMatcher.match(in.getStringMessage());
76 std::string describe() const VP_OVERRIDE
78 std::ostringstream ss;
79 ss <<
"vpException has type " << m_type <<
" and message " << m_messageMatcher.describe();
84 class vpRandomArray2DGenerator :
public Catch::Generators::IGenerator<vpArray2D<double> >
87 std::minstd_rand m_rand;
88 std::uniform_real_distribution<> m_val_dist;
89 std::uniform_int_distribution<> m_dim_dist;
94 vpRandomArray2DGenerator(
double valueRange,
int minSize,
int maxSize)
95 : m_rand(std::random_device {}()), m_val_dist(-valueRange, valueRange), m_dim_dist(minSize, maxSize)
98 static_cast<void>(next());
102 bool next() VP_OVERRIDE
104 const unsigned nCols = m_dim_dist(m_rand);
105 const unsigned nRows = m_dim_dist(m_rand);
106 current.
resize(nRows, nCols);
107 for (
unsigned i = 0; i < nRows; ++i) {
108 for (
unsigned j = 0; j < nCols; ++j) {
109 current[i][j] = m_val_dist(m_rand);
115 class vpRandomColVectorGenerator :
public Catch::Generators::IGenerator<vpColVector>
118 std::minstd_rand m_rand;
119 std::uniform_real_distribution<> m_val_dist;
120 std::uniform_int_distribution<> m_dim_dist;
125 vpRandomColVectorGenerator(
double valueRange,
int minSize,
int maxSize)
126 : m_rand(std::random_device {}()), m_val_dist(-valueRange, valueRange), m_dim_dist(minSize, maxSize)
129 static_cast<void>(next());
132 const vpColVector &get() const VP_OVERRIDE {
return current; }
133 bool next() VP_OVERRIDE
135 const unsigned nRows = m_dim_dist(m_rand);
137 for (
unsigned i = 0; i < nRows; ++i) {
138 current[i] = m_val_dist(m_rand);
143 Catch::Generators::GeneratorWrapper<vpArray2D<double> > randomArray(
double v,
int minSize,
int maxSize)
145 return Catch::Generators::GeneratorWrapper<vpArray2D<double> >(
146 std::unique_ptr<Catch::Generators::IGenerator<vpArray2D<double> > >(
147 new vpRandomArray2DGenerator(v, minSize, maxSize)));
149 Catch::Generators::GeneratorWrapper<vpColVector> randomColVector(
double v,
int minSize,
int maxSize)
151 return Catch::Generators::GeneratorWrapper<vpColVector>(
152 std::unique_ptr<Catch::Generators::IGenerator<vpColVector> >(
new vpRandomColVectorGenerator(v, minSize, maxSize)));
156 return vpExceptionMatcher(type, matcher);
159 SCENARIO(
"Serializing a vpArray2D",
"[json]")
161 GIVEN(
"A random vpArray2D<double>")
164 WHEN(
"Serializing to a JSON object")
166 const json j = array;
167 THEN(
"JSON object is a dictionary") { REQUIRE(j.is_object()); }
168 THEN(
"JSON object contains correct number of columns")
170 REQUIRE(j.at(
"cols").get<
unsigned int>() == array.
getCols());
172 THEN(
"JSON object contains correct number of rows")
174 REQUIRE(j.at(
"rows").get<
unsigned int>() == array.
getRows());
176 THEN(
"JSON object contains the array values")
178 const json jData = j.at(
"data");
179 THEN(
"The data field is an array") { REQUIRE(jData.is_array()); }
180 THEN(
"The data field contains the correct number of values") { REQUIRE(jData.size() == array.
size()); }
181 THEN(
"The data field contains the correct number of values")
183 const double *
const start = array[0];
184 const std::vector<double> vec(start, start + array.
size());
185 REQUIRE(vec == jData.get<std::vector<double> >());
192 SCENARIO(
"Trying to instantiate a vpArray with a wrong type of object",
"[json]")
194 GIVEN(
"A random scalar converted to a JSON representation")
197 std::minstd_rand rand;
198 std::uniform_real_distribution<> dist;
199 const json j = GENERATE(take(50, random(-200.0, 200.0)));
200 THEN(
"An exception is thrown")
202 const auto matcher = Catch::Matchers::Contains(
"is not an array or object");
208 SCENARIO(
"Recovering a vpArray2D from a JSON array",
"[json]")
210 GIVEN(
"An empty array")
212 const json j = json::array_t();
213 WHEN(
"Converting to a vpArray2D")
216 THEN(
"The resulting array is empty") { REQUIRE(array.
size() == 0); }
221 const json j = { 10.0, 20.0, 30.0 };
222 WHEN(
"Converting to a vpArray2D")
224 THEN(
"An exception is thrown, since this is an ambiguous array")
227 const auto matcher = Catch::Matchers::Contains(
"is not an array of array");
232 GIVEN(
"A vpArray2D converted to a json 2D array")
236 for (
unsigned i = 0; i < array.
getRows(); ++i) {
238 for (
unsigned j = 0; j < array.
getCols(); ++j) {
239 jRow.push_back(array[i][j]);
243 WHEN(
"Converting back to a vpArray2D")
246 THEN(
"The values are correct") { REQUIRE(array == array2); }
248 WHEN(
"Removing elements from rows so that they do not have the same size")
251 THEN(
"An exception is thrown")
253 const auto matcher = Catch::Matchers::Contains(
"row arrays that are not of the same size");
260 SCENARIO(
"Recovering a vpArray2D from a JSON object as serialized by ViSP",
"[json]")
262 GIVEN(
"A vpArray2D converted to JSON format")
266 WHEN(
"Converting back to a vpArray2D")
269 THEN(
"The 2 arrays are equal") { REQUIRE(array == array2); }
271 WHEN(
"Removing or adding some values from the data field so that its size does not match the expected array size")
273 j.at(
"data").erase(0);
274 THEN(
"An exception is thrown")
277 const auto matcher = Catch::Matchers::Contains(
"must be an array of size");
284 SCENARIO(
"Serializing and deserializing a vpColVector",
"[json]")
286 GIVEN(
"A random vpColVector")
288 const vpColVector v = GENERATE(take(100, randomColVector(100.0, 1, 50)));
289 WHEN(
"Serializing to JSON")
292 THEN(
"There is only one column") { REQUIRE(j.at(
"cols") == 1); }
293 THEN(
"The type is vpColVector") { REQUIRE(j.at(
"type") ==
"vpColVector"); }
294 WHEN(
"Deserializing back to a vpColVector")
297 THEN(
"The 2 vectors are the same") { REQUIRE(v == v2); }
301 GIVEN(
"A random 2D array with number of cols > 1")
304 WHEN(
"Serializing this array to JSON")
306 const json j = array;
307 THEN(
"Serializing back to a vpColVector throws an exception")
310 const auto matcher = Catch::Matchers::Contains(
"tried to read a 2D array into a vpColVector");
315 GIVEN(
"A random 2D array with number of cols = 1")
317 const vpColVector v = GENERATE(take(10, randomColVector(100.0, 1, 50)));
319 WHEN(
"Serializing this array to JSON")
321 const json j = array;
322 THEN(
"Serializing back to a vpColVector is ok and gives the same vector")
331 int main(
int argc,
char *argv[])
333 Catch::Session session;
334 session.applyCommandLine(argc, argv);
336 int numFailed = session.run();
342 int main() {
return EXIT_SUCCESS; }
unsigned int getCols() const
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
unsigned int size() const
Return the number of elements of the 2D array.
unsigned int getRows() const
Implementation of column vector and the associated operations.
void resize(unsigned int i, bool flagNullify=true)
error that can be emitted by ViSP classes.
@ badValue
Used to indicate that a value is not in the allowed range.