text: // Copyright 2020 The Fuchsia Authors
  //
  // Use of this source code is governed by a MIT-style
  // license that can be found in the LICENSE file or at
  // https://opensource.org/licenses/MIT
  
  #include <lib/acpi_lite.h>
  #include <lib/acpi_lite/apic.h>
  #include <lib/acpi_lite/testing/test_data.h>
  #include <lib/acpi_lite/testing/test_util.h>
  #include <lib/zx/status.h>
  
  #include <memory>
  
  #include <gtest/gtest.h>
  
  namespace acpi_lite::testing {
  namespace {
  
  // EXPECT_EQ with support for packed fields.
  //
  // The EXPECT_EQ implementation takes a reference to its arguments, which can
  // trigger undefined behaviour for packed fields that are not at the correct
  // alignment for their type.
  //
  // This macro unpacks its arguments first, ensuring that arguments to
  // EXPECT_EQ are correctly aligned.
  #define EXPECT_EQ_PACKED(a, b) \
    do {                         \
      decltype(a) _a = a;        \
      decltype(b) _b = b;        \
      EXPECT_EQ(_a, _b);         \
    } while (false)
  
  // Collect all items presented in the given callback.
  template <typename T>
  struct Collector {
   public:
    // Return a callback that, when called, collects the given item into |items|.
    fit::inline_function<zx_status_t(const T&)> callback() {
      return [this](const T& item) {
        fbl::AllocChecker ac;
        items.push_back(item, &ac);
        ZX_ASSERT(ac.check());
        return ZX_OK;
      };
    }
  
    fbl::Vector<T> items;
  };
  
  TEST(Apic, EnumerateEveCpus) {
    Collector<acpi_lite::AcpiMadtLocalApicEntry> collector;
    EXPECT_EQ(ZX_OK, acpi_lite::EnumerateProcessorLocalApics(PixelbookEveAcpiParser(),
                                                             collector.callback()));
  
    // Expect 4 CPUs.
    ASSERT_EQ(collector.items.size(), 4u);
    EXPECT_EQ_PACKED(collector.items[0].apic_id, 0u);
    EXPECT_EQ_PACKED(collector.items[1].apic_id, 1u);
    EXPECT_EQ_PACKED(collector.items[2].apic_id, 2u);
    EXPECT_EQ_PACKED(collector.items[3].apic_id, 3u);
  }
  
  TEST(Apic, EnumerateZ840Cpus) {
    Collector<acpi_lite::AcpiMadtLocalApicEntry> collector;
    EXPECT_EQ(ZX_OK, acpi_lite::EnumerateProcessorLocalApics(Z840AcpiParser(), collector.callback()));
  
    // We check the numcpus to ensure basic parsing is working.
    EXPECT_EQ(56u, collector.items.size());
  }
  
  TEST(Apic, EnumerateEveIO) {
    Collector<acpi_lite::AcpiMadtIoApicEntry> collector;
    EXPECT_EQ(ZX_OK, acpi_lite::EnumerateIoApics(PixelbookEveAcpiParser(), collector.callback()));
  
    ASSERT_EQ(1u, collector.items.size());
    EXPECT_EQ_PACKED(2u, collector.items[0].io_apic_id);
    EXPECT_EQ_PACKED(0u, collector.items[0].global_system_interrupt_base);
    EXPECT_EQ_PACKED(0xFEC00000u, collector.items[0].io_apic_address);
  }
  
  TEST(Apic, EnumerateInterruptOverrides) {
    Collector<acpi_lite::AcpiMadtIntSourceOverrideEntry> collector;
    EXPECT_EQ(ZX_OK,
              acpi_lite::EnumerateIoApicIsaOverrides(PixelbookEveAcpiParser(), collector.callback()));
  
    ASSERT_EQ(2u, collector.items.size());
  
    EXPECT_EQ_PACKED(0u, collector.items[0].source);
    EXPECT_EQ_PACKED(0u, collector.items[0].flags);
    EXPECT_EQ_PACKED(2u, collector.items[0].global_sys_interrupt);
  
    EXPECT_EQ_PACKED(9u, collector.items[1].source);
    EXPECT_EQ_PACKED(ACPI_MADT_FLAG_TRIGGER_MASK | ACPI_MADT_FLAG_POLARITY_HIGH,
                     collector.items[1].flags);
    EXPECT_EQ_PACKED(9u, collector.items[1].global_sys_interrupt);
  }
  
  }  // namespace
  }  // namespace acpi_lite::testing
  