-
Notifications
You must be signed in to change notification settings - Fork 359
/
app_helper.hpp
132 lines (109 loc) · 4.1 KB
/
app_helper.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright (c) 2017-2024, University of Cincinnati, developed by Henry Schreiner
// under NSF AWARD 1414736 and by the respective contributors.
// All rights reserved.
//
// SPDX-License-Identifier: BSD-3-Clause
#pragma once
#ifdef CLI11_SINGLE_FILE
#include "CLI11.hpp"
#else
#include "CLI/CLI.hpp"
#endif
#include "catch.hpp"
#include <array>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <string>
#include <utility>
#include <vector>
using input_t = std::vector<std::string>;
class TApp {
public:
CLI::App app{"My Test Program"};
input_t args{};
virtual ~TApp() = default;
void run() {
// It is okay to re-parse - clear is called automatically before a parse.
input_t newargs = args;
std::reverse(std::begin(newargs), std::end(newargs));
app.parse(newargs);
}
};
CLI11_INLINE int fileClear(const std::string &name) { return std::remove(name.c_str()); }
class TempFile {
std::string _name{};
public:
explicit TempFile(std::string name) : _name(std::move(name)) {
if(!CLI::NonexistentPath(_name).empty())
throw std::runtime_error(_name);
}
~TempFile() {
std::remove(_name.c_str()); // Doesn't matter if returns 0 or not
}
operator const std::string &() const { return _name; } // NOLINT(google-explicit-constructor)
CLI11_NODISCARD const char *c_str() const { return _name.c_str(); }
};
inline void put_env(std::string name, std::string value) {
#ifdef _WIN32
_putenv_s(name.c_str(), value.c_str());
#else
setenv(name.c_str(), value.c_str(), 1);
#endif
}
inline void unset_env(std::string name) {
#ifdef _WIN32
_putenv_s(name.c_str(), "");
#else
unsetenv(name.c_str());
#endif
}
/// these are provided for compatibility with the char8_t for C++20 that breaks stuff
CLI11_INLINE std::string from_u8string(const std::string &s) { return s; }
CLI11_INLINE std::string from_u8string(std::string &&s) { return std::move(s); }
#if defined(__cpp_lib_char8_t)
CLI11_INLINE std::string from_u8string(const std::u8string &s) { return std::string(s.begin(), s.end()); }
#elif defined(__cpp_char8_t)
CLI11_INLINE std::string from_u8string(const char8_t *s) { return std::string(reinterpret_cast<const char *>(s)); }
#endif
CLI11_INLINE void check_identical_files(const char *path1, const char *path2) {
std::string err1 = CLI::ExistingFile(path1);
if(!err1.empty()) {
FAIL("Could not open " << path1 << ": " << err1);
}
std::string err2 = CLI::ExistingFile(path2);
if(!err2.empty()) {
FAIL("Could not open " << path2 << ": " << err2);
}
// open files at the end to compare size first
std::ifstream file1(path1, std::ifstream::ate | std::ifstream::binary);
std::ifstream file2(path2, std::ifstream::ate | std::ifstream::binary);
if(!file1.good()) {
FAIL("File " << path1 << " is corrupted");
}
if(!file2.good()) {
FAIL("File " << path2 << " is corrupted");
}
if(file1.tellg() != file2.tellg()) {
FAIL("Different file sizes:\n " << file1.tellg() << " bytes in " << path1 << "\n " << file2.tellg()
<< " bytes in " << path2);
}
// rewind files
file1.seekg(0);
file2.seekg(0);
std::array<uint8_t, 10240> buffer1;
std::array<uint8_t, 10240> buffer2;
for(size_t ibuffer = 0; file1.good(); ++ibuffer) {
// Flawfinder: ignore
file1.read(reinterpret_cast<char *>(buffer1.data()), static_cast<std::streamsize>(buffer1.size()));
// Flawfinder: ignore
file2.read(reinterpret_cast<char *>(buffer2.data()), static_cast<std::streamsize>(buffer2.size()));
for(size_t i = 0; i < static_cast<size_t>(file1.gcount()); ++i) {
if(buffer1[i] != buffer2[i]) {
FAIL(std::hex << std::setfill('0') << "Different bytes at position " << (ibuffer * 10240 + i) << ":\n "
<< "0x" << std::setw(2) << static_cast<int>(buffer1[i]) << " in " << path1 << "\n "
<< "0x" << std::setw(2) << static_cast<int>(buffer2[i]) << " in " << path2);
}
}
}
}