• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

open-source-parsers / jsoncpp / 10821679119

12 Sep 2024 12:14AM CUT coverage: 95.295%. Remained the same
10821679119

push

github

web-flow
Merge fa99e2078 into 871f0cc43

5306 of 5568 relevant lines covered (95.29%)

11935.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

40.14
/src/test_lib_json/jsontest.cpp
1
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
2
// Distributed under MIT license, or public domain if desired and
3
// recognized in your jurisdiction.
4
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
5

6
#define _CRT_SECURE_NO_WARNINGS 1 // Prevents deprecation warning with MSVC
7
#include "jsontest.h"
8
#include <cstdio>
9
#include <string>
10

11
#if defined(_MSC_VER)
12
// Used to install a report hook that prevent dialog on assertion and error.
13
#include <crtdbg.h>
14
#endif // if defined(_MSC_VER)
15

16
#if defined(_WIN32)
17
// Used to prevent dialog on memory fault.
18
// Limits headers included by Windows.h
19
#define WIN32_LEAN_AND_MEAN
20
#define NOSERVICE
21
#define NOMCX
22
#define NOIME
23
#define NOSOUND
24
#define NOCOMM
25
#define NORPC
26
#define NOGDI
27
#define NOUSER
28
#define NODRIVERS
29
#define NOLOGERROR
30
#define NOPROFILER
31
#define NOMEMMGR
32
#define NOLFILEIO
33
#define NOOPENFILE
34
#define NORESOURCE
35
#define NOATOM
36
#define NOLANGUAGE
37
#define NOLSTRING
38
#define NODBCS
39
#define NOKEYBOARDINFO
40
#define NOGDICAPMASKS
41
#define NOCOLOR
42
#define NOGDIOBJ
43
#define NODRAWTEXT
44
#define NOTEXTMETRIC
45
#define NOSCALABLEFONT
46
#define NOBITMAP
47
#define NORASTEROPS
48
#define NOMETAFILE
49
#define NOSYSMETRICS
50
#define NOSYSTEMPARAMSINFO
51
#define NOMSG
52
#define NOWINSTYLES
53
#define NOWINOFFSETS
54
#define NOSHOWWINDOW
55
#define NODEFERWINDOWPOS
56
#define NOVIRTUALKEYCODES
57
#define NOKEYSTATES
58
#define NOWH
59
#define NOMENUS
60
#define NOSCROLL
61
#define NOCLIPBOARD
62
#define NOICONS
63
#define NOMB
64
#define NOSYSCOMMANDS
65
#define NOMDI
66
#define NOCTLMGR
67
#define NOWINMESSAGES
68
#include <windows.h>
69
#endif // if defined(_WIN32)
70

