1#ifndef TEST_GENERATORS_HPP
2#define TEST_GENERATORS_HPP
4#pragma GCC diagnostic push
5#pragma GCC diagnostic ignored "-Wconversion"
7#include <rapidcheck/gtest.h>
9#pragma GCC diagnostic pop
46 static_assert(N > 0,
"N must be greater than 0");
49 gen::container<std::array<bool, N>>(gen::arbitrary<bool>()),
50 [](
const auto &booleans)
52 return std::any_of(booleans.begin(), booleans.end(), [](
const bool b)
82 return gen::container<std::array<bool, N>>(gen::just(
true));
84 return atLeastOneFalse<N>();
100inline auto IPv4Octet(
const bool valid =
true) -> Gen<int>
102 static constexpr int min_ipv4_octet = 0;
103 static constexpr int max_ipv4_octet = 255;
107 return gen::inRange(min_ipv4_octet, max_ipv4_octet + 1);
109 return gen::suchThat(gen::arbitrary<int>(), [](
const auto &i)
110 {
return i < min_ipv4_octet || i > max_ipv4_octet; });
129inline auto IPv4Address(
const bool valid =
true) -> Gen<std::string>
131 static constexpr int octets_number = 4;
132 static constexpr std::array<bool, octets_number> all_true = {
true,
true,
true,
true};
133 const auto octet_validity = valid ? all_true : *atLeastOneFalse<octets_number>().as(
"first,second,third,fourth octet valid");
140 [](
const auto &octets)
142 return std::to_string(std::get<0>(octets)) +
"." + std::to_string(std::get<1>(octets)) +
"."
143 + std::to_string(std::get<2>(octets)) +
"." + std::to_string(std::get<3>(octets));
161 static constexpr int ASCII_range_start_code = 32;
162 static constexpr int ASCII_range_end_code = 127;
163 static constexpr int ASCII_percent_sign_code = 37;
167 return gen::distinctFrom(gen::inRange(ASCII_range_start_code, ASCII_range_end_code), ASCII_percent_sign_code);
185inline auto hexChar(
const bool valid =
true) -> Gen<std::string>
189 const auto alphapositives = gen::elementOf(std::string(
"abcdefABCDEF123456789"));
191 static constexpr int probability_weight_of_0 = 23;
192 static constexpr int probability_weight_of_alphapositives = 1;
195 return gen::map(gen::weightedOneOf<char>({{probability_weight_of_0, gen::just<char>(
'0')},
196 {probability_weight_of_alphapositives, alphapositives}}),
199 return std::string{
static_cast<char>(c)};
205 {
return isxdigit(c) == 0; }),
208 return std::string{
static_cast<char>(c)};
228 static constexpr int hexchars_number = 4;
229 static constexpr std::array<bool, hexchars_number> all_true = {
true,
true,
true,
true};
230 const auto hexchar_validity = valid ? all_true : *atLeastOneFalse<hexchars_number>().as(
"first,second,third,fourth hexchar in hextet valid");
233 gen::tuple(
hexChar(hexchar_validity[0]),
237 [](
const auto &hexchars)
239 const auto &[first_hexchar, second_hexchar, third_hexchar, fourth_hexchar] = hexchars;
240 return first_hexchar + second_hexchar + third_hexchar + fourth_hexchar;
253 const auto first_nonzero = hextet.find_first_not_of(
'0');
254 return first_nonzero == std::string::npos ?
"0" : hextet.substr(first_nonzero);
280 for (
auto longest_zero_sequence = hextets.size(); longest_zero_sequence > 1; --longest_zero_sequence)
282 auto position = std::search_n(hextets.begin(), hextets.end(), longest_zero_sequence, std::string{
"0"});
283 if (position != hextets.end())
285 const auto it = hextets.insert(position,
"::");
286 hextets.erase(it + 1, std::next(it + 1, longest_zero_sequence));
305 for (
size_t i = 0; i < hextets.size(); ++i)
307 if (i > 0 && hextets[i] !=
"::" && hextets[i - 1] !=
"::")
311 result += hextets[i];
349inline auto IPv6Address(
const bool valid =
true) -> Gen<std::string>
351 static constexpr int number_of_hextets = 8;
352 static constexpr std::array<bool, number_of_hextets> all_true = {
true,
true,
true,
true,
true,
true,
true,
true};
353 const auto hextet_validity = valid ? all_true : *atLeastOneFalse<number_of_hextets>().as(
"first,second,third,fourth,fifth,sixth,seventh,eighth hextet valid");
355 auto convert_hextets_to_compressed_address = [](std::string first_hextet,
356 std::string second_hextet,
357 std::string third_hextet,
358 std::string fourth_hextet,
359 std::string fifth_hextet,
360 std::string sixth_hextet,
361 std::string seventh_hextet,
362 std::string eighth_hextet)
365 std::move(second_hextet),
366 std::move(third_hextet),
367 std::move(fourth_hextet),
368 std::move(fifth_hextet),
369 std::move(sixth_hextet),
370 std::move(seventh_hextet),
371 std::move(eighth_hextet)});
376 return gen::apply(convert_hextets_to_compressed_address,
386 return gen::map(gen::tuple(
395 [](
const auto &hextets)
397 const auto [first_hextet, second_hextet, third_hextet, fourth_hextet, fifth_hextet, sixth_hextet, seventh_hextet, eighth_hextet] = hextets;
398 return first_hextet +
":" + second_hextet +
":" + third_hextet +
":" + fourth_hextet +
":" + fifth_hextet +
":" + sixth_hextet +
":" + seventh_hextet +
":" + eighth_hextet;
421 static constexpr int number_of_flags = 9;
423 gen::container<std::vector<int>>(gen::inRange(0, number_of_flags + 1)),
424 [](
const auto &bit_positions)
427 for (
const auto &pos : bit_positions)
451 static auto arbitrary() -> Gen<openvpn::TunBuilderCapture::RouteBase>
474 static auto arbitrary() -> Gen<openvpn::TunBuilderCapture::Route>
494 static auto arbitrary() -> Gen<openvpn::TunBuilderCapture::RouteAddress>
519template <
typename T,
typename... Ts>
520struct Arbitrary<std::variant<T, Ts...>>
533 gen::cast<std::variant<T, Ts...>>(gen::arbitrary<T>()),
534 gen::cast<std::variant<T, Ts...>>(gen::arbitrary<Ts>())...);
538static const std::string
ALPHA_CHARACTERS =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
539static const std::string
DIGITS =
"1234567890";
556inline auto alpha(
const bool valid =
true) -> Gen<char>
562 return gen::suchThat(gen::character<char>(),
563 [](
const char character)
564 {
return !std::isalpha(character); });
581inline auto from_allowed_chars(
const std::string_view &allowed_chars,
const bool valid =
true) -> Gen<char>
585 return gen::elementOf(allowed_chars);
587 return gen::suchThat(gen::character<char>(),
588 [allowed_chars](
const char character)
589 {
return allowed_chars.find(character) == std::string::npos; });
615 return gen::suchThat(gen::string<std::string>(), [allowed_chars](
const auto &
string)
616 {
return std::any_of(
string.begin(),
string.end(), [allowed_chars](
const auto &character)
617 {
return allowed_chars.find(character) == std::string::npos; }); });
630inline auto port(
const bool valid =
true) -> Gen<int>
632 static constexpr int port_upper_bound = 65535;
633 static constexpr int port_lower_bound = 0;
635 return gen::inRange(port_lower_bound, port_upper_bound + 1);
636 return gen::suchThat<int>(
637 [](
const auto port_number)
638 {
return port_number < port_lower_bound || port_number > port_upper_bound; });
660 std::array<unsigned int, 4> addressParts{};
661 std::istringstream addressStream(ipAddress);
663 size_t partIndex = 0;
665 while (std::getline(addressStream, part,
'.'))
667 addressParts[partIndex++] = std::stoi(part);
670 const uint32_t addressInteger = (addressParts[0] << 24) | (addressParts[1] << 16) | (addressParts[2] << 8) | addressParts[3];
672 auto minimumPrefix = 32;
673 for (
auto bitPosition = 0; bitPosition < 32; ++bitPosition)
675 if (addressInteger & (1U << bitPosition))
677 minimumPrefix = 32 - bitPosition;
701inline auto genHost(
const bool valid =
true) -> Gen<std::string>
703 static constexpr size_t HOST_MAX_LENGTH = 256;
704 static constexpr size_t HOST_MIN_LENGTH = 1;
705 static constexpr size_t INVALID_MAX_LENGTH_LIMIT = 8192;
707 static const std::string allowed_chars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-:";
709 auto [valid_chars, valid_length] = valid ? *generateValidityFlags<2>() : *generateValidityFlags<2>(
false);
710 const auto length = valid_length ? *gen::inRange(HOST_MIN_LENGTH, HOST_MAX_LENGTH + 1) : *gen::inRange(HOST_MAX_LENGTH + 1, INVALID_MAX_LENGTH_LIMIT);
712 return gen::container<std::string>(length,
from_allowed_chars(allowed_chars, valid_chars));
755 const auto size = Addr::version_size(version);
756 return Addr::netmask_from_prefix_len(version, size - bit) & ~Addr::netmask_from_prefix_len(version, size - bit - 1);
767 return ~singleBit(version, cleared_bit);
771template <
typename Parse>
778 catch (
const openvpn::IP::AddrMaskPair::addr_pair_mask_parse_error &e)
826inline auto genDnsDomain(
const bool valid =
true) -> Gen<openvpn::DnsDomain>
829 gen::construct<openvpn::DnsDomain>(),
855inline auto genDnsAddress(
const bool valid =
true) -> Gen<openvpn::DnsAddress>
860 gen::maybe(
port(*rc::gen::arbitrary<bool>()))),
863 const auto &[address, maybe_port] = params;
868 result.
port = *maybe_port;
889 gen::maybe(
port(valid))),
890 [](
const auto ¶ms) -> std::string
892 const auto &[address, maybe_port] = params;
897 result.
port = *maybe_port;
919 static constexpr auto MAX_VECTOR_SIZE = 100;
921 gen::construct<openvpn::DnsServer>(),
923 gen::container<std::vector<openvpn::DnsAddress>>(
924 *gen::inRange<size_t>(0, MAX_VECTOR_SIZE),
927 gen::container<std::vector<openvpn::DnsDomain>>(
928 *gen::inRange<size_t>(0, MAX_VECTOR_SIZE),
950 static constexpr auto MAX_CONTAINER_SIZE = 100;
951 auto generateDnsServerMap = []() -> Gen<std::map<int, openvpn::DnsServer>>
955 gen::container<std::vector<openvpn::DnsServer>>(
956 *gen::inRange<size_t>(0, MAX_CONTAINER_SIZE),
958 gen::unique<std::vector<int>>(*gen::inRange<size_t>(0, MAX_CONTAINER_SIZE), gen::nonNegative<int>())),
959 [](
const auto ¶ms) -> std::map<int, openvpn::DnsServer>
961 const auto &[servers, priorities] = params;
962 std::map<int, openvpn::DnsServer> result;
964 for (
size_t i = 0; i < std::min(servers.size(), priorities.size()); ++i)
966 result[priorities[i]] = servers[i];
974 gen::construct<openvpn::DnsOptions>(),
977 gen::container<std::vector<openvpn::DnsDomain>>(
978 *gen::inRange<size_t>(0, MAX_CONTAINER_SIZE),
991 static auto arbitrary() -> Gen<openvpn::IP::Addr::Version>
1010 [](
const std::string &address)
1016 return gen::mapcat(gen::arbitrary<openvpn::IP::Addr::Version>(),
1017 [](
const auto version)
1036 static constexpr int bound_weight = 1;
1037 static constexpr int interior_weight = 6;
1038 return gen::weightedOneOf<unsigned int>({{bound_weight, gen::just(0U)},
1039 {bound_weight, gen::just(address_size)},
1040 {interior_weight, gen::inRange(0U, address_size + 1U)}});
1042 static constexpr unsigned int illegal_prefix_upper_bound = std::numeric_limits<unsigned int>::max();
1043 return gen::inRange(address_size + 1U, illegal_prefix_upper_bound);
1070 return gen::mapcat(gen::arbitrary<openvpn::IP::Addr::Version>(),
1071 [](
const auto version)
1084 const auto size = Addr::version_size(version);
1085 return gen::mapcat(gen::inRange(0U, size),
1086 [version, size](
const unsigned int prefix_len)
1089 [version,
prefix_len](
const Addr &addr,
const unsigned int host_bit)
1092 .netmask = Addr::netmask_from_prefix_len(version,
prefix_len)};
1114 [version](
const unsigned int cleared_bit)
1128 const auto asToken = [](Gen<unsigned int> prefix_length)
1130 return gen::map(std::move(prefix_length),
1139 gen::just(std::string{}));
1155 static constexpr int bare_address_weight = 1;
1156 static constexpr int mask_term_weight = 3;
1157 static constexpr int shape_weight = 1;
1159 const auto joined = [](
const std::string &address,
const std::string &mask)
1160 {
return address +
"/" + mask; };
1164 return gen::weightedOneOf<std::string>({{bare_address_weight,
genIPAddressString(version)},
1168 const auto three_terms = [](
const std::string &address,
const unsigned int first,
const unsigned int second)
1169 {
return address +
"/" + std::to_string(first) +
"/" + std::to_string(second); };
1173 [](
const std::string &address)
1176 return gen::weightedOneOf<std::string>({{shape_weight, malformed_address},
1179 {shape_weight, gen::just(std::string{})},
static Addr from_string(const std::string &ipstr, const TITLE &title, const Version required_version)
std::string to_string() const
static bool is_valid(const std::string &ipstr)
static Addr netmask_from_prefix_len(Version v, const unsigned int prefix_len)
static unsigned int version_size(Version v)
static constexpr unsigned int SIZE
Route address class that may use non-canonical form.
Base class for route-related functionality representing a network route.
Route class that must use canonical form.
auto nonContiguousNetmask(const openvpn::IP::Addr::Version version, const unsigned int cleared_bit) -> openvpn::IP::Addr
A mask of version with every bit set except cleared_bit.
constexpr auto otherVersion(const openvpn::IP::Addr::Version version) -> openvpn::IP::Addr::Version
The address version that is not version; UNSPEC maps to V4.
std::optional< std::string > rejectionMessageOf(Parse &&parse)
The diagnostic AddrMaskPair::from_string throws when parse calls it, or nullopt when it accepts.
auto genDnsServerTransport() -> Gen< openvpn::DnsServer::Transport >
Generates random DNS server transport.
auto genHost(const bool valid=true) -> Gen< std::string >
Generates a host string.
auto singleBit(const openvpn::IP::Addr::Version version, const unsigned int bit) -> openvpn::IP::Addr
The address of version with only bit set; bit 0 is the least significant.
auto genDnsServerSecurity() -> Gen< openvpn::DnsServer::Security >
Generates random DNS server security settings.
std::optional< std::string > rejectionMessageForTerms(const std::string &address, const std::string &mask)
Named apart from rejectionMessage: a literal "" second argument would otherwise bind to the title par...
std::optional< std::string > rejectionMessage(const std::string &input, const char *title=nullptr)
auto genIPAddressString(const openvpn::IP::Addr::Version version, const bool valid=true) -> Gen< std::string >
Generates an address string of version; valid is IPv4Address()/IPv6Address()'s.
auto calculateIPPrefixRange(const std::string &ipAddress) -> std::tuple< int, int >
Calculates the valid IP prefix range for a given IP address.
auto string_from_allowed_chars(const std::string_view &allowed_chars, const bool valid=true) -> Gen< std::string >
Generates strings based on allowed characters.
auto from_allowed_chars(const std::string_view &allowed_chars, const bool valid=true) -> Gen< char >
Generates characters based on an allowed character set.
std::string stringifyHextetsToAddressWithColons(const std::vector< std::string > &hextets)
Converts a vector of hextets to an IPv6 address string with colons.
auto IPv4Octet(const bool valid=true) -> Gen< int >
Generates a valid or invalid IPv4 octet value.
auto genDnsAddressAsStr(const bool valid=true) -> Gen< std::string >
Generates a DNS address as a string.
auto genAddrMaskPair(const openvpn::IP::Addr::Version version) -> Gen< openvpn::IP::AddrMaskPair >
Generates a well-formed AddrMaskPair of version: an address and a contiguous netmask.
auto genMaskToken(const openvpn::IP::Addr::Version version, const bool valid=true) -> Gen< std::string >
Generates the netmask term of an AddrMaskPair input for an address of version.
void replaceSequenceOfZerosWithDoubleColon(std::vector< std::string > &hextets)
Replaces the longest sequence of consecutive "0" strings in a vector with "::".
std::variant< openvpn::TunBuilderCapture::Route, openvpn::TunBuilderCapture::RouteAddress, openvpn::TunBuilderCapture::RouteBase > RouteBased
Alias representing a route-based variant type.
auto genNetmaskString(const openvpn::IP::Addr::Version version, const bool valid=true) -> Gen< std::string >
Generates a netmask of version rendered as an address string.
auto genNonCanonicalAddrMaskPair(const openvpn::IP::Addr::Version version) -> Gen< openvpn::IP::AddrMaskPair >
Generates a pair of version whose address has a host bit set, so is_canonical() is false.
std::string compressIPv6Address(std::vector< std::string > hextets)
Compress an IPv6 address by simplifying its representation.
auto genDNSOptions() -> Gen< openvpn::DnsOptions >
Generates random DNS options.
static const std::string ALPHA_CHARACTERS
std::string removeLeadingZerosFromHextet(const std::string &hextet)
Removes leading zeros from a hextet (IPv6 segment).
auto port(const bool valid=true) -> Gen< int >
Generates a port number value.
static const std::string DIGITS
void removeLeadingZerosFromHextets(std::vector< std::string > &hextets)
Removes leading zeros from a vector of hextets.
auto genDnsAddress(const bool valid=true) -> Gen< openvpn::DnsAddress >
Generates a DNS address.
auto genIPAddr() -> Gen< openvpn::IP::Addr >
auto hexChar(const bool valid=true) -> Gen< std::string >
Generates a valid or invalid hexadecimal character.
auto genDnsServer() -> Gen< openvpn::DnsServer >
Generates a DNS server.
auto genPrefixLength(const openvpn::IP::Addr::Version version, const bool valid=true) -> Gen< unsigned int >
Generates a prefix length for an address of version.
auto genAddrMaskPairString(const openvpn::IP::Addr::Version version, const bool valid=true) -> Gen< std::string >
Generates an AddrMaskPair::from_string input for an address of version.
auto atLeastOneFalse() -> Gen< std::array< bool, N > >
Generates an array of booleans that contains at least one false.
auto asciiPrintableCode() -> Gen< int >
Generates a random printable ASCII character code.
auto genDnsDomain(const bool valid=true) -> Gen< openvpn::DnsDomain >
Generates a DnsDomain.
auto generateValidityFlags(const bool all_valid=true) -> Gen< std::array< bool, N > >
Generates an array of validity flags for component testing.
auto IPv6HextetValue(const bool valid=true) -> Gen< std::string >
Generates a hextet value of an IPv6 address.
auto IPv4Address(const bool valid=true) -> Gen< std::string >
Generates a random IPv4 address.
auto IPv6Address(const bool valid=true) -> Gen< std::string >
Generates a random IPv6 address.
auto alpha(const bool valid=true) -> Gen< char >
Generates alphabetic or non-alphabetic characters.
A name server address and optional port.
std::string to_string() const
Return string representation of the IP address and port stored in the DnsAddress object.
std::map< int, DnsServer > servers
List of DNS servers to use, according to the list of priority.
std::vector< DnsDomain > search_domains
List of global DNS search domains to use.
bool from_dhcp_options
Set to true if the DNS options comes from –dhcp-option options.
std::vector< DnsAddress > addresses
Parsed from –dns server n address ADDRESS[:PORT] [...] or –dhcp-option DNS/DNS6.
std::vector< DnsDomain > domains
Parsed from –dns server n resolve-domains DOMAIN [...] or –dhcp-option DOMAIN/DOMAIN-SEARCH if use_se...
std::string sni
Parsed from –dns server n sni.
Security dnssec
Parsed from –dns server n dnssec {yes,optional,no}.
@ Yes
Enforce using DNSSEC.
@ Unset
Undefined setting; default value when not set.
@ Optional
Try to use DNSSEC opportunistically. If it fails, the DNS resolver may ignore DNSSEC.
@ TLS
Use DNS-over-TLS (DoT)
@ HTTPS
Use DNS-over-HTTPS (DoH)
@ Plain
Use the classic unencrypted DNS protocol.
@ Unset
Undefined setting; default value when not set.
Transport transport
Parsed from –dns server n transport {plain,DoT,DoH}.
static AddrMaskPair from_string(const std::string &s1, const std::string &s2, const char *title=nullptr)
static Gen< RedirectGatewayFlagsValues > arbitrary()
Generates an arbitrary RedirectGatewayFlagsValues.
static auto arbitrary() -> Gen< openvpn::IP::AddrMaskPair >
static auto arbitrary() -> Gen< openvpn::IP::Addr::Version >
static auto arbitrary() -> Gen< openvpn::TunBuilderCapture::RouteAddress >
Generates an arbitrary RouteAddress instance.
static auto arbitrary() -> Gen< openvpn::TunBuilderCapture::RouteBase >
Generates a value of type RouteBase.
static auto arbitrary() -> Gen< openvpn::TunBuilderCapture::Route >
Generates an arbitrary instance of TunBuilderCapture::Route.
static auto arbitrary() -> Gen< std::variant< T, Ts... > >
Generates an arbitrary std::variant containing one of the specified types.
static const char * input[]
int prefix_len(const IPv4::Addr::base_type mask)