// Copyright 2017 The Chromium 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 "components/zucchini/address_translator.h"

#include <algorithm>
#include <string>
#include <utility>

#include "base/format_macros.h"
#include "base/strings/stringprintf.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace zucchini {

namespace {

// Test case structs. The convention of EXPECT() specifies "expectd" value
// before ""actual". However, AddressTranslator interfaces explicitly state "X
// to Y". So it is clearer in test cases to specify "input" before "expect".
struct OffsetToRvaTestCase {
  offset_t input;
  rva_t expect;
};

struct RvaToOffsetTestCase {
  rva_t input;
  offset_t expect;
};

class TestAddressTranslator : public AddressTranslator {
 public:
  using AddressTranslator::AddressTranslator;

  // Initialize() alternative that parses a visual representation of offset and
  // RVA ranges. Illustrative example ("special" means '.' or '!'):
  // "..AAA...|....aaaa" => "..AAA..." for offsets, and "....aaaa" for RVAs:
  // - "..AAA...": First non-period character is at 2, so |offset_begin| = 2.
  // - "..AAA...": There are 3 non-special characters, so |offset_size| = +3.
  // - "....aaaa": First non-period character is at 4, so |rva_begin| = 4.
  // - "....aaaa": There are 4 non-special characters, so |rva_size| = +4.
  // For the special case of length-0 range, '!' can be used. For example,
  // "...!...." specifies |begin| = 3 and |size| = +0.
  AddressTranslator::Status InitializeWithStrings(
      const std::vector<std::string>& specs) {
    std::vector<Unit> units;
    units.reserve(specs.size());
    for (const std::string& s : specs) {
      size_t sep = s.find('|');
      CHECK_NE(sep, std::string::npos);
      std::string s1 = s.substr(0, sep);
      std::string s2 = s.substr(sep + 1);

      auto first_non_blank = [](const std::string& t) {
        auto is_blank = [](char ch) { return ch == '.'; };
        return std::find_if_not(t.begin(), t.end(), is_blank) - t.begin();
      };
      auto count_non_special = [](const std::string& t) {
        auto is_special = [](char ch) { return ch == '.' || ch == '!'; };
        return t.size() - std::count_if(t.begin(), t.end(), is_special);
      };
      units.push_back({static_cast<offset_t>(first_non_blank(s1)),
                       static_cast<offset_t>(count_non_special(s1)),
                       static_cast<rva_t>(first_non_blank(s2)),
                       static_cast<rva_t>(count_non_special(s2))});
    }
    return Initialize(std::move(units));
  }
};

// Simple test: Initialize TestAddressTranslator using |specs|, and match
// |expected| results re. success or failure.
void SimpleTest(const std::vector<std::string>& specs,
                AddressTranslator::Status expected,
                const std::string& case_name) {
  TestAddressTranslator translator;
  auto result = translator.InitializeWithStrings(specs);
  EXPECT_EQ(expected, result) << case_name;
}

// Test AddressTranslator::Initialize's Unit overlap and error checks over
// multiple test cases, each case consists of a fixed unit (specified as
// string), and a variable string taken from an list.
class TwoUnitOverlapTester {
 public:
  struct TestCase {
    std::string unit_str;
    AddressTranslator::Status expected;
  };

  static void RunTest(const std::string& unit_str1,
                      const std::vector<TestCase>& test_cases) {
    for (size_t i = 0; i < test_cases.size(); ++i) {
      const auto& test_case = test_cases[i];
      const std::string& unit_str2 = test_case.unit_str;
      const std::string str =
          base::StringPrintf("Case #%" PRIuS ": %s", i, unit_str2.c_str());
      SimpleTest({unit_str1, unit_str2}, test_case.expected, str);
      // Switch order. Expect same results.
      SimpleTest({unit_str2, unit_str1}, test_case.expected, str);
    }
  }
};

}  // namespace

