Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (c) 2016, Google Inc.
      3  * All rights reserved.
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #ifndef PERFTOOLS_INTERVALMAP_TEST_H_
      9 #define PERFTOOLS_INTERVALMAP_TEST_H_
     10 
     11 #include <utility>
     12 #include <vector>
     13 
     14 #include "int_compat.h"
     15 #include "intervalmap.h"
     16 #include "string_compat.h"
     17 #include "test_compat.h"
     18 
     19 namespace perftools {
     20 namespace {
     21 
     22 class Command {
     23  public:
     24   virtual ~Command() {}
     25   virtual void ExecuteOn(IntervalMap<string>* map) const = 0;
     26 };
     27 
     28 class SetCommand : public Command {
     29  public:
     30   SetCommand(uint64 start, uint64 limit, const char* value)
     31       : start_(start), limit_(limit), value_(value) {}
     32 
     33   void ExecuteOn(IntervalMap<string>* map) const override {
     34     map->Set(start_, limit_, value_);
     35   }
     36 
     37  private:
     38   const uint64 start_;
     39   const uint64 limit_;
     40   const char* value_;
     41 };
     42 
     43 class NumIntervalsCommand : public Command {
     44  public:
     45   explicit NumIntervalsCommand(uint64 expected) : expected_(expected) {}
     46 
     47   void ExecuteOn(IntervalMap<string>* map) const override {
     48     ASSERT_EQ(expected_, map->Size());
     49   }
     50 
     51  private:
     52   const uint64 expected_;
     53 };
     54 
     55 class LookupCommand : public Command {
     56  public:
     57   LookupCommand(uint64 from, uint64 to, const char* expected)
     58       : from_(from), to_(to), expected_(expected) {}
     59 
     60   void ExecuteOn(IntervalMap<string>* map) const override {
     61     for (uint64 key = from_; key <= to_; ++key) {
     62       string result;
     63       ASSERT_TRUE(map->Lookup(key, &result)) << "Did not find value for key: "
     64                                              << key;
     65       ASSERT_EQ(expected_, result) << "For key: " << key
     66                                    << " Found value: " << result
     67                                    << ". Expected: " << expected_;
     68     }
     69   }
     70 
     71  private:
     72   const uint64 from_;
     73   const uint64 to_;
     74   const char* expected_;
     75 };
     76 
     77 class FailLookupCommand : public Command {
     78  public:
     79   explicit FailLookupCommand(std::vector<uint64> keys)
     80       : keys_(std::move(keys)) {}
     81 
     82   void ExecuteOn(IntervalMap<string>* map) const override {
     83     string result;
     84     for (auto key : keys_) {
     85       ASSERT_FALSE(map->Lookup(key, &result)) << "Found value for key: " << key;
     86     }
     87   }
     88 
     89  private:
     90   std::vector<uint64> keys_;
     91 };
     92 
     93 class FindNextCommand : public Command {
     94  public:
     95   FindNextCommand(uint64 key, uint64 expected_start, uint64 expected_limit,
     96                   const char* expected_value)
     97       : key_(key),
     98         expected_start_(expected_start),
     99         expected_limit_(expected_limit),
    100         expected_value_(expected_value) {}
    101 
    102   void ExecuteOn(IntervalMap<string>* map) const override {
    103     uint64 start;
    104     uint64 limit;
    105     string value;
    106     ASSERT_TRUE(map->FindNext(key_, &start, &limit, &value))
    107         << "Did not find a next interval for key: " << key_;
    108     bool matches_expected = expected_start_ == start &&
    109                             expected_limit_ == limit &&
    110                             expected_value_ == value;
    111     ASSERT_TRUE(matches_expected)
    112         << "Found incorrect interval for key: " << key_ << ". "
    113         << "Expected start: " << expected_start_ << ". "
    114         << "Expected limit: " << expected_start_ << ". "
    115         << "Expected value: " << expected_value_ << ". "
    116         << "Found start: " << start << ". "
    117         << "Found limit: " << limit << ". "
    118         << "Found value: " << value << ". ";
    119   }
    120 
    121  private:
    122   uint64 key_;
    123   uint64 expected_start_;
    124   uint64 expected_limit_;
    125   const char* expected_value_;
    126 };
    127 
    128 class FailFindNextCommand : public Command {
    129  public:
    130   explicit FailFindNextCommand(uint64 key) : key_(key) {}
    131 
    132   void ExecuteOn(IntervalMap<string>* map) const override {
    133     uint64 start;
    134     uint64 limit;
    135     string value;
    136     ASSERT_FALSE(map->FindNext(key_, &start, &limit, &value))
    137         << "Found interval for: " << key_ << ". "
    138         << "start: " << start << ". "
    139         << "limit: " << limit << ". "
    140         << "value: " << value << ". "
    141         << "Did not find a next interval for key: " << key_;
    142   }
    143 
    144  private:
    145   uint64 key_;
    146 };
    147 
    148 std::shared_ptr<Command> Set(uint64 start, uint64 limit, const char* value) {
    149   return std::make_shared<SetCommand>(start, limit, value);
    150 }
    151 
    152 std::shared_ptr<Command> NumIntervals(uint64 size) {
    153   return std::make_shared<NumIntervalsCommand>(size);
    154 }
    155 
    156 // Looks up every key in the interval [from, to] and expects them all to be
    157 // equal to expected.
    158 std::shared_ptr<Command> Lookup(uint64 from, uint64 to, const char* expected) {
    159   return std::make_shared<LookupCommand>(from, to, expected);
    160 }
    161 
    162 std::shared_ptr<Command> FailLookup(std::vector<uint64> keys) {
    163   return std::make_shared<FailLookupCommand>(keys);
    164 }
    165 
    166 std::shared_ptr<Command> FindNext(uint64 key, uint64 start, uint64 limit,
    167                                   const char* expected) {
    168   return std::make_shared<FindNextCommand>(key, start, limit, expected);
    169 }
    170 
    171 std::shared_ptr<Command> FailFindNext(uint64 key) {
    172   return std::make_shared<FailFindNextCommand>(key);
    173 }
    174 
    175 class IntervalMapTest
    176     : public ::testing::TestWithParam<std::vector<std::shared_ptr<Command>>> {};
    177 
    178 const std::vector<std::shared_ptr<Command>> tests[] = {
    179     {
    180         // Simple set/lookup
    181         Set(0, 10, "Added"), NumIntervals(1), Lookup(0, 9, "Added"),
    182         FailLookup({10, 11}),
    183     },
    184     {
    185         // Total overwrite same start
    186         Set(5, 10, "Added"), Set(5, 20, "Overwrite"), NumIntervals(1),
    187         Lookup(5, 19, "Overwrite"), FailLookup({3, 4, 20, 21}),
    188     },
    189     {
    190         // No overwrite, start of one equals limit of other
    191         Set(5, 10, "Segment 1"), Set(10, 20, "Segment 2"), NumIntervals(2),
    192         Lookup(5, 9, "Segment 1"), Lookup(10, 19, "Segment 2"),
    193         FailLookup({3, 4, 20, 21}),
    194     },
    195     {
    196         // Right side overwrite
    197         Set(5, 10, "Added"), Set(8, 12, "Overwrite"), NumIntervals(2),
    198         Lookup(5, 7, "Added"), Lookup(8, 11, "Overwrite"),
    199         FailLookup({3, 4, 12, 13}),
    200     },
    201     {
    202         // Left side overwrite
    203         Set(5, 10, "Added"), Set(3, 8, "Overwrite"), NumIntervals(2),
    204         Lookup(8, 9, "Added"), Lookup(3, 7, "Overwrite"),
    205         FailLookup({1, 2, 12, 13}),
    206     },
    207     {
    208         // Total overwrite
    209         Set(5, 10, "Added"), Set(3, 12, "Overwrite"), NumIntervals(1),
    210         Lookup(3, 11, "Overwrite"), FailLookup({1, 2, 12, 13}),
    211     },
    212     {
    213         // Internal overwrite
    214         Set(4, 11, "Added"), Set(6, 9, "Overwrite"), NumIntervals(3),
    215         Lookup(4, 5, "Added"), Lookup(6, 8, "Overwrite"),
    216         Lookup(9, 10, "Added"), FailLookup({2, 3, 11, 12}),
    217     },
    218     {
    219         // Exact overwrite
    220         Set(5, 10, "Added"), Set(5, 10, "Overwrite"), NumIntervals(1),
    221         Lookup(5, 9, "Overwrite"), FailLookup({3, 4, 10, 11}),
    222     },
    223     {
    224         // Same left side overwrite
    225         Set(5, 10, "Added"), Set(5, 8, "Overwrite"), NumIntervals(2),
    226         Lookup(5, 7, "Overwrite"), Lookup(8, 9, "Added"),
    227         FailLookup({3, 4, 10, 11}),
    228     },
    229     {
    230         // Multiple total overwrite
    231         Set(5, 10, "SEG 1"), Set(8, 12, "SEG 2"), Set(16, 22, "SEG 3"),
    232         Set(25, 26, "SEG 4"), Set(3, 30, "Overwrite"), NumIntervals(1),
    233         Lookup(3, 29, "Overwrite"), FailLookup({1, 2, 30, 31}),
    234     },
    235     {
    236         // Multiple total overwrite, left side free
    237         Set(5, 10, "SEG 1"), Set(8, 12, "SEG 2"), Set(16, 22, "SEG 3"),
    238         Set(25, 26, "SEG 4"), Set(7, 30, "Overwrite"), NumIntervals(2),
    239         Lookup(5, 6, "SEG 1"), Lookup(7, 29, "Overwrite"),
    240         FailLookup({3, 4, 30, 31}),
    241     },
    242     {
    243         // Multiple total overwrite, right side free
    244         Set(5, 10, "SEG 1"), Set(8, 12, "SEG 2"), Set(16, 22, "SEG 3"),
    245         Set(25, 32, "SEG 4"), Set(3, 30, "Overwrite"), NumIntervals(2),
    246         Lookup(3, 29, "Overwrite"), Lookup(30, 31, "SEG 4"),
    247         FailLookup({1, 2, 32, 33}),
    248     },
    249     {
    250         // Multiple total overwrite, both sides free
    251         Set(5, 10, "SEG 1"), Set(8, 12, "SEG 2"), Set(16, 22, "SEG 3"),
    252         Set(25, 32, "SEG 4"), Set(7, 30, "Overwrite"), NumIntervals(3),
    253         Lookup(5, 6, "SEG 1"), Lookup(7, 29, "Overwrite"),
    254         Lookup(30, 31, "SEG 4"), FailLookup({3, 4, 32, 33}),
    255     },
    256     {
    257         // Two segments partly overwritten
    258         Set(5, 10, "SEG 1"), Set(17, 25, "SEG 2"), Set(8, 20, "Overwrite"),
    259         NumIntervals(3), Lookup(5, 7, "SEG 1"), Lookup(8, 19, "Overwrite"),
    260         Lookup(20, 24, "SEG 2"), FailLookup({3, 4, 25, 26}),
    261     },
    262     {
    263         // Loop through interval map using FindNext
    264         Set(5, 10, "SEG 1"), Set(15, 20, "SEG 2"), FindNext(0, 5, 10, "SEG 1"),
    265         FindNext(10, 15, 20, "SEG 2"), FailFindNext(20),
    266     },
    267 };
    268 
    269 TEST_P(IntervalMapTest, GenericTest) {
    270   IntervalMap<string> map;
    271   const auto& commands = GetParam();
    272   for (const auto& command : commands) {
    273     command->ExecuteOn(&map);
    274     // Failed asserts in subroutines aren't actually fatal so we have to return
    275     // manually.
    276     if (HasFatalFailure()) return;
    277   }
    278 }
    279 
    280 INSTANTIATE_TEST_CASE_P(AllIntervalMapTests, IntervalMapTest,
    281                         ::testing::ValuesIn(tests));
    282 
    283 }  // namespace
    284 }  // namespace perftools
    285 
    286 int main(int argc, char** argv) {
    287   ::testing::InitGoogleTest(&argc, argv);
    288   return RUN_ALL_TESTS();
    289 }
    290 
    291 #endif  // PERFTOOLS_INTERVALMAP_TEST_H_
    292