Просмотр исходного кода

refactor: extract curl and load functions

Sam Jaffe 3 недель назад
Родитель
Сommit
3907a1f4aa

+ 7 - 0
include/jvalidate/adapter.h

@@ -1,6 +1,8 @@
 #pragma once
 
 #include <cstdint>
+#include <filesystem>
+#include <fstream>
 #include <optional>
 #include <ostream>
 
@@ -382,6 +384,11 @@ public:
     return os;
   }
 };
+
+template <typename JSON> bool load_file(std::filesystem::path const & path, JSON & out) {
+  std::ifstream in(path);
+  return load_stream(in, out);
+}
 }
 
 namespace jvalidate::adapter::detail {

+ 10 - 0
include/jvalidate/adapters/jsoncpp.h

@@ -1,14 +1,24 @@
 #pragma once
 #include <type_traits>
 
+#include <json/reader.h>
 #include <json/value.h>
 
 #include <jvalidate/adapter.h>
+#include <jvalidate/detail/expect.h>
 #include <jvalidate/detail/number.h>
 #include <jvalidate/detail/simple_adapter.h>
 #include <jvalidate/enum.h>
 
 namespace jvalidate::adapter {
+template <> inline bool load_stream(std::istream & in, Json::Value & out) {
+  Json::CharReaderBuilder builder;
+  std::string error;
+  bool good = Json::parseFromStream(builder, in, &out, &error);
+  EXPECT_M(good, "Failed to load JSON: " << error);
+  return good;
+}
+
 template <typename JSON> class JsonCppAdapter;
 
 template <> struct AdapterTraits<Json::Value> {

+ 44 - 0
include/jvalidate/compat/curl.h

@@ -0,0 +1,44 @@
+#pragma once
+#include <sstream>
+#include <string_view>
+
+#include <curl/curl.h>
+
+#include <jvalidate/adapter.h>
+#include <jvalidate/forward.h>
+#include <jvalidate/uri.h>
+
+namespace jvalidate {
+inline size_t transfer_to_buffer(char * data, size_t size, size_t nmemb, void * userdata) {
+  std::stringstream & ss = *reinterpret_cast<std::stringstream *>(userdata);
+  size_t actual_size = size * nmemb;
+  ss << std::string_view(data, actual_size);
+  return actual_size;
+}
+
+template <typename JSON> bool curl_get(jvalidate::URI const & uri, JSON & out) {
+  using jvalidate::adapter::load_file;
+  using jvalidate::adapter::load_stream;
+  if (uri.scheme().starts_with("http")) {
+    std::stringstream ss;
+    if (CURL * curl = curl_easy_init(); curl) {
+      curl_easy_setopt(curl, CURLOPT_URL, uri.c_str());
+      curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+      curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ss);
+      curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &transfer_to_buffer);
+
+      CURLcode res = curl_easy_perform(curl);
+      curl_easy_cleanup(curl);
+
+      if (res == CURLE_OK) {
+        return load_stream(ss, out);
+      }
+    }
+    return false;
+  } else if (uri.scheme() == "file") {
+    return load_file(uri.resource(), out);
+  } else {
+    return false;
+  }
+}
+}

+ 2 - 0
include/jvalidate/forward.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include <functional>
+#include <iosfwd>
 #include <string>
 #include <type_traits>
 #include <variant>
@@ -32,6 +33,7 @@ template <typename> struct AdapterTraits;
 template <typename V> struct AdapterTraits<V const> : AdapterTraits<V> {};
 
 template <typename JSON> using AdapterFor = typename AdapterTraits<JSON>::template Adapter<JSON>;
+template <typename JSON> bool load_stream(std::istream & in, JSON & out);
 }
 
 namespace jvalidate::schema {

+ 8 - 47
src/validate.cxx

@@ -1,7 +1,6 @@
 #include <cstdio>
 #include <cstdlib>
 #include <filesystem>
-#include <fstream>
 #include <iostream>
 #include <sstream>
 #include <stdexcept>
@@ -11,57 +10,19 @@
 
 #include <jvalidate/adapter.h>
 #include <jvalidate/adapters/jsoncpp.h>
+#include <jvalidate/compat/curl.h>
 #include <jvalidate/enum.h>
+#include <jvalidate/forward.h>
 #include <jvalidate/schema.h>
 #include <jvalidate/status.h>
 #include <jvalidate/uri.h>
 #include <jvalidate/validator.h>
 
-#include <json/reader.h>
 #include <json/value.h>
 #include <json/writer.h>
 
-bool load_stream(std::istream & in, Json::Value & out) {
-  Json::CharReaderBuilder builder;
-  std::string error;
-  return Json::parseFromStream(builder, in, &out, &error);
-}
-
-bool load_file(std::filesystem::path const & path, Json::Value & out) {
-  std::ifstream in(path);
-  return load_stream(in, out);
-}
-
-size_t transfer_to_buffer(char * data, size_t size, size_t nmemb, void * userdata) {
-  std::stringstream & ss = *reinterpret_cast<std::stringstream *>(userdata);
-  size_t actual_size = size * nmemb;
-  ss << std::string_view(data, actual_size);
-  return actual_size;
-}
-
-bool curl_get(jvalidate::URI const & uri, Json::Value & out) {
-  if (uri.scheme().starts_with("http")) {
-    std::stringstream ss;
-    if (CURL * curl = curl_easy_init(); curl) {
-      curl_easy_setopt(curl, CURLOPT_URL, uri.c_str());
-      curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
-      curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ss);
-      curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &transfer_to_buffer);
-
-      CURLcode res = curl_easy_perform(curl);
-      curl_easy_cleanup(curl);
-
-      if (res == CURLE_OK) {
-        return load_stream(ss, out);
-      }
-    }
-    return false;
-  } else if (uri.scheme() == "file") {
-    return load_file(uri.resource(), out);
-  } else {
-    return false;
-  }
-}
+using jvalidate::adapter::load_file;
+using jvalidate::adapter::load_stream;
 
 struct ProgramArgs {
   ProgramArgs(std::string_view program, std::vector<std::string_view> args) {
@@ -105,7 +66,7 @@ int main(int argc, char const * const * argv) {
   }
 
   using enum jvalidate::schema::Version;
-  jvalidate::Schema schema(jschema, Draft2020_12, &curl_get);
+  jvalidate::Schema schema(jschema, Draft2020_12, &jvalidate::curl_get<Json::Value>);
 
   jvalidate::ValidationResult result;
   bool compact_error = !args.verbose && !args.format_as_explaination;
@@ -135,14 +96,14 @@ int main(int argc, char const * const * argv) {
 
   Json::Value out;
   for (Json::Value & elem : json["details"]) {
-    if (!elem.isMember("errors") || elem["valid"].asBool()) {
+    if (!elem.isMember("errors")) {
       continue;
     }
 
     for (std::string const & path = elem["evaluationPath"].asString();
          auto const & [key, reason] : because) {
-      if (path.starts_with(key)) {
-        elem["because"] = reason;
+      if (path.starts_with(key) && path != reason["evaluationPath"].asString()) {
+        elem["because"].append(reason);
       }
     }
 

+ 3 - 39
tests/selfvalidate_test.cxx

@@ -1,15 +1,14 @@
 #include <cstdio>
 #include <cstdlib>
 #include <filesystem>
-#include <fstream>
 #include <iostream>
 
-#include <curl/curl.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 #include <jvalidate/adapter.h>
 #include <jvalidate/adapters/jsoncpp.h>
+#include <jvalidate/compat/curl.h>
 #include <jvalidate/enum.h>
 #include <jvalidate/schema.h>
 #include <jvalidate/status.h>
@@ -27,50 +26,15 @@ using jvalidate::schema::Version;
 
 using testing::TestWithParam;
 
-bool load_stream(std::istream & in, Json::Value & out) {
-  Json::CharReaderBuilder builder;
-  std::string error;
-  return Json::parseFromStream(builder, in, &out, &error);
-}
-
-bool load_file(std::filesystem::path const & path, Json::Value & out) {
-  std::ifstream in(path);
-  return load_stream(in, out);
-}
-
-size_t transfer_to_buffer(char * data, size_t size, size_t nmemb, void * userdata) {
-  std::stringstream & ss = *reinterpret_cast<std::stringstream *>(userdata);
-  size_t actual_size = size * nmemb;
-  ss << std::string_view(data, actual_size);
-  return actual_size;
-}
+using jvalidate::adapter::load_file;
 
 bool load_external_for_test(jvalidate::URI const & uri, Json::Value & out) {
   constexpr std::string_view g_fake_url = "localhost:1234/";
   if (uri.scheme().starts_with("http") && uri.resource().starts_with(g_fake_url)) {
     std::string_view path = uri.resource().substr(g_fake_url.size());
     return load_file(JSONSchemaTestSuiteDir() / "remotes" / path, out);
-  } else if (uri.scheme().starts_with("http")) {
-    std::stringstream ss;
-    if (CURL * curl = curl_easy_init(); curl) {
-      curl_easy_setopt(curl, CURLOPT_URL, uri.c_str());
-      curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
-      curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ss);
-      curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &transfer_to_buffer);
-
-      CURLcode res = curl_easy_perform(curl);
-      curl_easy_cleanup(curl);
-
-      if (res == CURLE_OK) {
-        return load_stream(ss, out);
-      }
-    }
-    return false;
-  } else if (uri.scheme() == "file") {
-    return load_file(uri.resource(), out);
-  } else {
-    return false;
   }
+  return jvalidate::curl_get(uri, out);
 }
 
 class JsonSchema : public TestWithParam<SchemaParams> {