TEST(AddressTranslatorTest, Empty) {
  using AT = AddressTranslator;
  TestAddressTranslator translator;
  EXPECT_EQ(AT::kSuccess,
            translator.Initialize(std::vector<AddressTranslator::Unit>()));
  offset_t fake_offset_begin = translator.fake_offset_begin();

  // Optimized versions.
  AddressTranslator::OffsetToRvaCache offset_to_rva(translator);
  AddressTranslator::RvaToOffsetCache rva_to_offset(translator);

  EXPECT_EQ(kInvalidRva, translator.OffsetToRva(0U));
  EXPECT_EQ(kInvalidRva, translator.OffsetToRva(100U));
  EXPECT_EQ(kInvalidRva, offset_to_rva.Convert(0U));
  EXPECT_EQ(kInvalidRva, offset_to_rva.Convert(100U));

  EXPECT_EQ(kInvalidOffset, translator.RvaToOffset(0U));
  EXPECT_EQ(kInvalidOffset, translator.RvaToOffset(100U));
  EXPECT_EQ(kInvalidOffset, rva_to_offset.Convert(0U));
  EXPECT_EQ(kInvalidOffset, rva_to_offset.Convert(100U));

  EXPECT_EQ(kInvalidRva, translator.OffsetToRva(fake_offset_begin));
  EXPECT_EQ(kInvalidRva, offset_to_rva.Convert(fake_offset_begin));
}

TEST(AddressTranslatorTest, Single) {
  using AT = AddressTranslator;
  TestAddressTranslator translator;
  // Offsets to RVA: [10, 30) -> [100, 120).
  EXPECT_EQ(AT::kSuccess, translator.Initialize({{10U, +20U, 100U, +20U}}));
  offset_t fake_offset_begin = translator.fake_offset_begin();

  // Optimized versions.
  AddressTranslator::OffsetToRvaCache offset_to_rva(translator);
  AddressTranslator::RvaToOffsetCache rva_to_offset(translator);
  EXPECT_EQ(30U, fake_offset_begin);  // Test implementation detail.

  // Offsets to RVAs.
  OffsetToRvaTestCase test_cases1[] = {
      {0U, kInvalidRva}, {9U, kInvalidRva}, {10U, 100U},
      {20U, 110U},       {29U, 119U},       {30U, kInvalidRva},
  };
  for (auto& test_case : test_cases1) {
    EXPECT_EQ(test_case.expect, translator.OffsetToRva(test_case.input));
    EXPECT_EQ(test_case.expect, offset_to_rva.Convert(test_case.input));
  }

  // RVAs to offsets.
  RvaToOffsetTestCase test_cases2[] = {
      {0U, kInvalidOffset}, {99U, kInvalidOffset}, {100U, 10U},
      {110U, 20U},          {119U, 29U},           {120U, kInvalidOffset},
  };
  for (auto& test_case : test_cases2) {
    EXPECT_EQ(test_case.expect, translator.RvaToOffset(test_case.input));
    EXPECT_EQ(test_case.expect, rva_to_offset.Convert(test_case.input));
  }
}

