1 /*
2 * Copyright (c) 2016-present, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under both the BSD-style license (found in the
6 * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7 * in the COPYING file in the root directory of this source tree).
8 */
9 #include "Options.h"
10
11 #include <array>
12 #include <gtest/gtest.h>
13
14 using namespace pzstd;
15
16 namespace pzstd {
operator ==(const Options & lhs,const Options & rhs)17 bool operator==(const Options &lhs, const Options &rhs) {
18 return lhs.numThreads == rhs.numThreads &&
19 lhs.maxWindowLog == rhs.maxWindowLog &&
20 lhs.compressionLevel == rhs.compressionLevel &&
21 lhs.decompress == rhs.decompress && lhs.inputFiles == rhs.inputFiles &&
22 lhs.outputFile == rhs.outputFile && lhs.overwrite == rhs.overwrite &&
23 lhs.keepSource == rhs.keepSource && lhs.writeMode == rhs.writeMode &&
24 lhs.checksum == rhs.checksum && lhs.verbosity == rhs.verbosity;
25 }
26
operator <<(std::ostream & out,const Options & opt)27 std::ostream &operator<<(std::ostream &out, const Options &opt) {
28 out << "{";
29 {
30 out << "\n\t"
31 << "numThreads: " << opt.numThreads;
32 out << ",\n\t"
33 << "maxWindowLog: " << opt.maxWindowLog;
34 out << ",\n\t"
35 << "compressionLevel: " << opt.compressionLevel;
36 out << ",\n\t"
37 << "decompress: " << opt.decompress;
38 out << ",\n\t"
39 << "inputFiles: {";
40 {
41 bool first = true;
42 for (const auto &file : opt.inputFiles) {
43 if (!first) {
44 out << ",";
45 }
46 first = false;
47 out << "\n\t\t" << file;
48 }
49 }
50 out << "\n\t}";
51 out << ",\n\t"
52 << "outputFile: " << opt.outputFile;
53 out << ",\n\t"
54 << "overwrite: " << opt.overwrite;
55 out << ",\n\t"
56 << "keepSource: " << opt.keepSource;
57 out << ",\n\t"
58 << "writeMode: " << static_cast<int>(opt.writeMode);
59 out << ",\n\t"
60 << "checksum: " << opt.checksum;
61 out << ",\n\t"
62 << "verbosity: " << opt.verbosity;
63 }
64 out << "\n}";
65 return out;
66 }
67 }
68
69 namespace {
70 #ifdef _WIN32
71 const char nullOutput[] = "nul";
72 #else
73 const char nullOutput[] = "/dev/null";
74 #endif
75
76 constexpr auto autoMode = Options::WriteMode::Auto;
77 } // anonymous namespace
78
79 #define EXPECT_SUCCESS(...) EXPECT_EQ(Options::Status::Success, __VA_ARGS__)
80 #define EXPECT_FAILURE(...) EXPECT_EQ(Options::Status::Failure, __VA_ARGS__)
81 #define EXPECT_MESSAGE(...) EXPECT_EQ(Options::Status::Message, __VA_ARGS__)
82
83 template <typename... Args>
makeArray(Args...args)84 std::array<const char *, sizeof...(Args) + 1> makeArray(Args... args) {
85 return {{nullptr, args...}};
86 }
87
TEST(Options,ValidInputs)88 TEST(Options, ValidInputs) {
89 {
90 Options options;
91 auto args = makeArray("--processes", "5", "-o", "x", "y", "-f");
92 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
93 Options expected = {5, 23, 3, false, {"y"}, "x",
94 true, true, autoMode, true, 2};
95 EXPECT_EQ(expected, options);
96 }
97 {
98 Options options;
99 auto args = makeArray("-p", "1", "input", "-19");
100 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
101 Options expected = {1, 23, 19, false, {"input"}, "",
102 false, true, autoMode, true, 2};
103 EXPECT_EQ(expected, options);
104 }
105 {
106 Options options;
107 auto args =
108 makeArray("--ultra", "-22", "-p", "1", "-o", "x", "-d", "x.zst", "-f");
109 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
110 Options expected = {1, 0, 22, true, {"x.zst"}, "x",
111 true, true, autoMode, true, 2};
112 EXPECT_EQ(expected, options);
113 }
114 {
115 Options options;
116 auto args = makeArray("--processes", "100", "hello.zst", "--decompress",
117 "--force");
118 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
119 Options expected = {100, 23, 3, true, {"hello.zst"}, "", true,
120 true, autoMode, true, 2};
121 EXPECT_EQ(expected, options);
122 }
123 {
124 Options options;
125 auto args = makeArray("x", "-dp", "1", "-c");
126 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
127 Options expected = {1, 23, 3, true, {"x"}, "-",
128 false, true, autoMode, true, 2};
129 EXPECT_EQ(expected, options);
130 }
131 {
132 Options options;
133 auto args = makeArray("x", "-dp", "1", "--stdout");
134 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
135 Options expected = {1, 23, 3, true, {"x"}, "-",
136 false, true, autoMode, true, 2};
137 EXPECT_EQ(expected, options);
138 }
139 {
140 Options options;
141 auto args = makeArray("-p", "1", "x", "-5", "-fo", "-", "--ultra", "-d");
142 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
143 Options expected = {1, 0, 5, true, {"x"}, "-",
144 true, true, autoMode, true, 2};
145 EXPECT_EQ(expected, options);
146 }
147 {
148 Options options;
149 auto args = makeArray("silesia.tar", "-o", "silesia.tar.pzstd", "-p", "2");
150 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
151 Options expected = {2,
152 23,
153 3,
154 false,
155 {"silesia.tar"},
156 "silesia.tar.pzstd",
157 false,
158 true,
159 autoMode,
160 true,
161 2};
162 EXPECT_EQ(expected, options);
163 }
164 {
165 Options options;
166 auto args = makeArray("x", "-p", "1");
167 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
168 }
169 {
170 Options options;
171 auto args = makeArray("x", "-p", "1");
172 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
173 }
174 }
175
TEST(Options,GetOutputFile)176 TEST(Options, GetOutputFile) {
177 {
178 Options options;
179 auto args = makeArray("x");
180 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
181 EXPECT_EQ("x.zst", options.getOutputFile(options.inputFiles[0]));
182 }
183 {
184 Options options;
185 auto args = makeArray("x", "y", "-o", nullOutput);
186 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
187 EXPECT_EQ(nullOutput, options.getOutputFile(options.inputFiles[0]));
188 }
189 {
190 Options options;
191 auto args = makeArray("x.zst", "-do", nullOutput);
192 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
193 EXPECT_EQ(nullOutput, options.getOutputFile(options.inputFiles[0]));
194 }
195 {
196 Options options;
197 auto args = makeArray("x.zst", "-d");
198 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
199 EXPECT_EQ("x", options.getOutputFile(options.inputFiles[0]));
200 }
201 {
202 Options options;
203 auto args = makeArray("xzst", "-d");
204 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
205 EXPECT_EQ("", options.getOutputFile(options.inputFiles[0]));
206 }
207 {
208 Options options;
209 auto args = makeArray("xzst", "-doxx");
210 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
211 EXPECT_EQ("xx", options.getOutputFile(options.inputFiles[0]));
212 }
213 }
214
TEST(Options,MultipleFiles)215 TEST(Options, MultipleFiles) {
216 {
217 Options options;
218 auto args = makeArray("x", "y", "z");
219 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
220 Options expected;
221 expected.inputFiles = {"x", "y", "z"};
222 expected.verbosity = 1;
223 EXPECT_EQ(expected, options);
224 }
225 {
226 Options options;
227 auto args = makeArray("x", "y", "z", "-o", nullOutput);
228 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
229 Options expected;
230 expected.inputFiles = {"x", "y", "z"};
231 expected.outputFile = nullOutput;
232 expected.verbosity = 1;
233 EXPECT_EQ(expected, options);
234 }
235 {
236 Options options;
237 auto args = makeArray("x", "y", "-o-");
238 EXPECT_FAILURE(options.parse(args.size(), args.data()));
239 }
240 {
241 Options options;
242 auto args = makeArray("x", "y", "-o", "file");
243 EXPECT_FAILURE(options.parse(args.size(), args.data()));
244 }
245 {
246 Options options;
247 auto args = makeArray("-qqvd12qp4", "-f", "x", "--", "--rm", "-c");
248 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
249 Options expected = {4, 23, 12, true, {"x", "--rm", "-c"},
250 "", true, true, autoMode, true,
251 0};
252 EXPECT_EQ(expected, options);
253 }
254 }
255
TEST(Options,NumThreads)256 TEST(Options, NumThreads) {
257 {
258 Options options;
259 auto args = makeArray("x", "-dfo", "-");
260 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
261 }
262 {
263 Options options;
264 auto args = makeArray("x", "-p", "0", "-fo", "-");
265 EXPECT_FAILURE(options.parse(args.size(), args.data()));
266 }
267 {
268 Options options;
269 auto args = makeArray("-f", "-p", "-o", "-");
270 EXPECT_FAILURE(options.parse(args.size(), args.data()));
271 }
272 }
273
TEST(Options,BadCompressionLevel)274 TEST(Options, BadCompressionLevel) {
275 {
276 Options options;
277 auto args = makeArray("x", "-20");
278 EXPECT_FAILURE(options.parse(args.size(), args.data()));
279 }
280 {
281 Options options;
282 auto args = makeArray("x", "--ultra", "-23");
283 EXPECT_FAILURE(options.parse(args.size(), args.data()));
284 }
285 {
286 Options options;
287 auto args = makeArray("x", "--1"); // negative 1?
288 EXPECT_FAILURE(options.parse(args.size(), args.data()));
289 }
290 }
291
TEST(Options,InvalidOption)292 TEST(Options, InvalidOption) {
293 {
294 Options options;
295 auto args = makeArray("x", "-x");
296 EXPECT_FAILURE(options.parse(args.size(), args.data()));
297 }
298 }
299
TEST(Options,BadOutputFile)300 TEST(Options, BadOutputFile) {
301 {
302 Options options;
303 auto args = makeArray("notzst", "-d", "-p", "1");
304 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
305 EXPECT_EQ("", options.getOutputFile(options.inputFiles.front()));
306 }
307 }
308
TEST(Options,BadOptionsWithArguments)309 TEST(Options, BadOptionsWithArguments) {
310 {
311 Options options;
312 auto args = makeArray("x", "-pf");
313 EXPECT_FAILURE(options.parse(args.size(), args.data()));
314 }
315 {
316 Options options;
317 auto args = makeArray("x", "-p", "10f");
318 EXPECT_FAILURE(options.parse(args.size(), args.data()));
319 }
320 {
321 Options options;
322 auto args = makeArray("x", "-p");
323 EXPECT_FAILURE(options.parse(args.size(), args.data()));
324 }
325 {
326 Options options;
327 auto args = makeArray("x", "-o");
328 EXPECT_FAILURE(options.parse(args.size(), args.data()));
329 }
330 {
331 Options options;
332 auto args = makeArray("x", "-o");
333 EXPECT_FAILURE(options.parse(args.size(), args.data()));
334 }
335 }
336
TEST(Options,KeepSource)337 TEST(Options, KeepSource) {
338 {
339 Options options;
340 auto args = makeArray("x", "--rm", "-k");
341 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
342 EXPECT_EQ(true, options.keepSource);
343 }
344 {
345 Options options;
346 auto args = makeArray("x", "--rm", "--keep");
347 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
348 EXPECT_EQ(true, options.keepSource);
349 }
350 {
351 Options options;
352 auto args = makeArray("x");
353 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
354 EXPECT_EQ(true, options.keepSource);
355 }
356 {
357 Options options;
358 auto args = makeArray("x", "--rm");
359 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
360 EXPECT_EQ(false, options.keepSource);
361 }
362 }
363
TEST(Options,Verbosity)364 TEST(Options, Verbosity) {
365 {
366 Options options;
367 auto args = makeArray("x");
368 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
369 EXPECT_EQ(2, options.verbosity);
370 }
371 {
372 Options options;
373 auto args = makeArray("--quiet", "-qq", "x");
374 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
375 EXPECT_EQ(-1, options.verbosity);
376 }
377 {
378 Options options;
379 auto args = makeArray("x", "y");
380 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
381 EXPECT_EQ(1, options.verbosity);
382 }
383 {
384 Options options;
385 auto args = makeArray("--", "x", "y");
386 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
387 EXPECT_EQ(1, options.verbosity);
388 }
389 {
390 Options options;
391 auto args = makeArray("-qv", "x", "y");
392 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
393 EXPECT_EQ(1, options.verbosity);
394 }
395 {
396 Options options;
397 auto args = makeArray("-v", "x", "y");
398 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
399 EXPECT_EQ(3, options.verbosity);
400 }
401 {
402 Options options;
403 auto args = makeArray("-v", "x");
404 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
405 EXPECT_EQ(3, options.verbosity);
406 }
407 }
408
TEST(Options,TestMode)409 TEST(Options, TestMode) {
410 {
411 Options options;
412 auto args = makeArray("x", "-t");
413 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
414 EXPECT_EQ(true, options.keepSource);
415 EXPECT_EQ(true, options.decompress);
416 EXPECT_EQ(nullOutput, options.outputFile);
417 }
418 {
419 Options options;
420 auto args = makeArray("x", "--test", "--rm", "-ohello");
421 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
422 EXPECT_EQ(true, options.keepSource);
423 EXPECT_EQ(true, options.decompress);
424 EXPECT_EQ(nullOutput, options.outputFile);
425 }
426 }
427
TEST(Options,Checksum)428 TEST(Options, Checksum) {
429 {
430 Options options;
431 auto args = makeArray("x.zst", "--no-check", "-Cd");
432 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
433 EXPECT_EQ(true, options.checksum);
434 }
435 {
436 Options options;
437 auto args = makeArray("x");
438 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
439 EXPECT_EQ(true, options.checksum);
440 }
441 {
442 Options options;
443 auto args = makeArray("x", "--no-check", "--check");
444 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
445 EXPECT_EQ(true, options.checksum);
446 }
447 {
448 Options options;
449 auto args = makeArray("x", "--no-check");
450 EXPECT_SUCCESS(options.parse(args.size(), args.data()));
451 EXPECT_EQ(false, options.checksum);
452 }
453 }
454
TEST(Options,InputFiles)455 TEST(Options, InputFiles) {
456 {
457 Options options;
458 auto args = makeArray("-cd");
459 options.parse(args.size(), args.data());
460 EXPECT_EQ(1, options.inputFiles.size());
461 EXPECT_EQ("-", options.inputFiles[0]);
462 EXPECT_EQ("-", options.outputFile);
463 }
464 {
465 Options options;
466 auto args = makeArray();
467 options.parse(args.size(), args.data());
468 EXPECT_EQ(1, options.inputFiles.size());
469 EXPECT_EQ("-", options.inputFiles[0]);
470 EXPECT_EQ("-", options.outputFile);
471 }
472 {
473 Options options;
474 auto args = makeArray("-d");
475 options.parse(args.size(), args.data());
476 EXPECT_EQ(1, options.inputFiles.size());
477 EXPECT_EQ("-", options.inputFiles[0]);
478 EXPECT_EQ("-", options.outputFile);
479 }
480 {
481 Options options;
482 auto args = makeArray("x", "-");
483 EXPECT_FAILURE(options.parse(args.size(), args.data()));
484 }
485 }
486
TEST(Options,InvalidOptions)487 TEST(Options, InvalidOptions) {
488 {
489 Options options;
490 auto args = makeArray("-ibasdf");
491 EXPECT_FAILURE(options.parse(args.size(), args.data()));
492 }
493 {
494 Options options;
495 auto args = makeArray("- ");
496 EXPECT_FAILURE(options.parse(args.size(), args.data()));
497 }
498 {
499 Options options;
500 auto args = makeArray("-n15");
501 EXPECT_FAILURE(options.parse(args.size(), args.data()));
502 }
503 {
504 Options options;
505 auto args = makeArray("-0", "x");
506 EXPECT_FAILURE(options.parse(args.size(), args.data()));
507 }
508 }
509
TEST(Options,Extras)510 TEST(Options, Extras) {
511 {
512 Options options;
513 auto args = makeArray("-h");
514 EXPECT_MESSAGE(options.parse(args.size(), args.data()));
515 }
516 {
517 Options options;
518 auto args = makeArray("-H");
519 EXPECT_MESSAGE(options.parse(args.size(), args.data()));
520 }
521 {
522 Options options;
523 auto args = makeArray("-V");
524 EXPECT_MESSAGE(options.parse(args.size(), args.data()));
525 }
526 {
527 Options options;
528 auto args = makeArray("--help");
529 EXPECT_MESSAGE(options.parse(args.size(), args.data()));
530 }
531 {
532 Options options;
533 auto args = makeArray("--version");
534 EXPECT_MESSAGE(options.parse(args.size(), args.data()));
535 }
536 }
537