blob: f77a36811849fd14362d95202ea46420178b8b01 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/lib/cmx/cmx.h"
#include <fcntl.h>
#include <string>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "rapidjson/document.h"
#include "src/lib/files/path.h"
#include "src/lib/files/scoped_temp_dir.h"
#include "src/lib/json_parser/json_parser.h"
#include "src/lib/pkg_url/fuchsia_pkg_url.h"
namespace component {
namespace {
class CmxMetadataTest : public ::testing::Test {
protected:
void ExpectFailedParse(const std::string& json, std::string expected_error) {
bool create_tmp_file[] = {true, false};
for (bool create_file : create_tmp_file) {
SCOPED_TRACE("create file: " + std::to_string(create_file));
std::string error;
CmxMetadata cmx;
json::JSONParser json_parser;
std::string json_basename;
EXPECT_FALSE(ParseFrom(&cmx, &json_parser, json, &json_basename, create_file));
EXPECT_TRUE(json_parser.HasError());
EXPECT_THAT(json_parser.error_str(), ::testing::HasSubstr(expected_error));
}
}
bool ParseFrom(CmxMetadata* cmx, json::JSONParser* json_parser, const std::string& json,
std::string* json_basename, bool create_tmp_file) {
if (create_tmp_file) {
std::string json_path;
if (!tmp_dir_.NewTempFileWithData(json, &json_path)) {
return false;
}
*json_basename = files::GetBaseName(json_path);
const int dirfd = open(tmp_dir_.path().c_str(), O_RDONLY);
return cmx->ParseFromFileAt(dirfd, *json_basename, json_parser);
} else {
*json_basename = "file_name";
return cmx->ParseFromString(json, *json_basename, json_parser);
}
}
private:
files::ScopedTempDir tmp_dir_;
};
TEST_F(CmxMetadataTest, ParseMetadata) {
const std::string json = R"JSON({
"sandbox": {
"dev": [ "class/input" ],
"features": [ "feature_a" ],
"services": [ "fuchsia.MyService" ]
},
"runner": "dart_runner",
"facets": {
"some_key": "some_value"
},
"other": "stuff"
})JSON";
bool create_tmp_file[] = {true, false};
for (bool create_file : create_tmp_file) {
CmxMetadata cmx;
json::JSONParser json_parser;
SCOPED_TRACE("create file: " + std::to_string(create_file));
std::string file_unused;
EXPECT_TRUE(ParseFrom(&cmx, &json_parser, json, &file_unused, create_file))
<< json_parser.error_str();
EXPECT_FALSE(json_parser.HasError());
const auto& sandbox = cmx.sandbox_meta();
EXPECT_FALSE(sandbox.IsNull());
EXPECT_THAT(sandbox.dev(), ::testing::ElementsAre("class/input"));
EXPECT_TRUE(sandbox.HasFeature("feature_a"));
EXPECT_FALSE(sandbox.HasFeature("feature_b"));
EXPECT_THAT(sandbox.services(), ::testing::ElementsAre("fuchsia.MyService"));
EXPECT_FALSE(cmx.runtime_meta().IsNull());
EXPECT_EQ(cmx.runtime_meta().runner(), "dart_runner");
const auto& some_value = cmx.GetFacet("some_key");
ASSERT_TRUE(some_value.IsString());
EXPECT_EQ("some_value", std::string(some_value.GetString()));
const auto& null_value = cmx.GetFacet("invalid");
EXPECT_TRUE(null_value.IsNull());
}
}
TEST_F(CmxMetadataTest, ParseEmpty) {
// No 'program' or 'runner'. Valid syntax, but empty.
rapidjson::Value sandbox;
std::string error;
const std::string json = R"JSON(
{
"sandwich": { "ingredients": [ "bacon", "lettuce", "tomato" ] }
}
)JSON";
bool create_tmp_file[] = {true, false};
for (bool create_file : create_tmp_file) {
SCOPED_TRACE("create file: " + std::to_string(create_file));
CmxMetadata cmx;
json::JSONParser json_parser;
std::string file_unused;
EXPECT_TRUE(ParseFrom(&cmx, &json_parser, json, &file_unused, create_file))
<< json_parser.error_str();
// Missing "sandbox" defaults to empty.
EXPECT_FALSE(cmx.sandbox_meta().IsNull());
EXPECT_TRUE(cmx.runtime_meta().IsNull());
EXPECT_TRUE(cmx.program_meta().IsBinaryNull());
EXPECT_TRUE(cmx.program_meta().IsDataNull());
}
}
TEST_F(CmxMetadataTest, ParseWithErrors) {
rapidjson::Value sandbox;
std::string error;
ExpectFailedParse(R"JSON({ ,,, })JSON", "Missing a name for object member.");
ExpectFailedParse(R"JSON(3)JSON", "File is not a JSON object.");
ExpectFailedParse(R"JSON({ "sandbox" : 3})JSON", "'sandbox' is not an object.");
ExpectFailedParse(R"JSON({ "sandbox" : {"dev": "notarray"} })JSON", "'dev' is not an array.");
ExpectFailedParse(R"JSON({ "runner" : 3 })JSON", "'runner' is not a string.");
ExpectFailedParse(R"JSON({ "program" : { "binary": 3 } })JSON",
"'binary' in program is not a string.");
}
} // namespace
} // namespace component