TEST(AddressTranslatorTest, SingleDanglingRva) {
  using AT = AddressTranslator;
  TestAddressTranslator translator;
  // Offsets to RVA: [10, 30) -> [100, 120 + 7), so has dangling RVAs.
  EXPECT_EQ(AT::kSuccess,
            translator.Initialize({{10U, +20U, 100U, +20U + 7U}}));
  offset_t fake_offset_begin = translator.fake_offset_begin();

  EXPECT_EQ(30U, fake_offset_begin);  // Test implementation detail.

  // Optimized versions.
  AddressTranslator::OffsetToRvaCache offset_to_rva(translator);
  AddressTranslator::RvaToOffsetCache rva_to_offset(translator);

  // Offsets to RVAs.
  OffsetToRvaTestCase test_cases1[] = {
      {0U, kInvalidRva},
      {9U, kInvalidRva},
      {10U, 100U},
      {20U, 110U},
      {29U, 119U},
      {30U, kInvalidRva},
      // Fake offsets to dangling RVAs.
      {fake_offset_begin + 100U, kInvalidRva},
      {fake_offset_begin + 119U, kInvalidRva},
      {fake_offset_begin + 120U, 120U},
      {fake_offset_begin + 126U, 126U},
      {fake_offset_begin + 127U, kInvalidRva},
  };
  for (auto& test_case : test_cases1) {
    EXPECT_EQ(test_case.expect, translator.OffsetToRva(test_case.input));
    EXPECT_EQ(test_case.expect, offset_to_rva.Convert(test_case.input));
  }

  // RVAs to offsets.
  RvaToOffsetTestCase test_cases2[] = {
      {0U, kInvalidOffset},
      {99U, kInvalidOffset},
      {100U, 10U},
      {110U, 20U},
      {119U, 29U},
      // Dangling RVAs to fake offsets.
      {120U, fake_offset_begin + 120U},
      {126U, fake_offset_begin + 126U},
      {127U, kInvalidOffset},
  };
  for (auto& test_case : test_cases2) {
    EXPECT_EQ(test_case.expect, translator.RvaToOffset(test_case.input));
    EXPECT_EQ(test_case.expect, rva_to_offset.Convert(test_case.input));
  }
}

TEST(AddressTranslatorTest, BasicUsage) {
  using AT = AddressTranslator;
  TestAddressTranslator translator;
  // Offsets covered: [10, 30), [40, 70), [70, 110).
  // Map to RVAs: [200, 220 + 5), [300, 330), [100, 140), so has dangling RVAs.
  auto result = translator.Initialize({
      {10U, +20U, 200U, +20U + 5U},  // Has dangling RVAs.
      {40U, +30U, 300U, +20U},       // Extra offset truncated and ignored.
      {50U, +20U, 310U, +20U},       // Overlap with previous: Merged.
      {70U, +40U, 100U, +20U},  // Tangent with previous but inconsistent; extra
                                // offset truncated and ignored.
      {90U, +20U, 120U, +20U},  // Tangent with previous and consistent: Merged.
  });
  EXPECT_EQ(AT::kSuccess, result);
  offset_t fake_offset_begin = translator.fake_offset_begin();
  EXPECT_EQ(110U, fake_offset_begin);  // Test implementation detail.

  // Optimized versions.
  AddressTranslator::OffsetToRvaCache offset_to_rva(translator);
  AddressTranslator::RvaToOffsetCache rva_to_offset(translator);

  // Offsets to RVAs.
  OffsetToRvaTestCase test_cases1[] = {
      {0U, kInvalidRva},
      {9U, kInvalidRva},
      {10U, 200U},
      {20U, 210U},
      {29U, 219U},
      {30U, kInvalidRva},
      {39U, kInvalidRva},
      {40U, 300U},
      {55U, 315U},
      {69U, 329U},
      {70U, 100U},
      {90U, 120U},
      {109U, 139U},
      {110U, kInvalidRva},
      // Fake offsets to dangling RVAs.
      {fake_offset_begin + 220U, 220U},
      {fake_offset_begin + 224U, 224U},
      {fake_offset_begin + 225U, kInvalidRva},
  };
  for (auto& test_case : test_cases1) {
    EXPECT_EQ(test_case.expect, translator.OffsetToRva(test_case.input));
    EXPECT_EQ(test_case.expect, offset_to_rva.Convert(test_case.input));
  }

  // RVAs to offsets.
  RvaToOffsetTestCase test_cases2[] = {
      {0U, kInvalidOffset},
      {99U, kInvalidOffset},
      {100U, 70U},
      {120U, 90U},
      {139U, 109U},
      {140U, kInvalidOffset},
      {199U, kInvalidOffset},
      {200U, 10U},
      {210U, 20U},
      {219U, 29U},
      {225U, kInvalidOffset},
      {299U, kInvalidOffset},
      {300U, 40U},
      {315U, 55U},
      {329U, 69U},
      {330U, kInvalidOffset},
      // Dangling RVAs to fake offsets.
      {220U, fake_offset_begin + 220U},
      {224U, fake_offset_begin + 224U},
      {225U, kInvalidOffset},
  };
  for (auto& test_case : test_cases2) {
    EXPECT_EQ(test_case.expect, translator.RvaToOffset(test_case.input));
    EXPECT_EQ(test_case.expect, rva_to_offset.Convert(test_case.input));
  }
}

