diff --git a/src/index/explorer.h b/src/index/explorer.h index 4c7d7cc8..f6d583e2 100644 --- a/src/index/explorer.h +++ b/src/index/explorer.h @@ -17,6 +17,7 @@ #include // std::lround #include // std::memcpy #include // std::filesystem +#include // std::numeric_limits #include // std::accumulate #include // std::optional #include // std::regex, std::regex_search, std::smatch @@ -222,6 +223,15 @@ static auto make_explorer_schema_extension( const std::string_view dialect, const std::string_view title, const std::string_view description, const std::string_view alert, const std::string_view provenance) -> std::vector { + assert(path.size() <= std::numeric_limits::max()); + assert(identifier.size() <= std::numeric_limits::max()); + assert(base_dialect.size() <= std::numeric_limits::max()); + assert(dialect.size() <= std::numeric_limits::max()); + assert(title.size() <= std::numeric_limits::max()); + assert(description.size() <= std::numeric_limits::max()); + assert(alert.size() <= std::numeric_limits::max()); + assert(provenance.size() <= std::numeric_limits::max()); + const auto strings_size{ path.size() + identifier.size() + base_dialect.size() + dialect.size() + title.size() + description.size() + alert.size() + provenance.size()}; @@ -273,9 +283,13 @@ struct GENERATE_EXPLORER_SCHEMA_METADATA { const auto &resolver_entry{resolver.entry(action.data)}; // Read the schema to get data and bytes sourcemeta::core::FileView schema_view{action.dependencies.front()}; - const auto schema_info{sourcemeta::one::metapack_info(schema_view)}; - const auto schema_data{ + const auto schema_info_option{sourcemeta::one::metapack_info(schema_view)}; + assert(schema_info_option.has_value()); + const auto &schema_info{schema_info_option.value()}; + const auto schema_data_option{ sourcemeta::one::metapack_read_json(action.dependencies.front())}; + assert(schema_data_option.has_value()); + const auto &schema_data{schema_data_option.value()}; const auto id{sourcemeta::core::identify( schema_data, [&callback, &resolver](const auto identifier) { return resolver(identifier, callback); @@ -337,12 +351,16 @@ struct GENERATE_EXPLORER_SCHEMA_METADATA { result.assign("examples", std::move(examples_array)); } - const auto health{ + const auto health_option{ sourcemeta::one::metapack_read_json(action.dependencies.at(1))}; + assert(health_option.has_value()); + const auto &health{health_option.value()}; result.assign("health", health.at("score")); - const auto schema_dependencies{ + const auto schema_dependencies_option{ sourcemeta::one::metapack_read_json(action.dependencies.at(2))}; + assert(schema_dependencies_option.has_value()); + const auto &schema_dependencies{schema_dependencies_option.value()}; result.assign("dependencies", sourcemeta::core::to_json(schema_dependencies.size())); @@ -499,7 +517,10 @@ struct GENERATE_EXPLORER_DIRECTORY_LIST { dependency.parent_path().parent_path().filename().string()}; if (filename == "directory.metapack") { - auto directory_json{sourcemeta::one::metapack_read_json(dependency)}; + auto directory_json_option{ + sourcemeta::one::metapack_read_json(dependency)}; + assert(directory_json_option.has_value()); + auto directory_json{std::move(directory_json_option.value())}; assert(directory_json.is_object()); assert(directory_json.defines("health")); assert(directory_json.at("health").is_integer()); diff --git a/src/index/generators.h b/src/index/generators.h index 633510a1..9213d037 100644 --- a/src/index/generators.h +++ b/src/index/generators.h @@ -28,6 +28,7 @@ #include // std::memcpy #include // std::filesystem #include // std::ofstream +#include // std::numeric_limits #include // std::unique_ptr #include // std::mutex, std::lock_guard #include // std::queue @@ -47,6 +48,7 @@ struct MetapackDialectExtension { static auto make_dialect_extension(const std::string_view dialect) -> std::vector { + assert(dialect.size() <= std::numeric_limits::max()); std::vector result; result.resize(sizeof(MetapackDialectExtension) + dialect.size()); MetapackDialectExtension header{}; @@ -179,8 +181,10 @@ struct GENERATE_POINTER_POSITIONS { const sourcemeta::one::Configuration &, const sourcemeta::core::JSON &) -> bool { const auto timestamp_start{std::chrono::steady_clock::now()}; - const auto schema{ + const auto schema_option{ sourcemeta::one::metapack_read_json(action.dependencies.front())}; + assert(schema_option.has_value()); + const auto &schema{schema_option.value()}; std::ostringstream schema_stream; sourcemeta::core::prettify(schema, schema_stream); sourcemeta::core::PointerPositionTracker tracker; @@ -204,8 +208,10 @@ struct GENERATE_FRAME_LOCATIONS { const sourcemeta::one::Configuration &, const sourcemeta::core::JSON &) -> bool { const auto timestamp_start{std::chrono::steady_clock::now()}; - const auto contents{ + const auto contents_option{ sourcemeta::one::metapack_read_json(action.dependencies.front())}; + assert(contents_option.has_value()); + const auto &contents{contents_option.value()}; std::ostringstream contents_stream; sourcemeta::core::prettify(contents, contents_stream); sourcemeta::core::PointerPositionTracker tracker; @@ -235,8 +241,10 @@ struct GENERATE_DEPENDENCIES { const sourcemeta::one::Configuration &, const sourcemeta::core::JSON &) -> bool { const auto timestamp_start{std::chrono::steady_clock::now()}; - const auto contents{ + const auto contents_option{ sourcemeta::one::metapack_read_json(action.dependencies.front())}; + assert(contents_option.has_value()); + const auto &contents{contents_option.value()}; auto result{sourcemeta::core::JSON::make_array()}; sourcemeta::core::dependencies( contents, sourcemeta::core::schema_walker, @@ -290,7 +298,10 @@ struct GENERATE_DEPENDENTS { std::unordered_set>; DirectMap direct; for (const auto &dependency : action.dependencies) { - const auto contents{sourcemeta::one::metapack_read_json(dependency)}; + const auto contents_option{ + sourcemeta::one::metapack_read_json(dependency)}; + assert(contents_option.has_value()); + const auto &contents{contents_option.value()}; assert(contents.is_array()); for (const auto &entry : contents.as_array()) { direct[entry.at("to").to_string()].emplace( @@ -356,8 +367,10 @@ struct GENERATE_HEALTH { const sourcemeta::one::Configuration &, const sourcemeta::core::JSON &) -> bool { const auto timestamp_start{std::chrono::steady_clock::now()}; - const auto contents{ + const auto contents_option{ sourcemeta::one::metapack_read_json(action.dependencies.front())}; + assert(contents_option.has_value()); + const auto &contents{contents_option.value()}; const auto &collection{*resolver.entry(action.data).collection}; auto &cache_entry{bundle_for(collection, resolver, callback)}; auto errors{sourcemeta::core::JSON::make_array()}; @@ -454,8 +467,10 @@ struct GENERATE_BUNDLE { const sourcemeta::one::Configuration &, const sourcemeta::core::JSON &) -> bool { const auto timestamp_start{std::chrono::steady_clock::now()}; - auto schema{ + auto schema_option{ sourcemeta::one::metapack_read_json(action.dependencies.front())}; + assert(schema_option.has_value()); + auto schema{std::move(schema_option.value())}; sourcemeta::core::bundle(schema, sourcemeta::core::schema_walker, [&callback, &resolver](const auto identifier) { return resolver(identifier, callback); @@ -489,8 +504,10 @@ struct GENERATE_EDITOR { const sourcemeta::one::Configuration &, const sourcemeta::core::JSON &) -> bool { const auto timestamp_start{std::chrono::steady_clock::now()}; - auto schema{ + auto schema_option{ sourcemeta::one::metapack_read_json(action.dependencies.front())}; + assert(schema_option.has_value()); + auto schema{std::move(schema_option.value())}; sourcemeta::core::for_editor(schema, sourcemeta::core::schema_walker, [&callback, &resolver](const auto identifier) { return resolver(identifier, callback); @@ -521,8 +538,10 @@ static auto generate_blaze_template( const sourcemeta::one::BuildPlan::Action::Dependencies &dependencies, const sourcemeta::blaze::Mode mode) -> void { const auto timestamp_start{std::chrono::steady_clock::now()}; - const auto contents{ + const auto contents_option{ sourcemeta::one::metapack_read_json(dependencies.front())}; + assert(contents_option.has_value()); + const auto &contents{contents_option.value()}; sourcemeta::core::SchemaFrame frame{ sourcemeta::core::SchemaFrame::Mode::References}; frame.analyse(contents, sourcemeta::core::schema_walker, @@ -574,8 +593,10 @@ struct GENERATE_STATS { const sourcemeta::one::Configuration &, const sourcemeta::core::JSON &) -> bool { const auto timestamp_start{std::chrono::steady_clock::now()}; - const auto schema{ + const auto schema_option{ sourcemeta::one::metapack_read_json(action.dependencies.front())}; + assert(schema_option.has_value()); + const auto &schema{schema_option.value()}; std::map> result; diff --git a/src/index/index.cc b/src/index/index.cc index 2326fc83..826932d8 100644 --- a/src/index/index.cc +++ b/src/index/index.cc @@ -428,7 +428,10 @@ static auto index_main(const std::string_view &program, if (entry.is_regular_file() && entry.path().extension() == ".metapack") { try { sourcemeta::core::FileView file_view{entry.path()}; - const auto file_info{sourcemeta::one::metapack_info(file_view)}; + const auto file_info_option{ + sourcemeta::one::metapack_info(file_view)}; + assert(file_info_option.has_value()); + const auto &file_info{file_info_option.value()}; durations.emplace_back(entry.path(), file_info.duration); } catch (...) { std::cerr << "Could not profile file: " << entry.path() << "\n"; diff --git a/src/metapack/include/sourcemeta/one/metapack.h b/src/metapack/include/sourcemeta/one/metapack.h index ae352f28..678a1d18 100644 --- a/src/metapack/include/sourcemeta/one/metapack.h +++ b/src/metapack/include/sourcemeta/one/metapack.h @@ -12,6 +12,7 @@ #include // std::chrono #include // std::uint8_t, std::uint16_t, std::uint32_t, etc. #include // std::filesystem::path +#include // std::optional #include // std::span #include // std::string_view #include // std::vector @@ -88,14 +89,15 @@ auto metapack_write_file(const std::filesystem::path &destination, SOURCEMETA_ONE_METAPACK_EXPORT auto metapack_read_json(const std::filesystem::path &path) - -> sourcemeta::core::JSON; + -> std::optional; SOURCEMETA_ONE_METAPACK_EXPORT -auto metapack_info(const sourcemeta::core::FileView &view) -> MetapackInfo; +auto metapack_info(const sourcemeta::core::FileView &view) + -> std::optional; SOURCEMETA_ONE_METAPACK_EXPORT auto metapack_payload_offset(const sourcemeta::core::FileView &view) - -> std::size_t; + -> std::optional; SOURCEMETA_ONE_METAPACK_EXPORT auto metapack_extension_offset(const sourcemeta::core::FileView &view) diff --git a/src/metapack/metapack.cc b/src/metapack/metapack.cc index 618542aa..39d74a9f 100644 --- a/src/metapack/metapack.cc +++ b/src/metapack/metapack.cc @@ -8,8 +8,8 @@ #include // assert #include // std::memcpy #include // std::ofstream +#include // std::optional, std::nullopt #include // std::ostringstream, std::stringstream -#include // std::runtime_error #include // std::string #include // std::string_view @@ -162,8 +162,10 @@ auto metapack_extension_offset(const sourcemeta::core::FileView &view) } const auto *header{view.as()}; - assert(header->magic == METAPACK_MAGIC); - assert(header->format_version == METAPACK_VERSION); + if (header->magic != METAPACK_MAGIC || + header->format_version != METAPACK_VERSION) { + return 0; + } const auto offset_of_extension_size{sizeof(MetapackHeader) + header->mime_length}; @@ -171,13 +173,18 @@ auto metapack_extension_offset(const sourcemeta::core::FileView &view) return 0; } - const auto *extension_size_pointer{ - view.as(offset_of_extension_size)}; - if (*extension_size_pointer == 0) { + const auto extension_size{*view.as(offset_of_extension_size)}; + if (extension_size == 0) { + return 0; + } + + const auto extension_data_offset{offset_of_extension_size + + sizeof(std::uint32_t)}; + if (extension_data_offset + extension_size > view.size()) { return 0; } - return offset_of_extension_size + sizeof(std::uint32_t); + return extension_data_offset; } auto metapack_extension_size(const sourcemeta::core::FileView &view) @@ -187,7 +194,10 @@ auto metapack_extension_size(const sourcemeta::core::FileView &view) } const auto *header{view.as()}; - assert(header->magic == METAPACK_MAGIC); + if (header->magic != METAPACK_MAGIC || + header->format_version != METAPACK_VERSION) { + return 0; + } const auto offset_of_extension_size{sizeof(MetapackHeader) + header->mime_length}; @@ -199,27 +209,27 @@ auto metapack_extension_size(const sourcemeta::core::FileView &view) } auto metapack_read_json(const std::filesystem::path &path) - -> sourcemeta::core::JSON { + -> std::optional { sourcemeta::core::FileView view{path}; if (view.size() < sizeof(MetapackHeader) + sizeof(std::uint32_t)) { - throw std::runtime_error("Metapack file too small"); + return std::nullopt; } const auto *header{view.as()}; - if (header->magic != METAPACK_MAGIC) { - throw std::runtime_error("Invalid metapack magic"); + if (header->magic != METAPACK_MAGIC || + header->format_version != METAPACK_VERSION) { + return std::nullopt; } - if (header->format_version != METAPACK_VERSION) { - throw std::runtime_error("Unsupported metapack version"); + auto payload_offset{sizeof(MetapackHeader) + header->mime_length}; + if (payload_offset + sizeof(std::uint32_t) > view.size()) { + return std::nullopt; } - auto payload_offset{sizeof(MetapackHeader) + header->mime_length}; const auto *extension_size{view.as(payload_offset)}; payload_offset += sizeof(std::uint32_t) + *extension_size; - if (payload_offset > view.size()) { - throw std::runtime_error("Metapack header extends past file end"); + return std::nullopt; } const auto payload_data_size{view.size() - payload_offset}; @@ -239,11 +249,21 @@ auto metapack_read_json(const std::filesystem::path &path) return sourcemeta::core::parse_json(payload_string); } -auto metapack_info(const sourcemeta::core::FileView &view) -> MetapackInfo { - assert(view.size() >= sizeof(MetapackHeader) + sizeof(std::uint32_t)); +auto metapack_info(const sourcemeta::core::FileView &view) + -> std::optional { + if (view.size() < sizeof(MetapackHeader) + sizeof(std::uint32_t)) { + return std::nullopt; + } + const auto *header{view.as()}; - assert(header->magic == METAPACK_MAGIC); - assert(header->format_version == METAPACK_VERSION); + if (header->magic != METAPACK_MAGIC || + header->format_version != METAPACK_VERSION) { + return std::nullopt; + } + + if (sizeof(MetapackHeader) + header->mime_length > view.size()) { + return std::nullopt; + } std::string checksum_hex; checksum_hex.reserve(64); @@ -270,14 +290,27 @@ auto metapack_info(const sourcemeta::core::FileView &view) -> MetapackInfo { } auto metapack_payload_offset(const sourcemeta::core::FileView &view) - -> std::size_t { - assert(view.size() >= sizeof(MetapackHeader) + sizeof(std::uint32_t)); + -> std::optional { + if (view.size() < sizeof(MetapackHeader) + sizeof(std::uint32_t)) { + return std::nullopt; + } + const auto *header{view.as()}; - assert(header->magic == METAPACK_MAGIC); + if (header->magic != METAPACK_MAGIC || + header->format_version != METAPACK_VERSION) { + return std::nullopt; + } auto offset{sizeof(MetapackHeader) + header->mime_length}; + if (offset + sizeof(std::uint32_t) > view.size()) { + return std::nullopt; + } + const auto *extension_size{view.as(offset)}; offset += sizeof(std::uint32_t) + *extension_size; + if (offset > view.size()) { + return std::nullopt; + } return offset; } diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc index 061fb9ce..9e9986ab 100644 --- a/src/resolver/resolver.cc +++ b/src/resolver/resolver.cc @@ -121,8 +121,10 @@ auto Resolver::operator()( if (result->second.cache_path.has_value()) { // We can guarantee the cached outcome is JSON, so we don't need to try // reading as YAML - auto schema{ + auto schema_option{ sourcemeta::one::metapack_read_json(result->second.cache_path.value())}; + assert(schema_option.has_value()); + auto schema{std::move(schema_option.value())}; assert(sourcemeta::core::is_schema(schema)); if (callback) { callback(result->second.cache_path.value()); diff --git a/src/server/action_jsonschema_evaluate.h b/src/server/action_jsonschema_evaluate.h index b88dc9ed..f11a8ea1 100644 --- a/src/server/action_jsonschema_evaluate.h +++ b/src/server/action_jsonschema_evaluate.h @@ -33,7 +33,10 @@ auto trace(sourcemeta::blaze::Evaluator &evaluator, auto locations_path{template_path.parent_path() / "locations.metapack"}; // TODO: Cache this across runs? - const auto locations{sourcemeta::one::metapack_read_json(locations_path)}; + const auto locations_option{ + sourcemeta::one::metapack_read_json(locations_path)}; + assert(locations_option.has_value()); + const auto &locations{locations_option.value()}; if (!locations.is_object() || !locations.defines("static")) { throw std::runtime_error("Failed to read schema locations metadata"); } @@ -144,7 +147,9 @@ auto evaluate(const std::filesystem::path &template_path, // TODO: Cache this conversion across runs, potentially using the schema file // "checksum" as the cache key. This is important as the template might be // compressed - const auto template_json{metapack_read_json(template_path)}; + const auto template_json_option{metapack_read_json(template_path)}; + assert(template_json_option.has_value()); + const auto &template_json{template_json_option.value()}; const auto schema_template{sourcemeta::blaze::from_json(template_json)}; if (!schema_template.has_value()) { throw std::runtime_error("Failed to parse schema template"); diff --git a/src/server/action_schema_search.h b/src/server/action_schema_search.h index 5378cc8f..bb2ab66a 100644 --- a/src/server/action_schema_search.h +++ b/src/server/action_schema_search.h @@ -30,7 +30,9 @@ static auto search(const std::filesystem::path &search_index, assert(search_index.is_absolute()); sourcemeta::core::FileView view{search_index}; - const auto payload_start{metapack_payload_offset(view)}; + const auto payload_start_option{metapack_payload_offset(view)}; + assert(payload_start_option.has_value()); + const auto &payload_start{payload_start_option.value()}; const auto payload_size{view.size() - payload_start}; // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) const std::string_view payload{ diff --git a/src/server/action_serve_metapack_file.h b/src/server/action_serve_metapack_file.h index 67145405..cbc1ab1b 100644 --- a/src/server/action_serve_metapack_file.h +++ b/src/server/action_serve_metapack_file.h @@ -52,6 +52,11 @@ static auto action_serve_metapack_file( } const auto info{sourcemeta::one::metapack_info(view)}; + if (!info.has_value()) { + json_error(request, response, sourcemeta::one::STATUS_NOT_FOUND, + "not-found", "There is nothing at this URL"); + return; + } // Note that `If-Modified-Since` can only be used with a `GET` or `HEAD`. // See @@ -61,7 +66,7 @@ static auto action_serve_metapack_file( // to more consistent behavior. if (if_modified_since.has_value() && (if_modified_since.value() + std::chrono::seconds(1)) >= - info.last_modified) { + info->last_modified) { response.write_status(sourcemeta::one::STATUS_NOT_MODIFIED); if (enable_cors) { response.write_header("Access-Control-Allow-Origin", "*"); @@ -71,7 +76,7 @@ static auto action_serve_metapack_file( return; } - const auto &checksum{info.checksum_hex}; + const auto &checksum{info->checksum_hex}; std::ostringstream etag_value_strong; std::ostringstream etag_value_weak; etag_value_strong << '"' << checksum << '"'; @@ -100,11 +105,11 @@ static auto action_serve_metapack_file( if (mime.has_value()) { response.write_header("Content-Type", mime.value()); } else { - response.write_header("Content-Type", info.mime); + response.write_header("Content-Type", info->mime); } response.write_header("Last-Modified", - sourcemeta::core::to_gmt(info.last_modified)); + sourcemeta::core::to_gmt(info->last_modified)); std::ostringstream etag; etag << '"' << checksum << '"'; @@ -117,8 +122,11 @@ static auto action_serve_metapack_file( } else { const auto *dialect_ext{ sourcemeta::one::metapack_extension(view)}; + const auto extension_total{sourcemeta::one::metapack_extension_size(view)}; const std::string_view dialect = - (dialect_ext != nullptr && dialect_ext->dialect_length > 0) + (dialect_ext != nullptr && dialect_ext->dialect_length > 0 && + sizeof(MetapackDialectExtension) + dialect_ext->dialect_length <= + extension_total) ? std::string_view{reinterpret_cast< const char *>(view.as( sourcemeta::one::metapack_extension_offset( @@ -132,13 +140,19 @@ static auto action_serve_metapack_file( } const auto payload_start{sourcemeta::one::metapack_payload_offset(view)}; - const auto payload_size{view.size() - payload_start}; + if (!payload_start.has_value()) { + json_error(request, response, sourcemeta::one::STATUS_NOT_FOUND, + "not-found", "There is nothing at this URL"); + return; + } + + const auto payload_size{view.size() - payload_start.value()}; // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - const std::string contents{ - reinterpret_cast(view.as(payload_start)), - payload_size}; + const std::string contents{reinterpret_cast( + view.as(payload_start.value())), + payload_size}; - if (info.encoding == sourcemeta::one::MetapackEncoding::GZIP) { + if (info->encoding == sourcemeta::one::MetapackEncoding::GZIP) { send_response(code, request, response, contents, sourcemeta::one::Encoding::GZIP); } else { diff --git a/src/web/pages/directory.cc b/src/web/pages/directory.cc index fca65f36..989f5a14 100644 --- a/src/web/pages/directory.cc +++ b/src/web/pages/directory.cc @@ -7,6 +7,7 @@ #include #include +#include // assert #include // std::chrono #include // std::filesystem @@ -20,7 +21,9 @@ auto GENERATE_WEB_DIRECTORY::handler( const sourcemeta::core::JSON &) -> bool { const auto timestamp_start{std::chrono::steady_clock::now()}; - const auto directory{metapack_read_json(action.dependencies.front())}; + const auto directory_option{metapack_read_json(action.dependencies.front())}; + assert(directory_option.has_value()); + const auto &directory{directory_option.value()}; const auto &canonical{directory.at("url").to_string()}; const auto &title{directory.defines("title") ? directory.at("title").to_string() diff --git a/src/web/pages/index.cc b/src/web/pages/index.cc index 7bcde3cb..1077267a 100644 --- a/src/web/pages/index.cc +++ b/src/web/pages/index.cc @@ -7,6 +7,7 @@ #include #include +#include // assert #include // std::chrono #include // std::filesystem #include // std::ostringstream @@ -37,7 +38,9 @@ auto GENERATE_WEB_INDEX::handler( const sourcemeta::core::JSON &) -> bool { const auto timestamp_start{std::chrono::steady_clock::now()}; - const auto directory{metapack_read_json(action.dependencies.front())}; + const auto directory_option{metapack_read_json(action.dependencies.front())}; + assert(directory_option.has_value()); + const auto &directory{directory_option.value()}; const auto &canonical{directory.at("url").to_string()}; const auto title{configuration.html->name + " Schemas"}; const auto &description{configuration.html->description}; diff --git a/src/web/pages/schema.cc b/src/web/pages/schema.cc index 2c93e775..fbe786f0 100644 --- a/src/web/pages/schema.cc +++ b/src/web/pages/schema.cc @@ -23,7 +23,9 @@ auto GENERATE_WEB_SCHEMA::handler( const sourcemeta::core::JSON &) -> bool { const auto timestamp_start{std::chrono::steady_clock::now()}; - const auto meta{metapack_read_json(action.dependencies.front())}; + const auto meta_option{metapack_read_json(action.dependencies.front())}; + assert(meta_option.has_value()); + const auto &meta{meta_option.value()}; const auto &canonical{meta.at("identifier").to_string()}; const auto &title{meta.defines("title") ? meta.at("title").to_string() : meta.at("path").to_string()}; @@ -196,7 +198,9 @@ auto GENERATE_WEB_SCHEMA::handler( {"data-sourcemeta-ui-editor-language", "json"}}, "Loading schema...")); - const auto health{metapack_read_json(action.dependencies.at(1))}; + const auto health_option{metapack_read_json(action.dependencies.at(1))}; + assert(health_option.has_value()); + const auto &health{health_option.value()}; assert(health.is_object()); assert(health.defines("errors")); diff --git a/test/unit/metapack/metapack_test.cc b/test/unit/metapack/metapack_test.cc index e9c394a8..18eb37e6 100644 --- a/test/unit/metapack/metapack_test.cc +++ b/test/unit/metapack/metapack_test.cc @@ -26,7 +26,7 @@ TEST(Metapack, write_and_read_json_identity) { sourcemeta::one::MetapackEncoding::Identity, {}, std::chrono::milliseconds{5}); - const auto result{sourcemeta::one::metapack_read_json(path)}; + const auto result{sourcemeta::one::metapack_read_json(path).value()}; EXPECT_TRUE(result.is_object()); EXPECT_EQ(result.at("hello").to_string(), "world"); } @@ -40,7 +40,7 @@ TEST(Metapack, write_and_read_json_gzip) { sourcemeta::one::MetapackEncoding::GZIP, {}, std::chrono::milliseconds{10}); - const auto result{sourcemeta::one::metapack_read_json(path)}; + const auto result{sourcemeta::one::metapack_read_json(path).value()}; EXPECT_TRUE(result.is_object()); EXPECT_TRUE(result.at("foo").is_integer()); EXPECT_EQ(result.at("foo").to_integer(), 42); @@ -56,7 +56,7 @@ TEST(Metapack, write_and_read_pretty_json) { sourcemeta::one::MetapackEncoding::GZIP, {}, std::chrono::milliseconds{3}); - const auto result{sourcemeta::one::metapack_read_json(path)}; + const auto result{sourcemeta::one::metapack_read_json(path).value()}; EXPECT_EQ(result.at("key").to_string(), "value"); } @@ -137,7 +137,7 @@ TEST(Metapack, write_and_read_extension) { view.as(extension_start + sizeof(TestExtension)))}; EXPECT_EQ(std::string_view(name_data, read_extension->name_length), "hello"); - const auto result{sourcemeta::one::metapack_read_json(path)}; + const auto result{sourcemeta::one::metapack_read_json(path).value()}; EXPECT_TRUE(result.is_object()); }