71
namespace JsonTest {
72

73
// class TestResult
74
// //////////////////////////////////////////////////////////////////
75

76
TestResult::TestResult() {
121✔
77
  // The root predicate has id 0
78
  rootPredicateNode_.id_ = 0;
121✔
79
  rootPredicateNode_.next_ = nullptr;
121✔
80
  predicateStackTail_ = &rootPredicateNode_;
121✔
81
}
121✔
82

83
void TestResult::setTestName(const Json::String& name) { name_ = name; }
121✔
84

85
TestResult& TestResult::addFailure(const char* file, unsigned int line,
×
86
                                   const char* expr) {
87
  /// Walks the PredicateContext stack adding them to failures_ if not already
88
  /// added.
89
  unsigned int nestingLevel = 0;
90
  PredicateContext* lastNode = rootPredicateNode_.next_;
×
91
  for (; lastNode != nullptr; lastNode = lastNode->next_) {
×
92
    if (lastNode->id_ > lastUsedPredicateId_) // new PredicateContext
×
93
    {
94
      lastUsedPredicateId_ = lastNode->id_;
×
95
      addFailureInfo(lastNode->file_, lastNode->line_, lastNode->expr_,
×
96
                     nestingLevel);
97
      // Link the PredicateContext to the failure for message target when
98
      // popping the PredicateContext.
99
      lastNode->failure_ = &(failures_.back());
×
100
    }
101
    ++nestingLevel;
×
102
  }
103

104
  // Adds the failed assertion
105
  addFailureInfo(file, line, expr, nestingLevel);
×
106
  messageTarget_ = &(failures_.back());
×
107
  return *this;
×
108
}
109

110
void TestResult::addFailureInfo(const char* file, unsigned int line,
×
111
                                const char* expr, unsigned int nestingLevel) {
112
  Failure failure;
113
  failure.file_ = file;
×
114
  failure.line_ = line;
×
115
  if (expr) {
×
116
    failure.expr_ = expr;
117
  }
118
  failure.nestingLevel_ = nestingLevel;
×
119
  failures_.push_back(failure);
×
120
}
×
121

122
TestResult& TestResult::popPredicateContext() {
130✔
123
  PredicateContext* lastNode = &rootPredicateNode_;
130✔
124
  while (lastNode->next_ != nullptr && lastNode->next_->next_ != nullptr) {
145✔
125
    lastNode = lastNode->next_;
126
  }
127
  // Set message target to popped failure
128
  PredicateContext* tail = lastNode->next_;
129
  if (tail != nullptr && tail->failure_ != nullptr) {
130✔
130
    messageTarget_ = tail->failure_;
×
131
  }
132
  // Remove tail from list
133
  predicateStackTail_ = lastNode;
130✔
134
  lastNode->next_ = nullptr;
130✔
135
  return *this;
130✔
136
}
137

138
bool TestResult::failed() const { return !failures_.empty(); }
×
139

140
void TestResult::printFailure(bool printTestName) const {
×
141
  if (failures_.empty()) {
×
142
    return;
143
  }
144

145
  if (printTestName) {
×
146
    printf("* Detail of %s test failure:\n", name_.c_str());
147
  }
148

149
  // Print in reverse to display the callstack in the right order
150
  for (const auto& failure : failures_) {
×
151
    Json::String indent(failure.nestingLevel_ * 2, ' ');
×
152
    if (failure.file_) {
×
153
      printf("%s%s(%u): ", indent.c_str(), failure.file_, failure.line_);
×
154
    }
155
    if (!failure.expr_.empty()) {
×
156
      printf("%s\n", failure.expr_.c_str());
157
    } else if (failure.file_) {
×
158
      printf("\n");
159
    }
160
    if (!failure.message_.empty()) {
×
161
      Json::String reindented = indentText(failure.message_, indent + "  ");
×
162
      printf("%s\n", reindented.c_str());
163
    }
164
  }
165
}
166

167
Json::String TestResult::indentText(const Json::String& text,
×
168
                                    const Json::String& indent) {
169
  Json::String reindented;
170
  Json::String::size_type lastIndex = 0;
171
  while (lastIndex < text.size()) {
×
172
    Json::String::size_type nextIndex = text.find('\n', lastIndex);
×
173
    if (nextIndex == Json::String::npos) {
×
174
      nextIndex = text.size() - 1;
×
175
    }
176
    reindented += indent;
177
    reindented += text.substr(lastIndex, nextIndex - lastIndex + 1);
×
178
    lastIndex = nextIndex + 1;
×
179
  }
180
  return reindented;
×
181
}
182

183
TestResult& TestResult::addToLastFailure(const Json::String& message) {
3,486✔
184
  if (messageTarget_ != nullptr) {
3,918✔
185
    messageTarget_->message_ += message;
×
186
  }
187
  return *this;
3,486✔
188
}
189

190
TestResult& TestResult::operator<<(Json::Int64 value) {
×
191
  return addToLastFailure(Json::valueToString(value));
×
192
}
193

194
TestResult& TestResult::operator<<(Json::UInt64 value) {
48✔
195
  return addToLastFailure(Json::valueToString(value));
96✔
196
}
197

198
TestResult& TestResult::operator<<(bool value) {
384✔
199
  return addToLastFailure(value ? "true" : "false");
896✔
200
}
201

202
// class TestCase
203
// //////////////////////////////////////////////////////////////////
204

205
TestCase::TestCase() = default;
121✔
206

207
TestCase::~TestCase() = default;
242✔
208

209
void TestCase::run(TestResult& result) {
×
210
  result_ = &result;
121✔
211
  runTestCase();
121✔
212
}
121✔
213

214
// class Runner
215
// //////////////////////////////////////////////////////////////////
216

217
Runner::Runner() = default;
2✔
218

219
Runner& Runner::add(TestCaseFactory factory) {
121✔
220
  tests_.push_back(factory);
121✔
221
  return *this;
121✔
222
}
223

224
size_t Runner::testCount() const { return tests_.size(); }
×
225

226
Json::String Runner::testNameAt(size_t index) const {
×
227
  TestCase* test = tests_[index]();
×
228
  Json::String name = test->testName();
×
229
  delete test;
×
230
  return name;
×
231
}
232

233
void Runner::runTestAt(size_t index, TestResult& result) const {
121✔
234
  TestCase* test = tests_[index]();
121✔
235
  result.setTestName(test->testName());
121✔
236
  printf("Testing %s: ", test->testName());
121✔
237
  fflush(stdout);
121✔
238
#if JSON_USE_EXCEPTION
239
  try {
240
#endif // if JSON_USE_EXCEPTION
241
    test->run(result);
242
#if JSON_USE_EXCEPTION
243
  } catch (const std::exception& e) {
×
244
    result.addFailure(__FILE__, __LINE__, "Unexpected exception caught:")
×
245
        << e.what();
×
246
  }
×
247
#endif // if JSON_USE_EXCEPTION
248
  delete test;
121✔
249
  const char* status = result.failed() ? "FAILED" : "OK";
121✔
250
  printf("%s\n", status);
251
  fflush(stdout);
121✔
252
}
121✔
253

254
bool Runner::runAllTest(bool printSummary) const {
1✔
255
  size_t const count = testCount();
256
  std::deque<TestResult> failures;
257
  for (size_t index = 0; index < count; ++index) {
122✔
258
    TestResult result;
121✔
259
    runTestAt(index, result);
121✔
260
    if (result.failed()) {
121✔
261
      failures.push_back(result);
×
262
    }
263
  }
121✔
264

265
  if (failures.empty()) {
1✔
266
    if (printSummary) {
1✔
267
      printf("All %zu tests passed\n", count);
268
    }
269
    return true;
1✔
270
  }
271
  for (auto& result : failures) {
×
272
    result.printFailure(count > 1);
×
273
  }
274

275
  if (printSummary) {
×
276
    size_t const failedCount = failures.size();
277
    size_t const passedCount = count - failedCount;
×
278
    printf("%zu/%zu tests passed (%zu failure(s))\n", passedCount, count,
279
           failedCount);
280
  }
281
  return false;
282
}
1✔
283

284
bool Runner::testIndex(const Json::String& testName, size_t& indexOut) const {
×
285
  const size_t count = testCount();
286
  for (size_t index = 0; index < count; ++index) {
×
287
    if (testNameAt(index) == testName) {
×
288
      indexOut = index;
×
289
      return true;
×
290
    }
291
  }
292
  return false;
293
}
294

295
void Runner::listTests() const {
×
296
  const size_t count = testCount();
297
  for (size_t index = 0; index < count; ++index) {
×
298
    printf("%s\n", testNameAt(index).c_str());
×
299
  }
300
}
×
301

302
int Runner::runCommandLine(int argc, const char* argv[]) const {
1✔
303
  // typedef std::deque<String> TestNames;
304
  Runner subrunner;
305
  for (int index = 1; index < argc; ++index) {
1✔
306
    Json::String opt = argv[index];
×
307
    if (opt == "--list-tests") {
×
308
      listTests();
×
309
      return 0;
310
    }
311
    if (opt == "--test-auto") {
×
312
      preventDialogOnCrash();
313
    } else if (opt == "--test") {
×
314
      ++index;
×
315
      if (index < argc) {
×
316
        size_t testNameIndex;
317
        if (testIndex(argv[index], testNameIndex)) {
×
318
          subrunner.add(tests_[testNameIndex]);
×
319
        } else {
320
          fprintf(stderr, "Test '%s' does not exist!\n", argv[index]);
×
321
          return 2;
×
322
        }
323
      } else {
324
        printUsage(argv[0]);
×
325
        return 2;
326
      }
327
    } else {
328
      printUsage(argv[0]);
×
329
      return 2;
330
    }
331
  }
332
  bool succeeded;
333
  if (subrunner.testCount() > 0) {
1✔
334
    succeeded = subrunner.runAllTest(subrunner.testCount() > 1);
×
335
  } else {
336
    succeeded = runAllTest(true);
1✔
337
  }
338
  return succeeded ? 0 : 1;
1✔
339
}
340

341
#if defined(_MSC_VER) && defined(_DEBUG)
342
// Hook MSVCRT assertions to prevent dialog from appearing
343
static int msvcrtSilentReportHook(int reportType, char* message,
344
                                  int* /*returnValue*/) {
345
  // The default CRT handling of error and assertion is to display
346
  // an error dialog to the user.
347
  // Instead, when an error or an assertion occurs, we force the
348
  // application to terminate using abort() after display
349
  // the message on stderr.
350
  if (reportType == _CRT_ERROR || reportType == _CRT_ASSERT) {
351
    // calling abort() cause the ReportHook to be called
352
    // The following is used to detect this case and let's the
353
    // error handler fallback on its default behaviour (
354
    // display a warning message)
355
    static volatile bool isAborting = false;
356
    if (isAborting) {
357
      return TRUE;
358
    }
359
    isAborting = true;
360

361
    fprintf(stderr, "CRT Error/Assert:\n%s\n", message);
362
    fflush(stderr);
363
    abort();
364
  }
365
  // Let's other reportType (_CRT_WARNING) be handled as they would by default
366
  return FALSE;
367
}
368
#endif // if defined(_MSC_VER)
369

370
void Runner::preventDialogOnCrash() {
×
371
#if defined(_MSC_VER) && defined(_DEBUG)
372
  // Install a hook to prevent MSVCRT error and assertion from
373
  // popping a dialog
374
  // This function a NO-OP in release configuration
375
  // (which cause warning since msvcrtSilentReportHook is not referenced)
376
  _CrtSetReportHook(&msvcrtSilentReportHook);
377
#endif // if defined(_MSC_VER)
378

379
  // @todo investigate this handler (for buffer overflow)
380
  // _set_security_error_handler
381

382
#if defined(_WIN32)
383
  // Prevents the system from popping a dialog for debugging if the
384
  // application fails due to invalid memory access.
385
  SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
386
               SEM_NOOPENFILEERRORBOX);
387
#endif // if defined(_WIN32)
388
}
×
389