TEST(AddressTranslatorTest, Overflow) {
  using AT = AddressTranslator;
  // Test assumes that offset_t and rva_t to be 32-bit.
  static_assert(sizeof(offset_t) == 4 && sizeof(rva_t) == 4,
                "Needs to update test.");
  {
    AddressTranslator translator1;
    EXPECT_EQ(AT::kErrorOverflow,
              translator1.Initialize({{0, +0xC0000000U, 0, +0xC0000000U}}));
  }
  {
    AddressTranslator translator2;
    EXPECT_EQ(AT::kErrorOverflow,
              translator2.Initialize({{0, +0, 0, +0xC0000000U}}));
  }
  {
    // Units are okay, owing to but limitations of the heuristic to convert
    // dangling RVA to fake offset, AddressTranslator::Initialize() fails.
    AddressTranslator translator3;
    EXPECT_EQ(AT::kErrorFakeOffsetBeginTooLarge,
              translator3.Initialize(
                  {{32, +0, 32, +0x50000000U}, {0x50000000U, +16, 0, +16}}));
  }
}

// Sanity test for TestAddressTranslator::InitializeWithStrings();
TEST(AddressTranslatorTest, AddUnitAsString) {
  using AT = AddressTranslator;
  {
    TestAddressTranslator translator1;
    EXPECT_EQ(AT::kSuccess, translator1.InitializeWithStrings({"..A..|.aaa."}));
    AddressTranslator::Unit unit1 = translator1.units_sorted_by_offset()[0];
    EXPECT_EQ(2U, unit1.offset_begin);
    EXPECT_EQ(+1U, unit1.offset_size);
    EXPECT_EQ(1U, unit1.rva_begin);
    EXPECT_EQ(+3U, unit1.rva_size);
  }
  {
    TestAddressTranslator translator2;
    EXPECT_EQ(AT::kSuccess,
              translator2.InitializeWithStrings({".....!...|.bbbbbb..."}));
    AddressTranslator::Unit unit2 = translator2.units_sorted_by_offset()[0];
    EXPECT_EQ(5U, unit2.offset_begin);
    EXPECT_EQ(+0U, unit2.offset_size);
    EXPECT_EQ(1U, unit2.rva_begin);
    EXPECT_EQ(+6U, unit2.rva_size);
  }
}

// AddressTranslator::Initialize() lists Unit merging examples in comments. The
// format is different from that used by InitializeWithStrings(), but adapting
// them is easy, so we may as well do so.
TEST(AddressTranslatorTest, OverlapFromComment) {
  using AT = AddressTranslator;
  constexpr auto OK = AT::kSuccess;
  struct {
    const char* rva_str;  // RVA comes first in this case.
    const char* offset_str;
    AT::Status expected;
  } test_cases[] = {
      {"..ssssffff..", "..SSSSFFFF..", OK},
      {"..ssssffff..", "..SSSS..FFFF..", OK},
      {"..ssssffff..", "..FFFF..SSSS..", OK},
      {"..ssssffff..", "..SSOOFF..", AT::kErrorBadOverlap},
      {"..sssooofff..", "..SSSOOOFFF..", OK},
      {"..sssooofff..", "..SSSSSOFFFFF..", AT::kErrorBadOverlap},
      {"..sssooofff..", "..FFOOOOSS..", AT::kErrorBadOverlap},
      {"..sssooofff..", "..SSSOOOF..", OK},
      {"..sssooofff..", "..SSSOOOF..", OK},
      {"..sssooosss..", "..SSSOOOS..", OK},
      {"..sssooofff..", "..SSSOO..", OK},
      {"..sssooofff..", "..SSSOFFF..", AT::kErrorBadOverlapDanglingRva},
      {"..sssooosss..", "..SSSOOSSSS..", AT::kErrorBadOverlapDanglingRva},
      {"..oooooo..", "..OOO..", OK},
  };

  auto to_period = [](std::string s, char ch) {  // |s| passed by value.
    std::replace(s.begin(), s.end(), ch, '.');
    return s;
  };

  size_t idx = 0;
  for (const auto& test_case : test_cases) {
    std::string base_str =
        std::string(test_case.offset_str) + "|" + test_case.rva_str;
    std::string unit_str1 = to_period(to_period(base_str, 'S'), 's');
    std::string unit_str2 = to_period(to_period(base_str, 'F'), 'f');
    SimpleTest({unit_str1, unit_str2}, test_case.expected,
               base::StringPrintf("Case #%" PRIuS, idx));
    ++idx;
  }
}

