Coverage for /Syzygy/bard/story_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
94.2%981040.C++test

Line-by-line coverage:

   1    :  // Copyright 2015 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include "syzygy/bard/story.h"
  16    :  
  17    :  #include <vector>
  18    :  
  19    :  #include "base/atomicops.h"
  20    :  #include "gmock/gmock.h"
  21    :  #include "gtest/gtest.h"
  22    :  #include "syzygy/bard/events/heap_alloc_event.h"
  23    :  #include "syzygy/bard/events/heap_create_event.h"
  24    :  #include "syzygy/bard/events/heap_destroy_event.h"
  25    :  #include "syzygy/bard/events/heap_free_event.h"
  26    :  #include "syzygy/bard/events/heap_size_event.h"
  27    :  #include "syzygy/bard/events/linked_event.h"
  28    :  #include "syzygy/core/unittest_util.h"
  29    :  
  30    :  namespace bard {
  31    :  namespace {
  32    :  
  33    :  using events::LinkedEvent;
  34    :  
  35    :  using events::HeapAllocEvent;
  36    :  using events::HeapCreateEvent;
  37    :  using events::HeapDestroyEvent;
  38    :  using events::HeapFreeEvent;
  39    :  using events::HeapSizeEvent;
  40    :  
  41    :  const HANDLE kLiveHeap = reinterpret_cast<HANDLE>(0x4197FC83);
  42    :  const HANDLE kTraceHeap = reinterpret_cast<HANDLE>(0xAB12CD34);
  43    :  const LPVOID kLiveAlloc = reinterpret_cast<LPVOID>(0x4820BC7A);
  44    :  const LPVOID kTraceAlloc = reinterpret_cast<LPVOID>(0xF1D97AE4);
  45    :  const DWORD kFlags = 1;
  46    :  const DWORD kOptions = 0;
  47    :  const SIZE_T kBytes = 100;
  48    :  const SIZE_T kSize = 100;
  49    :  const SIZE_T kInitialSize = 1;
  50    :  const SIZE_T kMaximumSize = 1000;
  51    :  
  52    :  class InvalidEvent : public EventInterface {
  53    :   public:
  54    :    EventType type() const override { return EventType::kMaxEventType; }
  55    :  
  56    :    bool Play(void* backdrop) override { return true; }
  57    :    bool Equals(const EventInterface*) const override { return false; }
  58    :  };
  59    :  
  60    :  // A simple event that simply returns false. Used for testing playback.
  61    :  class FailedEvent : public EventInterface {
  62    :   public:
  63  i :    EventType type() const override { return EventType::kMaxEventType; }
  64    :  
  65  E :    bool Play(void* backdrop) override { return false; }
  66  i :    bool Equals(const EventInterface*) const override { return false; }
  67    :  };
  68    :  
  69    :  // A simple event that appends its ID to a vector. Used for testing playback.
  70    :  class AppendEvent : public EventInterface {
  71    :   public:
  72  E :    explicit AppendEvent(uint32_t id) : id_(id) {}
  73  i :    EventType type() const override { return EventType::kMaxEventType; }
  74    :  
  75  E :    bool Play(void* backdrop) override {
  76  E :      auto v = reinterpret_cast<std::vector<uint32_t>*>(backdrop);
  77  E :      v->push_back(id_);
  78  E :      return true;
  79  E :    }
  80  i :    bool Equals(const EventInterface*) const override { return false; }
  81    :  
  82    :   private:
  83    :    uint32_t id_;
  84    :  };
  85    :  
  86    :  // A simple event that increments a counter atomically. Used for testing
  87    :  // playback.
  88    :  class IncrementEvent : public EventInterface {
  89    :   public:
  90  E :    explicit IncrementEvent(uint32_t amount) : amount_(amount) {}
  91  i :    EventType type() const override { return EventType::kMaxEventType; }
  92    :  
  93  E :    bool Play(void* backdrop) override {
  94  E :      auto atomic = reinterpret_cast<volatile base::subtle::Atomic32*>(backdrop);
  95  E :      base::subtle::Barrier_AtomicIncrement(atomic, amount_);
  96  E :      return true;
  97  E :    }
  98  i :    bool Equals(const EventInterface*) const override { return false; }
  99    :  
 100    :   private:
 101    :    uint32_t amount_;
 102    :  };
 103    :  
 104    :  }  // namespace
 105    :  
 106  E :  TEST(StoryTest, CreatePlotLine) {
 107  E :    Story s;
 108  E :    EXPECT_EQ(0u, s.plot_lines().size());
 109  E :    auto pl = s.CreatePlotLine();
 110  E :    EXPECT_TRUE(pl);
 111  E :    EXPECT_EQ(1u, s.plot_lines().size());
 112    :  
 113  E :    Story::PlotLine* pl2 = new Story::PlotLine();
 114  E :    EXPECT_EQ(pl2, s.AddPlotLine(std::unique_ptr<Story::PlotLine>(pl2)));
 115  E :    EXPECT_EQ(2u, s.plot_lines().size());
 116  E :  }
 117    :  
 118  E :  TEST(StoryTest, TestSerialization) {
 119  E :    std::unique_ptr<EventInterface> event1(
 120    :        new HeapCreateEvent(0, kOptions, kInitialSize, kMaximumSize, kTraceHeap));
 121  E :    std::unique_ptr<EventInterface> event2(
 122    :        new HeapAllocEvent(0, kTraceHeap, kFlags, kBytes, kTraceAlloc));
 123  E :    std::unique_ptr<EventInterface> event3(
 124    :        new HeapSizeEvent(0, kTraceHeap, kFlags, kTraceAlloc, kSize));
 125  E :    std::unique_ptr<EventInterface> event4(
 126    :        new HeapFreeEvent(0, kTraceHeap, kFlags, kTraceAlloc, true));
 127  E :    std::unique_ptr<EventInterface> event5(
 128    :        new HeapDestroyEvent(0, kTraceHeap, true));
 129    :  
 130    :    // The following events will either be cross plot line dependencies or have
 131    :    // such dependencies.
 132  E :    std::unique_ptr<LinkedEvent> linked_event1(
 133    :        new LinkedEvent(std::move(event1)));
 134  E :    std::unique_ptr<LinkedEvent> linked_event2(
 135    :        new LinkedEvent(std::move(event2)));
 136  E :    std::unique_ptr<LinkedEvent> linked_event4(
 137    :        new LinkedEvent(std::move(event4)));
 138  E :    std::unique_ptr<LinkedEvent> linked_event5(
 139    :        new LinkedEvent(std::move(event5)));
 140    :  
 141    :    // Alloc depends on Create, as it would be on another thread.
 142  E :    linked_event2->AddDep(linked_event1.get());
 143    :  
 144    :    // Similarly the heap can't be detroyed until all use of it has been
 145    :    // completed.
 146  E :    linked_event5->AddDep(linked_event4.get());
 147    :  
 148  E :    std::unique_ptr<Story::PlotLine> plot_line1(new Story::PlotLine());
 149  E :    std::unique_ptr<Story::PlotLine> plot_line2(new Story::PlotLine());
 150    :  
 151    :    // One plot line creates and frees the heap.
 152  E :    plot_line1->push_back(linked_event1.release());
 153  E :    plot_line1->push_back(linked_event5.release());
 154    :  
 155    :    // Another plot line owns the allocation.
 156  E :    plot_line2->push_back(linked_event2.release());
 157  E :    plot_line2->push_back(event3.release());
 158  E :    plot_line2->push_back(linked_event4.release());
 159    :  
 160    :    // Create a story to wrap it all up.
 161  E :    Story story;
 162  E :    story.AddPlotLine(std::move(plot_line1));
 163  E :    story.AddPlotLine(std::move(plot_line2));
 164    :  
 165  E :    EXPECT_TRUE(testing::TestSerialization(story));
 166  E :  }
 167    :  
 168  E :  TEST(PlotLineRunnerTest, StopOnFailedEvent) {
 169  E :    Story::PlotLine plot_line;
 170  E :    plot_line.push_back(new AppendEvent(0));
 171  E :    plot_line.push_back(new FailedEvent());
 172  E :    plot_line.push_back(new AppendEvent(1));
 173    :  
 174  E :    std::vector<uint32_t> v;
 175  E :    Story::PlotLineRunner runner(&v, &plot_line);
 176  E :    runner.Start();
 177  E :    runner.Join();
 178    :  
 179  E :    EXPECT_TRUE(runner.Failed());
 180  E :    EXPECT_EQ(plot_line[1], runner.failed_event());
 181  E :    EXPECT_THAT(v, testing::ElementsAre(0));
 182  E :  }
 183    :  
 184  E :  TEST(PlotLineRunnerTest, Succeeds) {
 185  E :    Story::PlotLine plot_line;
 186  E :    plot_line.push_back(new AppendEvent(0));
 187  E :    plot_line.push_back(new AppendEvent(1));
 188  E :    plot_line.push_back(new AppendEvent(2));
 189    :  
 190  E :    std::vector<uint32_t> v;
 191  E :    Story::PlotLineRunner runner(&v, &plot_line);
 192  E :    runner.Start();
 193  E :    runner.Join();
 194    :  
 195  E :    EXPECT_FALSE(runner.Failed());
 196  E :    EXPECT_EQ(nullptr, runner.failed_event());
 197  E :    EXPECT_THAT(v, testing::ElementsAre(0, 1, 2));
 198  E :  }
 199    :  
 200  E :  TEST(StoryTest, PlaybackStopsAndFails) {
 201  E :    Story story;
 202    :  
 203  E :    auto plot_line = story.CreatePlotLine();
 204  E :    plot_line->push_back(new AppendEvent(0));
 205  E :    plot_line->push_back(new FailedEvent());
 206  E :    plot_line->push_back(new AppendEvent(1));
 207    :  
 208  E :    std::vector<uint32_t> v;
 209  E :    EXPECT_FALSE(story.Play(&v));
 210  E :    EXPECT_THAT(v, testing::ElementsAre(0));
 211  E :  }
 212    :  
 213  E :  TEST(StoryTest, PlaybackSucceeds) {
 214  E :    Story story;
 215    :  
 216    :    // 10 plotlines (threads) with 10000 events each was sufficient to generate
 217    :    // race conditions on a Z600.
 218  E :    uint32_t sum = 0;
 219  E :    for (size_t i = 0; i < 10; ++i) {
 220  E :      auto pl = story.CreatePlotLine();;
 221  E :      for (size_t j = 0; j < 10000; ++j) {
 222  E :        pl->push_back(new IncrementEvent(j + i));
 223  E :        sum += j + i;
 224  E :      }
 225  E :    }
 226    :  
 227  E :    base::subtle::Atomic32 atomic = 0;
 228  E :    EXPECT_TRUE(story.Play(&atomic));
 229  E :    EXPECT_EQ(sum, atomic);
 230  E :  }
 231    :  
 232    :  }  // namespace bard

Coverage information generated Fri Jul 29 11:00:21 2016.