Add project files.

This commit is contained in:
alejo committed 2026-08-18 18:33:08 -03:00
1 parent 9c60d1b47c
commit 40d55e00f2
11 files changed
+2099

No files matched your search

+144
View File
@@ -0,0 +1,144 @@
// Exercises the *registration-time* safety guards: things a programmer
// could get wrong while wiring up commands, which should fail loudly and
// clearly at startup rather than misbehaving at run time -- plus a few
// "this should now succeed" checks for behavior that's supposed to work.
#include <cstdio>
#include <optional>
#include <string>
#include <vector>
#include <cliforge/cliforge.hpp>
using cliforge::Command;
using cliforge::Engine;
using cliforge::RegistrationError;
enum class Color { Red, Green };
void noop(const std::string&) {}
void noop2(const std::string&, bool) {}
void noopOptStrStr(const std::optional<std::string>&, const std::string&) {}
void noopBoolOptVec(bool, const std::optional<std::string>&, const std::vector<std::string>&) {}
void noopWrongType(int32_t) {}
void noopColor(Color) {}
#define EXPECT_THROW(label, expr) \
do { \
try { \
expr; \
std::printf("[FAIL] %-45s did not throw\n", label); \
} catch (const RegistrationError& e) { \
std::printf("[ OK ] %-45s -> %s\n", label, e.what()); \
} \
} while (0)
#define EXPECT_OK(label, expr) \
do { \
try { \
expr; \
std::printf("[ OK ] %-45s (correctly did not throw)\n", label); \
} catch (const RegistrationError& e) { \
std::printf("[FAIL] %-45s threw: %s\n", label, e.what()); \
} \
} while (0)
int main() {
Engine cli;
EXPECT_THROW("keyword after flag", ({
cli.command()
.keyword("a")
.flag("x", '\0', "")
.keyword("b"); // keywords must come before flags/options
}));
EXPECT_THROW("keyword after variadic parameter", ({
cli.command()
.keyword("a")
.parameter<std::string>("p", "", /*variadic=*/true)
.keyword("b"); // variadic must be last in the structured part
}));
EXPECT_THROW("loose parameter after variadic loose parameter", ({
cli.command()
.keyword("a")
.flag("f", '\0', "")
.parameter<std::string>("p1", "", /*variadic=*/true)
.parameter<std::string>("p2", ""); // variadic must be the last parameter
}));
EXPECT_THROW("action() arity mismatch", ({
cli.command().keyword("a").parameter<std::string>("p", "").action(&noop2);
// noop2 takes 2 args, only 1 slot declared
}));
EXPECT_THROW("no keyword at all", ({
cli.command().parameter<std::string>("p", "").action(&noop);
// a command must have at least one keyword
}));
EXPECT_THROW("option bound to a required (bare) type", ({
cli.command().keyword("a").option<std::string>("o", '\0', "").action(&noop);
// options must be std::optional<T> or std::vector<T> -- never bare T
}));
EXPECT_THROW("declared type doesn't match action() type", ({
cli.command()
.keyword("a")
.parameter<std::string>("p", "")
.action(&noopWrongType); // declared string, action expects int32_t
}));
EXPECT_THROW("enum parameter without choices<T>()", ({
cli.command()
.keyword("a")
.parameter<Color>("c", "")
.action(&noopColor); // never called .choices<Color>(...)
}));
EXPECT_THROW("duplicate long flag name", ({
cli.command()
.keyword("a")
.flag("force", 'f', "")
.flag("force", 'g', "");
}));
EXPECT_THROW("duplicate short flag name", ({
cli.command()
.keyword("a")
.flag("force", 'f', "")
.flag("full", 'f', "");
}));
EXPECT_THROW("reserved --help name", ({ cli.command().keyword("a").flag("help", '\0', ""); }));
EXPECT_THROW("reserved -h short name", ({ cli.command().keyword("a").flag("x", 'h', ""); }));
EXPECT_THROW("invalid keyword charset", ({ cli.command().keyword("bad keyword!"); }));
EXPECT_THROW("keyword starting with dash", ({ cli.command().keyword("-bad"); }));
EXPECT_OK("parameter() after option() (loose parameter)", ({
cli.command()
.keyword("a")
.option<std::string>("o", '\0', "")
.parameter<std::string>("p", "")
.action(&noopOptStrStr);
}));
EXPECT_OK("flag/option/loose-parameter fully interleaved", ({
cli.command()
.keyword("b")
.flag("f", '\0', "")
.option<std::string>("o", '\0', "")
.parameter<std::string>("p", "", /*variadic=*/true)
.action(&noopBoolOptVec);
}));
EXPECT_OK("action() taking arguments by const reference", ({
cli.command().keyword("c").parameter<std::string>("p", "").action(&noop);
}));
std::printf("\nAll registration-guard checks completed.\n");
return 0;
}
+40
View File
@@ -0,0 +1,40 @@
#include <cstdint>
#include <cstdio>
#include <optional>
#include <string>
#include <vector>
#include <cliforge/cliforge.hpp>
using cliforge::Engine;
void allTypes(int8_t a, uint8_t b, int16_t c, uint16_t d, int32_t e, uint32_t f, int64_t g,
uint64_t h, float fl, double db, const std::string& s, char ch, bool bl) {
std::printf(
"i8=%d u8=%u i16=%d u16=%u i32=%d u32=%u i64=%lld u64=%llu f=%g d=%g s=%s c=%c b=%d\n",
a, b, c, d, e, f, static_cast<long long>(g), static_cast<unsigned long long>(h),
static_cast<double>(fl), db, s.c_str(), ch, bl);
}
int main(int argc, char** argv) {
Engine cli("typetest");
cli.command()
.keyword("all")
.parameter<int8_t>("a", "int8")
.parameter<uint8_t>("b", "uint8")
.parameter<int16_t>("c", "int16")
.parameter<uint16_t>("d", "uint16")
.parameter<int32_t>("e", "int32")
.parameter<uint32_t>("f", "uint32")
.parameter<int64_t>("g", "int64")
.parameter<uint64_t>("h", "uint64")
.parameter<float>("fl", "float32")
.parameter<double>("db", "float64")
.parameter<std::string>("s", "string")
.parameter<char>("ch", "char")
.flag("bl", 'b', "bool flag")
.describe("Exercises every scalar type")
.action(&allTypes);
return cli.run(argc, argv);
}