TEST(AddressTranslatorTest, Overlap) {
  using AT = AddressTranslator;
  constexpr auto OK = AT::kSuccess;
  constexpr const char* unit_str1 = "....AAA.......|.....aaa......";

  std::vector<TwoUnitOverlapTester::TestCase> test_cases = {
      //....AAA.......|.....aaa......   The first Unit. NOLINT
      {"....BBB.......|.....bbb......", OK},
      {"..BBB.........|...bbb........", OK},
      {"......BBB.....|.......bbb....", OK},
      {"..BBBBBBBBB...|...bbb........", OK},  // Extra offset get truncated.
      {"......BBBBBBBB|.......bbb....", OK},
      {"....BBB.......|.......bbb....", AT::kErrorBadOverlap},
      {"..BBB.........|.......bbb....", AT::kErrorBadOverlap},
      {".......BBB....|.......bbb....", AT::kErrorBadOverlap},
      //....AAA.......|.....aaa......   The first Unit. NOLINT
      {"....BBB.......|..........bbb.", AT::kErrorBadOverlap},
      {"..........BBB.|.......bbb....", AT::kErrorBadOverlap},
      {"......BBB.....|.....bbb......", AT::kErrorBadOverlap},
      {"......BBB.....|..bbb.........", AT::kErrorBadOverlap},
      {"......BBB.....|bbb...........", AT::kErrorBadOverlap},
      {"BBB...........|bbb...........", OK},  // Disjoint.
      {"........BBB...|.........bbb..", OK},  // Disjoint.
      {"BBB...........|..........bbb.", OK},  // Disjoint, offset elsewhere.
      //....AAA.......|.....aaa......   The first Unit. NOLINT
      {".BBB..........|..bbb.........", OK},  // Tangent.
      {".......BBB....|........bbb...", OK},  // Tangent.
      {".BBB..........|........bbb...", OK},  // Tangent, offset elsewhere.
      {"BBBBBB........|bbb...........", OK},  // Repeat, with extra offsets.
      {"........BBBB..|.........bbb..", OK},
      {"BBBBBB........|..........bbb.", OK},
      {".BBBBBB.......|..bbb.........", OK},
      {".......BBBBB..|........bbb...", OK},
      //....AAA.......|.....aaa......   The first Unit. NOLINT
      {".BBB..........|........bbb...", OK},  // Tangent, offset elsewhere.
      {"..BBB.........|........bbb...", AT::kErrorBadOverlap},
      {"...BB.........|....bb........", OK},
      {"....BB........|.....bb.......", OK},
      {".......BB.....|........bb....", OK},
      {"...BBBBBB.....|....bbbbbb....", OK},
      {"..BBBBBB......|...bbbbbb.....", OK},
      {"......BBBBBB..|.......bbbbbb.", OK},
      //....AAA.......|.....aaa......   The first Unit. NOLINT
      {"BBBBBBBBBBBBBB|bbbbbbbbbbbbbb", AT::kErrorBadOverlap},
      {"B.............|b.............", OK},
      {"B.............|.............b", OK},
      {"....B.........|.....b........", OK},
      {"....B.........|......b.......", AT::kErrorBadOverlap},
      {"....B.........|......b.......", AT::kErrorBadOverlap},
      {"....BBB.......|.....bb.......", OK},
      {"....BBBB......|.....bbb......", OK},
      //....AAA.......|.....aaa......   The first Unit. NOLINT
      {".........BBBBB|.b............", OK},
      {"....AAA.......|.....!........", OK},
      {"....!.........|.....!........", OK},  // Empty units gets deleted early.
      {"....!.........|..........!...", OK},  // Forgiving!
  };

  TwoUnitOverlapTester::RunTest(unit_str1, test_cases);
}

