Formatted includes/services/postal_code

This commit is contained in:
Aaron Po
2026-07-19 04:10:32 -04:00
parent 86db1c2827
commit 74f848d015
3 changed files with 66 additions and 65 deletions

View File

@@ -24,56 +24,57 @@
* example that fails validation, throws so the caller can skip the city. * example that fails validation, throws so the caller can skip the city.
*/ */
class MockPostalCodeService final : public IPostalCodeService { class MockPostalCodeService final : public IPostalCodeService {
public: public:
std::string GeneratePostalCode(const City& city) override { std::string GeneratePostalCode(const City& city) override {
const PostalCodeSpec& spec = city.postal_code; const PostalCodeSpec& spec = city.postal_code;
if (spec.examples.empty()) { if (spec.examples.empty()) {
throw std::runtime_error(std::format( throw std::runtime_error(std::format(
"No postal-code examples available for city '{}'", city.city)); "No postal-code examples available for city '{}'", city.city));
}
const std::string& candidate = spec.examples.front();
if (!MatchesAnyPattern(candidate, spec)) {
throw std::runtime_error(
std::format("Postal code '{}' for city '{}' does not match the "
"curated postal-code regex",
candidate, city.city));
}
return candidate;
}
private:
/**
* @brief Returns true if @p candidate matches any city regex, or the
* country format regex when no city regex matches. When the spec carries no
* usable regex at all, validation is skipped (returns true).
*/
static bool MatchesAnyPattern(const std::string& candidate,
const PostalCodeSpec& spec) {
bool has_pattern = false;
for (const std::string& pattern : spec.city_regexes) {
if (pattern.empty()) {
continue;
} }
has_pattern = true;
if (std::regex_match(candidate, std::regex(pattern))) {
return true;
}
}
if (!spec.country_format_regex.empty()) { const std::string& candidate = spec.examples.front();
has_pattern = true;
if (std::regex_match(candidate, std::regex(spec.country_format_regex))) {
return true;
}
}
return !has_pattern; if (!MatchesAnyPattern(candidate, spec)) {
} throw std::runtime_error(
std::format("Postal code '{}' for city '{}' does not match the "
"curated postal-code regex",
candidate, city.city));
}
return candidate;
}
private:
/**
* @brief Returns true if @p candidate matches any city regex, or the
* country format regex when no city regex matches. When the spec carries no
* usable regex at all, validation is skipped (returns true).
*/
static bool MatchesAnyPattern(const std::string& candidate,
const PostalCodeSpec& spec) {
bool has_pattern = false;
for (const std::string& pattern : spec.city_regexes) {
if (pattern.empty()) {
continue;
}
has_pattern = true;
if (std::regex_match(candidate, std::regex(pattern))) {
return true;
}
}
if (!spec.country_format_regex.empty()) {
has_pattern = true;
if (std::regex_match(candidate,
std::regex(spec.country_format_regex))) {
return true;
}
}
return !has_pattern;
}
}; };
#endif // BIERGARTEN_PIPELINE_INCLUDES_SERVICES_POSTAL_CODE_MOCK_POSTAL_CODE_SERVICE_H_ #endif // BIERGARTEN_PIPELINE_INCLUDES_SERVICES_POSTAL_CODE_MOCK_POSTAL_CODE_SERVICE_H_

View File

@@ -14,22 +14,22 @@
* @brief Interface for services that resolve a postal code for a city. * @brief Interface for services that resolve a postal code for a city.
*/ */
class IPostalCodeService { class IPostalCodeService {
public: public:
IPostalCodeService() = default; IPostalCodeService() = default;
virtual ~IPostalCodeService() = default; virtual ~IPostalCodeService() = default;
IPostalCodeService(const IPostalCodeService&) = delete; IPostalCodeService(const IPostalCodeService&) = delete;
IPostalCodeService& operator=(const IPostalCodeService&) = delete; IPostalCodeService& operator=(const IPostalCodeService&) = delete;
IPostalCodeService(IPostalCodeService&&) = delete; IPostalCodeService(IPostalCodeService&&) = delete;
IPostalCodeService& operator=(IPostalCodeService&&) = delete; IPostalCodeService& operator=(IPostalCodeService&&) = delete;
/** /**
* @brief Resolves a postal code for @p city. * @brief Resolves a postal code for @p city.
* *
* @param city City whose curated postal-code examples supply the result. * @param city City whose curated postal-code examples supply the result.
* @return A postal code string, or an empty string if none is available. * @return A postal code string, or an empty string if none is available.
*/ */
virtual std::string GeneratePostalCode(const City& city) = 0; virtual std::string GeneratePostalCode(const City& city) = 0;
}; };
#endif // BIERGARTEN_PIPELINE_INCLUDES_SERVICES_POSTAL_CODE_POSTAL_CODE_SERVICE_H_ #endif // BIERGARTEN_PIPELINE_INCLUDES_SERVICES_POSTAL_CODE_POSTAL_CODE_SERVICE_H_

View File

@@ -20,13 +20,13 @@
* via GenerateStringFromRegex(). * via GenerateStringFromRegex().
*/ */
class XegerPostalCodeService final : public IPostalCodeService { class XegerPostalCodeService final : public IPostalCodeService {
public: public:
XegerPostalCodeService(); XegerPostalCodeService();
std::string GeneratePostalCode(const City& city) override; std::string GeneratePostalCode(const City& city) override;
private: private:
std::mt19937 rng_; std::mt19937 rng_;
}; };
#endif // BIERGARTEN_PIPELINE_INCLUDES_SERVICES_POSTAL_CODE_XEGER_POSTAL_CODE_SERVICE_H_ #endif // BIERGARTEN_PIPELINE_INCLUDES_SERVICES_POSTAL_CODE_XEGER_POSTAL_CODE_SERVICE_H_