TerrainGen coverage


terraingen/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
174 / 180
96.7%
Branches:
259 / 278
93.2%
Functions:
17 / 17
100.0%

app/cli.cpp
Line Branch Exec Source
1 #include "terraingen/app/cli.h"
2
3 #include "terraingen/app/gui/run.h"
4 #include "terraingen/config/build.h"
5 #include "terraingen/config/generate.h"
6 #include "terraingen/config/json.h"
7 #include "terraingen/config/validate.h"
8 #include "terraingen/util/build_info.h"
9 #include "terraingen/util/log.h"
10 #include "terraingen/util/version.h"
11
12 #include <algorithm>
13 #include <cstddef>
14 #include <exception>
15 #include <filesystem>
16 #include <optional>
17 #include <stdexcept>
18 #include <string>
19 #include <vector>
20
21 namespace terraingen::cli {
22
23 namespace {
24
25 /// Options of the generate command.
26 struct GenerateArgs {
27 std::filesystem::path config;
28 std::optional<std::filesystem::path> outputDir;
29 LogLevel logLevel = LogLevel::Info;
30 unsigned threads = 0;
31 std::optional<Backend> backend = std::nullopt;
32 };
33
34 94 GenerateArgs ParseGenerate(const std::vector<std::string>& args) {
35 94 GenerateArgs parsed;
36 94 bool haveConfig = false;
37
2/2
✓ Branch 1 taken 264 times.
✓ Branch 2 taken 84 times.
348 for (std::size_t i = 0; i < args.size(); ++i) {
38 264 const std::string& arg = args[i];
39 171 const auto value = [&]() -> const std::string& {
40
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 169 times.
171 if (i + 1 >= args.size()) {
41
2/2
✓ Branch 2 taken 2 times.
✓ Branch 5 taken 2 times.
2 throw std::invalid_argument(arg + " needs a value");
42 }
43 169 return args[++i];
44 264 };
45
3/3
✓ Branch 1 taken 264 times.
✓ Branch 3 taken 80 times.
✓ Branch 4 taken 184 times.
264 if (arg == "--output-dir") {
46
2/2
✓ Branch 1 taken 79 times.
✓ Branch 4 taken 79 times.
80 parsed.outputDir = value();
47
3/3
✓ Branch 1 taken 184 times.
✓ Branch 3 taken 81 times.
✓ Branch 4 taken 103 times.
184 } else if (arg == "--log-level") {
48
1/1
✓ Branch 1 taken 81 times.
81 const std::string& name = value();
49
1/1
✓ Branch 2 taken 81 times.
81 const std::optional<LogLevel> level = ParseLogLevel(name);
50
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 80 times.
81 if (!level) {
51 throw std::invalid_argument(
52
1/1
✓ Branch 1 taken 1 time.
2 "--log-level needs trace, debug, info, warning, error or off, not '" + name +
53
2/2
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
3 "'");
54 }
55 80 parsed.logLevel = *level;
56
3/3
✓ Branch 1 taken 103 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 97 times.
103 } else if (arg == "--threads") {
57
2/2
✓ Branch 1 taken 6 times.
✓ Branch 4 taken 2 times.
6 parsed.threads = ParseThreads(value());
58
3/3
✓ Branch 1 taken 97 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 93 times.
97 } else if (arg == "--backend") {
59
2/2
✓ Branch 1 taken 3 times.
✓ Branch 4 taken 2 times.
4 parsed.backend = ParseBackend(value());
60
3/3
✓ Branch 1 taken 93 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 92 times.
93 } else if (arg.rfind("--", 0) == 0) {
61
2/2
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
1 throw std::invalid_argument("Unknown option " + arg);
62
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 91 times.
92 } else if (haveConfig) {
63
2/2
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
1 throw std::invalid_argument("Unexpected argument " + arg);
64 } else {
65
1/1
✓ Branch 1 taken 91 times.
91 parsed.config = arg;
66 91 haveConfig = true;
67 }
68 }
69
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 83 times.
84 if (!haveConfig) {
70
1/1
✓ Branch 2 taken 1 time.
1 throw std::invalid_argument("Missing the configuration file");
71 }
72 83 return parsed;
73 11 }
74
75 /// Restores the log level it was made with when it goes out of scope.
76 class LogLevelScope {
77 public:
78 83 explicit LogLevelScope(LogLevel level) : previous_(GetLogLevel()) {
79 83 SetLogLevel(level);
80 83 }
81 LogLevelScope(const LogLevelScope&) = delete;
82 LogLevelScope& operator=(const LogLevelScope&) = delete;
83 83 ~LogLevelScope() {
84 83 SetLogLevel(previous_);
85 83 }
86
87 private:
88 LogLevel previous_;
89 };
90
91 /// Runs `command`, reporting a configuration error against the file `config` and any other error
92 /// as terraingen's, and returns the exit code.
93 template <typename Command>
94 88 int RunReporting(const std::filesystem::path& config, std::ostream& err, Command command) {
95 try {
96
2/2
int terraingen::cli::(anonymous namespace)::RunReporting<terraingen::cli::(anonymous namespace)::Generate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}>(std::filesystem::__cxx11::path const&, std::ostream&, terraingen::cli::(anonymous namespace)::Generate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}):
✓ Branch 1 taken 81 times.
int terraingen::cli::(anonymous namespace)::RunReporting<terraingen::cli::(anonymous namespace)::Validate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}>(std::filesystem::__cxx11::path const&, std::ostream&, terraingen::cli::(anonymous namespace)::Validate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}):
✓ Branch 1 taken 2 times.
88 command();
97
3/6
int terraingen::cli::(anonymous namespace)::RunReporting<terraingen::cli::(anonymous namespace)::Generate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}>(std::filesystem::__cxx11::path const&, std::ostream&, terraingen::cli::(anonymous namespace)::Generate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}):
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
int terraingen::cli::(anonymous namespace)::RunReporting<terraingen::cli::(anonymous namespace)::Validate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}>(std::filesystem::__cxx11::path const&, std::ostream&, terraingen::cli::(anonymous namespace)::Validate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}):
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
5 } catch (const ConfigError& error) {
98
10/10
int terraingen::cli::(anonymous namespace)::RunReporting<terraingen::cli::(anonymous namespace)::Generate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}>(std::filesystem::__cxx11::path const&, std::ostream&, terraingen::cli::(anonymous namespace)::Generate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}):
✓ Branch 1 taken 1 time.
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 11 taken 1 time.
✓ Branch 14 taken 1 time.
int terraingen::cli::(anonymous namespace)::RunReporting<terraingen::cli::(anonymous namespace)::Validate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}>(std::filesystem::__cxx11::path const&, std::ostream&, terraingen::cli::(anonymous namespace)::Validate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}):
✓ Branch 1 taken 3 times.
✓ Branch 4 taken 3 times.
✓ Branch 7 taken 3 times.
✓ Branch 11 taken 3 times.
✓ Branch 14 taken 3 times.
4 err << config.string() << ": " << error.what() << "\n";
99 4 return kExitInvalidConfig;
100 1 } catch (const std::exception& error) {
101
3/6
int terraingen::cli::(anonymous namespace)::RunReporting<terraingen::cli::(anonymous namespace)::Generate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}>(std::filesystem::__cxx11::path const&, std::ostream&, terraingen::cli::(anonymous namespace)::Generate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}):
✓ Branch 1 taken 1 time.
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
int terraingen::cli::(anonymous namespace)::RunReporting<terraingen::cli::(anonymous namespace)::Validate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}>(std::filesystem::__cxx11::path const&, std::ostream&, terraingen::cli::(anonymous namespace)::Validate(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::ostream&, std::ostream&)::{lambda()#1}):
✗ Branch 1 not taken.
✗ Branch 5 not taken.
✗ Branch 8 not taken.
1 err << "terraingen: " << error.what() << "\n";
102 1 return kExitFailure;
103 }
104 83 return kExitSuccess;
105 }
106
107 94 int Generate(const std::vector<std::string>& args, std::ostream& out, std::ostream& err) {
108
1/1
✓ Branch 1 taken 83 times.
94 const GenerateArgs parsed = ParseGenerate(args);
109
1/1
✓ Branch 1 taken 83 times.
83 const LogLevelScope level(parsed.logLevel);
110
1/1
✓ Branch 1 taken 83 times.
83 return RunReporting(parsed.config, err, [&] {
111
1/1
✓ Branch 1 taken 82 times.
83 const TerrainConfig config = LoadConfig(parsed.config);
112
1/1
✓ Branch 1 taken 82 times.
82 const std::filesystem::path inputs = parsed.config.parent_path();
113 const GeneratedTerrain terrain =
114
1/1
✓ Branch 1 taken 82 times.
82 GenerateTerrain(config, inputs, parsed.threads, parsed.backend);
115
1/1
✓ Branch 1 taken 82 times.
82 const std::filesystem::path outputs = parsed.outputDir.value_or(inputs);
116 82 const Stopwatch stopwatch;
117
1/1
✓ Branch 1 taken 81 times.
82 const auto written = WriteOutputs(config, terrain, outputs);
118
3/3
✓ Branch 1 taken 81 times.
✓ Branch 4 taken 81 times.
✓ Branch 7 taken 81 times.
81 out << Summary(terrain) << "\n";
119
2/2
✓ Branch 1 taken 81 times.
✓ Branch 5 taken 81 times.
81 out << "Wrote " << written.size() << (written.size() == 1 ? " file" : " files") << " to "
120
3/5
✗ Branch 0 not taken.
✓ Branch 1 taken 81 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 81 times.
✓ Branch 9 taken 81 times.
162 << (outputs.empty() ? std::filesystem::path(".") : outputs).string() << " in "
121
10/10
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 56 times.
✓ Branch 3 taken 81 times.
✓ Branch 6 taken 81 times.
✓ Branch 10 taken 81 times.
✓ Branch 13 taken 81 times.
✓ Branch 16 taken 81 times.
✓ Branch 19 taken 81 times.
✓ Branch 22 taken 81 times.
✓ Branch 25 taken 81 times.
162 << FormatDuration(stopwatch.Milliseconds()) << "\n";
122 251 });
123 83 }
124
125 /// Prints each backend with its device or why it is unavailable, then the default backend.
126 1 int ListBackends(std::ostream& out, std::ostream& err) {
127
3/3
✓ Branch 1 taken 1 time.
✓ Branch 7 taken 4 times.
✓ Branch 8 taken 1 time.
5 for (const BackendStatus& status : Backends()) {
128 4 out << BackendName(status.backend) << ": "
129
1/1
✓ Branch 1 taken 2 times.
6 << (status.available ? "available on " + status.device
130
1/1
✓ Branch 1 taken 2 times.
2 : "unavailable: " + status.reason)
131
7/7
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 4 times.
✓ Branch 9 taken 2 times.
✓ Branch 10 taken 2 times.
✓ Branch 12 taken 4 times.
✓ Branch 15 taken 4 times.
8 << "\n";
132 1 }
133 try {
134
5/5
✓ Branch 1 taken 1 time.
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 13 taken 1 time.
1 out << "default: " << BackendName(DefaultBackend()) << "\n";
135
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ } catch (const std::invalid_argument& error) {
136
0/3
✗ Branch 1 not taken.
✗ Branch 5 not taken.
✗ Branch 8 not taken.
✗ err << "terraingen: " << error.what() << "\n";
137 ✗ return kExitFailure;
138 }
139 1 return kExitSuccess;
140 }
141
142 7 int Validate(const std::vector<std::string>& args, std::ostream& out, std::ostream& err) {
143
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 5 times.
7 if (args.size() != 2) {
144
1/1
✓ Branch 2 taken 2 times.
2 throw std::invalid_argument("validate needs exactly one configuration file");
145 }
146
1/1
✓ Branch 2 taken 5 times.
5 const std::filesystem::path path = args[1];
147
1/1
✓ Branch 1 taken 5 times.
5 return RunReporting(path, err, [&] {
148
1/1
✓ Branch 1 taken 4 times.
5 const TerrainConfig config = LoadConfig(path);
149
2/2
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 2 times.
6 const ConfigSummary summary = ValidateConfig(config, path.parent_path());
150
3/3
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 7 taken 2 times.
2 out << path.string() << " is valid: ";
151 2 std::vector<RasterGrid> grids;
152
2/2
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 2 times.
4 for (const std::optional<RasterGrid>& grid : summary.outputGrids) {
153
6/7
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 11 taken 1 time.
✓ Branch 12 taken 1 time.
✓ Branch 13 taken 1 time.
✓ Branch 14 taken 1 time.
2 if (grid && std::find(grids.begin(), grids.end(), *grid) == grids.end()) {
154
5/6
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
✓ Branch 15 taken 1 time.
1 out << (grids.empty() ? "a " : " and ") << grid->width << "x" << grid->height;
155
1/1
✓ Branch 2 taken 1 time.
1 grids.push_back(*grid);
156 }
157 }
158
4/5
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
2 out << (grids.empty() ? "no grids" : grids.size() == 1 ? " grid" : " grids");
159
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
2 if (summary.expectedCraters) {
160
2/2
✓ Branch 1 taken 1 time.
✓ Branch 5 taken 1 time.
1 out << ", about " << static_cast<long long>(*summary.expectedCraters)
161
1/1
✓ Branch 1 taken 1 time.
1 << " craters expected";
162 }
163
4/4
✓ Branch 1 taken 2 times.
✓ Branch 5 taken 2 times.
✓ Branch 8 taken 2 times.
✓ Branch 12 taken 2 times.
2 out << ", " << config.layers.size() << " layers and " << config.outputs.size()
164
1/1
✓ Branch 1 taken 2 times.
2 << " outputs\n";
165 14 });
166 5 }
167
168 } // namespace
169
170 15 unsigned ParseThreads(const std::string& text) {
171 15 std::size_t used = 0;
172 15 unsigned long value = 0;
173 try {
174
1/1
✓ Branch 1 taken 10 times.
15 value = std::stoul(text, &used);
175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 } catch (const std::exception&) {
176 5 used = 0;
177 5 }
178
10/10
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 1 time.
✓ Branch 6 taken 7 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 5 times.
✓ Branch 10 taken 10 times.
✓ Branch 11 taken 5 times.
15 if (used == 0 || used != text.size() || text.front() == '-' || value > 4096) {
179 throw std::invalid_argument(
180
3/3
✓ Branch 2 taken 10 times.
✓ Branch 5 taken 10 times.
✓ Branch 8 taken 10 times.
10 "--threads needs a count from 0 (every hardware thread) to 4096, not '" + text + "'");
181 }
182 5 return static_cast<unsigned>(value);
183 }
184
185 12 Backend ParseBackend(const std::string& text) {
186
3/3
✓ Branch 2 taken 12 times.
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 3 times.
12 if (const std::optional<Backend> backend = BackendNamed(text)) {
187 9 return *backend;
188 }
189 3 throw std::invalid_argument("--backend needs auto, cpu, gpu, vulkan, cuda or metal, not '" +
190
3/3
✓ Branch 2 taken 3 times.
✓ Branch 5 taken 3 times.
✓ Branch 8 taken 3 times.
6 text + "'");
191 }
192
193 12 GuiArgs ParseGuiArgs(const std::vector<std::string>& args) {
194 12 GuiArgs parsed;
195
2/2
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 3 times.
21 for (std::size_t i = 0; i < args.size(); ++i) {
196 18 const std::string& arg = args[i];
197 7 const auto value = [&]() -> const std::string& {
198
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 4 times.
7 if (i + 1 >= args.size()) {
199
2/2
✓ Branch 2 taken 3 times.
✓ Branch 5 taken 3 times.
3 throw std::invalid_argument(arg + " needs a value");
200 }
201 4 return args[++i];
202 18 };
203
3/3
✓ Branch 1 taken 18 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 14 times.
18 if (arg == "--threads") {
204
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 1 time.
4 parsed.threads = ParseThreads(value());
205
3/3
✓ Branch 1 taken 14 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 11 times.
14 } else if (arg == "--backend") {
206
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 1 time.
3 parsed.backend = ParseBackend(value());
207
3/3
✓ Branch 1 taken 11 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 9 times.
11 } else if (arg.rfind("--", 0) == 0) {
208
3/3
✓ Branch 2 taken 2 times.
✓ Branch 5 taken 2 times.
✓ Branch 8 taken 2 times.
2 throw std::invalid_argument("Unknown option " + arg + " with --gui");
209
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 7 times.
9 } else if (!parsed.open.empty()) {
210
2/2
✓ Branch 2 taken 2 times.
✓ Branch 5 taken 2 times.
2 throw std::invalid_argument("Unexpected argument " + arg);
211 } else {
212
1/1
✓ Branch 1 taken 7 times.
7 parsed.open = arg;
213 }
214 }
215 3 return parsed;
216 9 }
217
218 6 std::string Usage() {
219 return "Usage:\n"
220 " terraingen CONFIG [--output-dir DIR] [--log-level LEVEL] [--threads N]\n"
221 " [--backend auto|cpu|gpu|vulkan|cuda|metal]\n"
222 " Generate the terrain the JSON file CONFIG describes\n"
223 " terraingen validate CONFIG\n"
224 " Check CONFIG without generating\n"
225 " terraingen schema Print every configuration type with its defaults\n"
226 " terraingen backends Show where terrains can be evaluated here, and the default\n"
227 " terraingen [PATH] --gui [--threads N] [--backend auto|cpu|gpu|vulkan|cuda|metal]\n"
228 " Open the GUI on a configuration, GeoTIFF heights or the\n"
229 " starter terrain\n"
230 " terraingen -V, --version\n"
231 " Show version and build information\n"
232
1/1
✓ Branch 1 taken 6 times.
12 " terraingen -h, --help Show this message\n";
233 }
234
235 123 int Run(const std::vector<std::string>& args, std::ostream& out, std::ostream& err) {
236 try {
237
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 121 times.
123 if (args.empty()) {
238
1/1
✓ Branch 2 taken 2 times.
2 throw std::invalid_argument("Missing a command or configuration file");
239 }
240
1/1
✓ Branch 3 taken 121 times.
121 const auto gui = std::find(args.begin(), args.end(), "--gui");
241
2/2
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 113 times.
121 if (gui != args.end()) {
242
1/1
✓ Branch 2 taken 8 times.
8 std::vector<std::string> rest(args.begin(), gui);
243
1/1
✓ Branch 5 taken 8 times.
8 rest.insert(rest.end(), gui + 1, args.end());
244
1/1
✓ Branch 1 taken 1 time.
8 return RunGui(rest, out, err);
245 8 }
246 113 const std::string& first = args.front();
247
8/8
✓ Branch 1 taken 113 times.
✓ Branch 3 taken 108 times.
✓ Branch 4 taken 5 times.
✓ Branch 6 taken 108 times.
✓ Branch 8 taken 1 time.
✓ Branch 9 taken 107 times.
✓ Branch 10 taken 6 times.
✓ Branch 11 taken 107 times.
113 if (first == "--help" || first == "-h") {
248
2/2
✓ Branch 1 taken 6 times.
✓ Branch 4 taken 6 times.
6 out << Usage();
249 6 return kExitSuccess;
250 }
251
8/8
✓ Branch 1 taken 107 times.
✓ Branch 3 taken 106 times.
✓ Branch 4 taken 1 time.
✓ Branch 6 taken 106 times.
✓ Branch 8 taken 1 time.
✓ Branch 9 taken 105 times.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 105 times.
107 if (first == "--version" || first == "-V") {
252
1/1
✓ Branch 1 taken 2 times.
2 const Version version = GetVersion();
253
1/1
✓ Branch 1 taken 2 times.
2 const BuildInfo build = GetBuildInfo();
254
5/5
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 7 taken 2 times.
✓ Branch 10 taken 2 times.
✓ Branch 13 taken 2 times.
2 out << "TerrainGen " << version.major << "." << version.minor << "." << version.patch
255 2 << " (" << build.gitSha << (build.gitDirty ? "-dirty" : "") << ", "
256
8/9
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✓ Branch 12 taken 2 times.
✓ Branch 15 taken 2 times.
✓ Branch 18 taken 2 times.
✓ Branch 21 taken 2 times.
2 << build.buildDate << ")\n";
257 2 return kExitSuccess;
258 2 }
259
3/3
✓ Branch 1 taken 105 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 103 times.
105 if (first == "schema") {
260
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
2 if (args.size() != 1) {
261
1/1
✓ Branch 2 taken 1 time.
1 throw std::invalid_argument("schema takes no arguments");
262 }
263
2/2
✓ Branch 1 taken 1 time.
✓ Branch 4 taken 1 time.
1 out << ConfigCatalog();
264 1 return kExitSuccess;
265 }
266
3/3
✓ Branch 1 taken 103 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 101 times.
103 if (first == "backends") {
267
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
2 if (args.size() != 1) {
268
1/1
✓ Branch 2 taken 1 time.
1 throw std::invalid_argument("backends takes no arguments");
269 }
270
1/1
✓ Branch 1 taken 1 time.
1 return ListBackends(out, err);
271 }
272
3/3
✓ Branch 1 taken 101 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 94 times.
101 if (first == "validate") {
273
1/1
✓ Branch 1 taken 5 times.
7 return Validate(args, out, err);
274 }
275
1/1
✓ Branch 1 taken 83 times.
94 return Generate(args, out, err);
276
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 } catch (const std::invalid_argument& error) {
277
3/3
✓ Branch 1 taken 24 times.
✓ Branch 5 taken 24 times.
✓ Branch 8 taken 24 times.
24 err << "terraingen: " << error.what() << "\nRun 'terraingen --help' to see the usage.\n";
278 24 return kExitUsage;
279 24 }
280 }
281
282 } // namespace terraingen::cli
283