TEST(AddressTranslatorTest, OverlapOffsetMultiple) {
  using AT = AddressTranslator;
  // Simple case. Note that RVA ranges don't get merged.
  SimpleTest({"A..|a....",  //
              ".A.|..a..",  //
              "..A|....a"},
             AT::kSuccess, "Case #0");

  // Offset range 1 overlaps 2 and 3, but truncation takes place to trim down
  // offset ranges, so still successful.
  SimpleTest({"..A|a....",  //
              ".AA|..a..",  //
              "AAA|....a"},
             AT::kSuccess, "Case #1");

  // Offset range 2 and 3 overlap, so fail.
  SimpleTest({"A..|a....",  //
              ".A.|..a..",  //
              ".A.|....a"},
             AT::kErrorBadOverlap, "Case #2");
}

TEST(AddressTranslatorTest, OverlapDangling) {
  using AT = AddressTranslator;
  constexpr auto OK = AT::kSuccess;
  // First Unit has dangling offsets at
  constexpr const char* unit_str1 = "....AAA.......|.....aaaaaa...";

  std::vector<TwoUnitOverlapTester::TestCase> test_cases = {
      //....AAA.......|.....aaaaaa...   The first Unit. NOLINT
      {"....BBB.......|.....bbbbbb...", OK},
      {"....BBB.......|.....bbbbb....", OK},
      {"....BBB.......|.....bbbb.....", OK},
      {"....BBB.......|.....bbb......", OK},
      {".....BBB......|......bbb.....", AT::kErrorBadOverlapDanglingRva},
      {".....BB.......|......bbb.....", OK},
      {"....BBB.......|.....bbbbbbbb.", OK},
      {"..BBBBB.......|...bbbbbbbb...", OK},
      //....AAA.......|.....aaaaaa...   The first Unit. NOLINT
      {"......!.......|.bbb..........", AT::kErrorBadOverlap},
      {"..BBBBB.......|...bbbbb......", OK},
      {".......BBB....|.bbb..........", OK},  // Just tangent: Can go elsewhere.
      {".......BBB....|.bbbb.........", OK},  // Can be another dangling RVA.
      {".......!......|.bbbb.........", OK},  // Same with empty.
      {"......!.......|.......!......", OK},  // Okay, but gets deleted.
      {"......!.......|.......b......", AT::kErrorBadOverlapDanglingRva},
      {"......B.......|.......b......", OK},
      //....AAA.......|.....aaaaaa...   The first Unit. NOLINT
      {"......BBBB....|.......bbbb...", AT::kErrorBadOverlapDanglingRva},
      {"......BB......|.......bb.....", AT::kErrorBadOverlapDanglingRva},
      {"......BB......|bb............", AT::kErrorBadOverlap},
  };

  TwoUnitOverlapTester::RunTest(unit_str1, test_cases);
}

