text: // Copyright 2021 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/devices/lib/acpi/client.h"
  
  #include <fidl/fuchsia.hardware.acpi/cpp/wire.h>
  #include <lib/async-loop/cpp/loop.h>
  #include <lib/fidl/llcpp/arena.h>
  
  #include <zxtest/zxtest.h>
  
  #include "src/devices/lib/acpi/mock/mock-acpi.h"
  
  using MockAcpiDevice = acpi::mock::Device;
  namespace facpi = fuchsia_hardware_acpi::wire;
  
  // Intel NHLT DSM UUID: a69f886e-6ceb-4594-a41f-7b5dce24c553
  static constexpr auto kNhltUuid =
      acpi::Uuid::Create(0xa69f886e, 0x6ceb, 0x4594, 0xa41f, 0x7b5dce24c553);
  static constexpr uint8_t kNhltUuidRaw[] = {
      /* 0000 */ 0x6e, 0x88, 0x9f, 0xa6, 0xeb, 0x6c, 0x94, 0x45,
      /* 0008 */ 0xa4, 0x1f, 0x7b, 0x5d, 0xce, 0x24, 0xc5, 0x53};
  
  class AcpiClientTest : public zxtest::Test {
   public:
    AcpiClientTest() : loop_(&kAsyncLoopConfigNeverAttachToThread) {}
  
    void SetUp() override {
      ASSERT_OK(loop_.StartThread("acpi-client-test-thread"));
      ASSERT_BYTES_EQ(kNhltUuid.bytes, kNhltUuidRaw, std::size(kNhltUuidRaw));
  
      server_.SetEvaluateObject([this](MockAcpiDevice::EvaluateObjectRequestView request,
                                       MockAcpiDevice::EvaluateObjectCompleter::Sync &sync) {
        ASSERT_BYTES_EQ(request->path.data(), "_DSM", request->path.size());
        ASSERT_EQ(request->mode, facpi::EvaluateObjectMode::kPlainObject);
        ASSERT_EQ(request->parameters.count(), 3);
        auto &params = request->parameters;
  
        ASSERT_TRUE(params[0].is_buffer_val());
        ASSERT_BYTES_EQ(params[0].buffer_val().data(), kNhltUuidRaw, std::size(kNhltUuidRaw));
  
        ASSERT_TRUE(params[1].is_integer_val());
        ASSERT_EQ(params[1].integer_val(), 1);
        ASSERT_TRUE(params[2].is_integer_val());
        ASSERT_EQ(params[2].integer_val(), 3);
  
        if (response_ == std::nullopt) {
          sync.ReplyError(facpi::Status::kError);
        } else {
          auto object = fidl::ObjectView<facpi::Object>::FromExternal(&response_.value());
          sync.ReplySuccess(facpi::EncodedObject::WithObject(object));
        }
      });
    }
  
   protected:
    async::Loop loop_;
    MockAcpiDevice server_;
    std::optional<facpi::Object> response_;
  };
  
  TEST_F(AcpiClientTest, TestCallDsmFails) {
    auto client = server_.CreateClient(loop_.dispatcher());
    ASSERT_OK(client.status_value());
  
    auto helper = std::move(client.value());
    auto result = helper.CallDsm(kNhltUuid, 1, 3, std::nullopt);
    ASSERT_OK(result.status_value());
    ASSERT_EQ(result->status_val(), facpi::Status::kError);
  }
  
  TEST_F(AcpiClientTest, TestCallDsmSucceeds) {
    fidl::Arena<> alloc;
    facpi::Object obj = facpi::Object::WithIntegerVal(alloc, 320);
    response_.emplace(obj);
    auto client = server_.CreateClient(loop_.dispatcher());
    ASSERT_OK(client.status_value());
  
    auto helper = std::move(client.value());
    auto result = helper.CallDsm(kNhltUuid, 1, 3, std::nullopt);
    ASSERT_OK(result.status_value());
    ASSERT_EQ(result->integer_val(), 320);
  }
  