diff --git a/src/metadata.cpp b/src/metadata.cpp index cb232846..db80888d 100644 --- a/src/metadata.cpp +++ b/src/metadata.cpp @@ -47,6 +47,59 @@ size_t getTextLength(const std::string& utf8EncodedString) return icu::UnicodeString::fromUTF8(utf8EncodedString).length(); } +bool checkTextLanguage(const std::string& text, const std::string& langCode) +{ + // TODO: check that text is in langCode's script + return true; +} + +class MetadataComplexCheckBase +{ +public: + const std::string description; + const MetadataComplexCheckBase* const prev; + +public: // functions + explicit MetadataComplexCheckBase(const std::string& desc) + : description(desc) + , prev(last) + { + last = this; + } + + virtual ~MetadataComplexCheckBase() = default; + + virtual bool checkMetadata(const Metadata& m) const = 0; + + static const MetadataComplexCheckBase* getLastCheck() { return last; } + +private: // functions + static const MetadataComplexCheckBase* last; +}; + +const MetadataComplexCheckBase* MetadataComplexCheckBase::last = nullptr; + +#define ADD_METADATA_COMPLEX_CHECK(DESC, CLSNAME) \ +class CLSNAME : public MetadataComplexCheckBase \ +{ \ +public: \ + CLSNAME() : MetadataComplexCheckBase(DESC) {} \ + bool checkMetadata(const Metadata& data) const override; \ +}; \ + \ +const CLSNAME CONCAT(obj, CLSNAME); \ + \ +bool CLSNAME::checkMetadata(const Metadata& data) const \ +/* should be followed by the check body */ + + + +#define CONCAT(X, Y) X##Y +#define GENCLSNAME(UUID) CONCAT(MetadataComplexCheck, UUID) + +#define METADATA_ASSERT(DESC) ADD_METADATA_COMPLEX_CHECK(DESC, GENCLSNAME(__LINE__)) + + #include "metadata_constraints.cpp" } // unnamed namespace @@ -124,13 +177,29 @@ Metadata::Errors Metadata::checkSimpleConstraints() const return errors; } +Metadata::Errors Metadata::checkComplexConstraints() const +{ + Errors errors; + const MetadataComplexCheckBase* c = MetadataComplexCheckBase::getLastCheck(); + for ( ; c != nullptr ; c = c->prev ) { + if ( ! c->checkMetadata(*this) ) { + errors.push_back(c->description); + } + } + return errors; +} + Metadata::Errors Metadata::check() const { Errors e = checkMandatoryMetadata(); if ( !e.empty() ) return e; - return checkSimpleConstraints(); + e = checkSimpleConstraints(); + if ( !e.empty() ) + return e; + + return checkComplexConstraints(); } } // namespace zim diff --git a/src/metadata.h b/src/metadata.h index ec14cc62..e782a486 100644 --- a/src/metadata.h +++ b/src/metadata.h @@ -59,6 +59,7 @@ class Metadata private: // functions Errors checkMandatoryMetadata() const; Errors checkSimpleConstraints() const; + Errors checkComplexConstraints() const; private: // data std::map data; diff --git a/src/metadata_constraints.cpp b/src/metadata_constraints.cpp index 8604dc08..123c5eca 100644 --- a/src/metadata_constraints.cpp +++ b/src/metadata_constraints.cpp @@ -24,3 +24,16 @@ const Metadata::ReservedMetadataTable reservedMetadataInfoTable = { PNG_REGEXP }, }; + +METADATA_ASSERT("LongDescription shouldn't be shorter than Description") +{ + return !data.has("LongDescription") + || data["LongDescription"].size() >= data["Description"].size(); +} + +METADATA_ASSERT("Description must be in the language of the ZIM file") +{ + const auto lang = data["Language"]; + const auto description = data["Description"]; + return checkTextLanguage(description, lang); +} diff --git a/test/metadata-test.cpp b/test/metadata-test.cpp index 078d9a8c..a46eef4f 100644 --- a/test/metadata-test.cpp +++ b/test/metadata-test.cpp @@ -128,3 +128,16 @@ TEST(Metadata, regexpConstraints) m.set("Language", "fre,nch"); ASSERT_TRUE(m.valid()); } + +TEST(Metadata, complexConstraints) +{ + zim::Metadata m = makeValidMetadata(); + m.set("Description", "Short description"); + m.set("LongDescription", "Long description"); + ASSERT_FALSE(m.valid()); + ASSERT_EQ(m.check(), + zim::Metadata::Errors({ + "LongDescription shouldn't be shorter than Description" + }) + ); +}