// Tests implementation since algorithm is tricky.
TEST(AddressTranslatorTest, Merge) {
  using AT = AddressTranslator;
  // Merge a bunch of overlapping Units into one big Unit.
  std::vector<std::string> test_case1 = {
      "AAA.......|.aaa......",  // Comment to prevent wrap by formatter.
      "AA........|.aa.......",  //
      "..AAA.....|...aaa....",  //
      "....A.....|.....a....",  //
      ".....AAA..|......aaa.",  //
      "........A.|.........a",  //
  };
  // Try all 6! permutations.
  std::sort(test_case1.begin(), test_case1.end());
  do {
    TestAddressTranslator translator1;
    EXPECT_EQ(AT::kSuccess, translator1.InitializeWithStrings(test_case1));
    EXPECT_EQ(9U, translator1.fake_offset_begin());

    AT::Unit expected{0U, +9U, 1U, +9U};
    EXPECT_EQ(1U, translator1.units_sorted_by_offset().size());
    EXPECT_EQ(expected, translator1.units_sorted_by_offset()[0]);
    EXPECT_EQ(1U, translator1.units_sorted_by_rva().size());
    EXPECT_EQ(expected, translator1.units_sorted_by_rva()[0]);
  } while (std::next_permutation(test_case1.begin(), test_case1.end()));

  // Merge RVA-adjacent Units into two Units.
  std::vector<std::string> test_case2 = {
      ".....A..|.a......",  // First Unit.
      "......A.|..a.....",  //
      "A.......|...a....",  // Second Unit: RVA-adjacent to first Unit, but
      ".A......|....a...",  // offset would become inconsistent, so a new
      "..A.....|.....a..",  // Unit gets created.
  };
  // Try all 5! permutations.
  std::sort(test_case2.begin(), test_case2.end());
  do {
    TestAddressTranslator translator2;
    EXPECT_EQ(AT::kSuccess, translator2.InitializeWithStrings(test_case2));
    EXPECT_EQ(7U, translator2.fake_offset_begin());

    AT::Unit expected1{0U, +3U, 3U, +3U};
    AT::Unit expected2{5U, +2U, 1U, +2U};
    EXPECT_EQ(2U, translator2.units_sorted_by_offset().size());
    EXPECT_EQ(expected1, translator2.units_sorted_by_offset()[0]);
    EXPECT_EQ(expected2, translator2.units_sorted_by_offset()[1]);
    EXPECT_EQ(2U, translator2.units_sorted_by_rva().size());
    EXPECT_EQ(expected2, translator2.units_sorted_by_rva()[0]);
    EXPECT_EQ(expected1, translator2.units_sorted_by_rva()[1]);
  } while (std::next_permutation(test_case2.begin(), test_case2.end()));
}

TEST(AddressTranslatorTest, RvaToOffsetCache_IsValid) {
  AddressTranslator translator;
  // Notice that the second section has dangling RVA.
  ASSERT_EQ(AddressTranslator::kSuccess,
            translator.Initialize(
                {{0x04, +0x28, 0x1A00, +0x28}, {0x30, +0x10, 0x3A00, +0x30}}));
  AddressTranslator::RvaToOffsetCache rva_checker(translator);

  EXPECT_FALSE(rva_checker.IsValid(kInvalidRva));

  for (int i = 0; i < 0x28; ++i)
    EXPECT_TRUE(rva_checker.IsValid(0x1A00 + i));
  EXPECT_FALSE(rva_checker.IsValid(0x1A00 + 0x28));
  EXPECT_FALSE(rva_checker.IsValid(0x1A00 + 0x29));
  EXPECT_FALSE(rva_checker.IsValid(0x1A00 - 1));
  EXPECT_FALSE(rva_checker.IsValid(0x1A00 - 2));

  for (int i = 0; i < 0x30; ++i)
    EXPECT_TRUE(rva_checker.IsValid(0x3A00 + i));
  EXPECT_FALSE(rva_checker.IsValid(0x3A00 + 0x30));
  EXPECT_FALSE(rva_checker.IsValid(0x3A00 + 0x31));
  EXPECT_FALSE(rva_checker.IsValid(0x3A00 - 1));
  EXPECT_FALSE(rva_checker.IsValid(0x3A00 - 2));

  EXPECT_FALSE(rva_checker.IsValid(0));
  EXPECT_FALSE(rva_checker.IsValid(0x10));
  EXPECT_FALSE(rva_checker.IsValid(0x7FFFFFFFU));
  EXPECT_FALSE(rva_checker.IsValid(0xFFFFFFFFU));
}

}  // namespace zucchini