390
void Runner::printUsage(const char* appName) {
×
391
  printf("Usage: %s [options]\n"
392
         "\n"
393
         "If --test is not specified, then all the test cases be run.\n"
394
         "\n"
395
         "Valid options:\n"
396
         "--list-tests: print the name of all test cases on the standard\n"
397
         "              output and exit.\n"
398
         "--test TESTNAME: executes the test case with the specified name.\n"
399
         "                 May be repeated.\n"
400
         "--test-auto: prevent dialog prompting for debugging on crash.\n",
401
         appName);
402
}
×
403

404
// Assertion functions
405
// //////////////////////////////////////////////////////////////////
406

407
Json::String ToJsonString(const char* toConvert) {
106✔
408
  return Json::String(toConvert);
106✔
409
}
410

411
Json::String ToJsonString(Json::String in) { return in; }
1,025✔
412

413
#if JSONCPP_USING_SECURE_MEMORY
414
Json::String ToJsonString(std::string in) {
415
  return Json::String(in.data(), in.data() + in.length());
416
}
417
#endif
418

419
TestResult& checkStringEqual(TestResult& result, const Json::String& expected,
559✔
420
                             const Json::String& actual, const char* file,
421
                             unsigned int line, const char* expr) {
422
  if (expected != actual) {
559✔
423
    result.addFailure(file, line, expr);
×
424
    result << "Expected: '" << expected << "'\n";
×
425
    result << "Actual  : '" << actual << "'";
×
426
  }
427
  return result;
559✔
428
}
429

430
} // namespace JsonTest
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc