// 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
