Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | // Copyright (c) 2006, Google Inc. |
michael@0 | 2 | // All rights reserved. |
michael@0 | 3 | // |
michael@0 | 4 | // Redistribution and use in source and binary forms, with or without |
michael@0 | 5 | // modification, are permitted provided that the following conditions are |
michael@0 | 6 | // met: |
michael@0 | 7 | // |
michael@0 | 8 | // * Redistributions of source code must retain the above copyright |
michael@0 | 9 | // notice, this list of conditions and the following disclaimer. |
michael@0 | 10 | // * Redistributions in binary form must reproduce the above |
michael@0 | 11 | // copyright notice, this list of conditions and the following disclaimer |
michael@0 | 12 | // in the documentation and/or other materials provided with the |
michael@0 | 13 | // distribution. |
michael@0 | 14 | // * Neither the name of Google Inc. nor the names of its |
michael@0 | 15 | // contributors may be used to endorse or promote products derived from |
michael@0 | 16 | // this software without specific prior written permission. |
michael@0 | 17 | // |
michael@0 | 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
michael@0 | 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
michael@0 | 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
michael@0 | 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
michael@0 | 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
michael@0 | 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
michael@0 | 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
michael@0 | 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
michael@0 | 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
michael@0 | 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
michael@0 | 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
michael@0 | 29 | |
michael@0 | 30 | // address_map_unittest.cc: Unit tests for AddressMap. |
michael@0 | 31 | // |
michael@0 | 32 | // Author: Mark Mentovai |
michael@0 | 33 | |
michael@0 | 34 | #include <limits.h> |
michael@0 | 35 | #include <stdio.h> |
michael@0 | 36 | |
michael@0 | 37 | #include "processor/address_map-inl.h" |
michael@0 | 38 | #include "processor/linked_ptr.h" |
michael@0 | 39 | #include "processor/logging.h" |
michael@0 | 40 | |
michael@0 | 41 | #define ASSERT_TRUE(condition) \ |
michael@0 | 42 | if (!(condition)) { \ |
michael@0 | 43 | fprintf(stderr, "FAIL: %s @ %s:%d\n", #condition, __FILE__, __LINE__); \ |
michael@0 | 44 | return false; \ |
michael@0 | 45 | } |
michael@0 | 46 | |
michael@0 | 47 | #define ASSERT_FALSE(condition) ASSERT_TRUE(!(condition)) |
michael@0 | 48 | |
michael@0 | 49 | #define ASSERT_EQ(e1, e2) ASSERT_TRUE((e1) == (e2)) |
michael@0 | 50 | |
michael@0 | 51 | namespace { |
michael@0 | 52 | |
michael@0 | 53 | using google_breakpad::AddressMap; |
michael@0 | 54 | using google_breakpad::linked_ptr; |
michael@0 | 55 | |
michael@0 | 56 | // A CountedObject holds an int. A global (not thread safe!) count of |
michael@0 | 57 | // allocated CountedObjects is maintained to help test memory management. |
michael@0 | 58 | class CountedObject { |
michael@0 | 59 | public: |
michael@0 | 60 | explicit CountedObject(int id) : id_(id) { ++count_; } |
michael@0 | 61 | ~CountedObject() { --count_; } |
michael@0 | 62 | |
michael@0 | 63 | static int count() { return count_; } |
michael@0 | 64 | int id() const { return id_; } |
michael@0 | 65 | |
michael@0 | 66 | private: |
michael@0 | 67 | static int count_; |
michael@0 | 68 | int id_; |
michael@0 | 69 | }; |
michael@0 | 70 | |
michael@0 | 71 | int CountedObject::count_; |
michael@0 | 72 | |
michael@0 | 73 | typedef int AddressType; |
michael@0 | 74 | typedef AddressMap< AddressType, linked_ptr<CountedObject> > TestMap; |
michael@0 | 75 | |
michael@0 | 76 | static bool DoAddressMapTest() { |
michael@0 | 77 | ASSERT_EQ(CountedObject::count(), 0); |
michael@0 | 78 | |
michael@0 | 79 | TestMap test_map; |
michael@0 | 80 | linked_ptr<CountedObject> entry; |
michael@0 | 81 | AddressType address; |
michael@0 | 82 | |
michael@0 | 83 | // Check that a new map is truly empty. |
michael@0 | 84 | ASSERT_FALSE(test_map.Retrieve(0, &entry, &address)); |
michael@0 | 85 | ASSERT_FALSE(test_map.Retrieve(INT_MIN, &entry, &address)); |
michael@0 | 86 | ASSERT_FALSE(test_map.Retrieve(INT_MAX, &entry, &address)); |
michael@0 | 87 | |
michael@0 | 88 | // Check that Clear clears the map without leaking. |
michael@0 | 89 | ASSERT_EQ(CountedObject::count(), 0); |
michael@0 | 90 | ASSERT_TRUE(test_map.Store(1, |
michael@0 | 91 | linked_ptr<CountedObject>(new CountedObject(0)))); |
michael@0 | 92 | ASSERT_TRUE(test_map.Retrieve(1, &entry, &address)); |
michael@0 | 93 | ASSERT_EQ(CountedObject::count(), 1); |
michael@0 | 94 | test_map.Clear(); |
michael@0 | 95 | ASSERT_EQ(CountedObject::count(), 1); // still holding entry in this scope |
michael@0 | 96 | |
michael@0 | 97 | // Check that a cleared map is truly empty. |
michael@0 | 98 | ASSERT_FALSE(test_map.Retrieve(0, &entry, &address)); |
michael@0 | 99 | ASSERT_FALSE(test_map.Retrieve(INT_MIN, &entry, &address)); |
michael@0 | 100 | ASSERT_FALSE(test_map.Retrieve(INT_MAX, &entry, &address)); |
michael@0 | 101 | |
michael@0 | 102 | // Check a single-element map. |
michael@0 | 103 | ASSERT_TRUE(test_map.Store(10, |
michael@0 | 104 | linked_ptr<CountedObject>(new CountedObject(1)))); |
michael@0 | 105 | ASSERT_FALSE(test_map.Retrieve(9, &entry, &address)); |
michael@0 | 106 | ASSERT_TRUE(test_map.Retrieve(10, &entry, &address)); |
michael@0 | 107 | ASSERT_EQ(CountedObject::count(), 1); |
michael@0 | 108 | ASSERT_EQ(entry->id(), 1); |
michael@0 | 109 | ASSERT_EQ(address, 10); |
michael@0 | 110 | ASSERT_TRUE(test_map.Retrieve(11, &entry, &address)); |
michael@0 | 111 | ASSERT_TRUE(test_map.Retrieve(11, &entry, NULL)); // NULL ok here |
michael@0 | 112 | |
michael@0 | 113 | // Add some more elements. |
michael@0 | 114 | ASSERT_TRUE(test_map.Store(5, |
michael@0 | 115 | linked_ptr<CountedObject>(new CountedObject(2)))); |
michael@0 | 116 | ASSERT_EQ(CountedObject::count(), 2); |
michael@0 | 117 | ASSERT_TRUE(test_map.Store(20, |
michael@0 | 118 | linked_ptr<CountedObject>(new CountedObject(3)))); |
michael@0 | 119 | ASSERT_TRUE(test_map.Store(15, |
michael@0 | 120 | linked_ptr<CountedObject>(new CountedObject(4)))); |
michael@0 | 121 | ASSERT_FALSE(test_map.Store(10, |
michael@0 | 122 | linked_ptr<CountedObject>(new CountedObject(5)))); // already in map |
michael@0 | 123 | ASSERT_TRUE(test_map.Store(16, |
michael@0 | 124 | linked_ptr<CountedObject>(new CountedObject(6)))); |
michael@0 | 125 | ASSERT_TRUE(test_map.Store(14, |
michael@0 | 126 | linked_ptr<CountedObject>(new CountedObject(7)))); |
michael@0 | 127 | |
michael@0 | 128 | // Nothing was stored with a key under 5. Don't use ASSERT inside loops |
michael@0 | 129 | // because it won't show exactly which key/entry/address failed. |
michael@0 | 130 | for (AddressType key = 0; key < 5; ++key) { |
michael@0 | 131 | if (test_map.Retrieve(key, &entry, &address)) { |
michael@0 | 132 | fprintf(stderr, |
michael@0 | 133 | "FAIL: retrieve %d expected false observed true @ %s:%d\n", |
michael@0 | 134 | key, __FILE__, __LINE__); |
michael@0 | 135 | return false; |
michael@0 | 136 | } |
michael@0 | 137 | } |
michael@0 | 138 | |
michael@0 | 139 | // Check everything that was stored. |
michael@0 | 140 | const int id_verify[] = { 0, 0, 0, 0, 0, // unused |
michael@0 | 141 | 2, 2, 2, 2, 2, // 5 - 9 |
michael@0 | 142 | 1, 1, 1, 1, 7, // 10 - 14 |
michael@0 | 143 | 4, 6, 6, 6, 6, // 15 - 19 |
michael@0 | 144 | 3, 3, 3, 3, 3, // 20 - 24 |
michael@0 | 145 | 3, 3, 3, 3, 3 }; // 25 - 29 |
michael@0 | 146 | const AddressType address_verify[] = { 0, 0, 0, 0, 0, // unused |
michael@0 | 147 | 5, 5, 5, 5, 5, // 5 - 9 |
michael@0 | 148 | 10, 10, 10, 10, 14, // 10 - 14 |
michael@0 | 149 | 15, 16, 16, 16, 16, // 15 - 19 |
michael@0 | 150 | 20, 20, 20, 20, 20, // 20 - 24 |
michael@0 | 151 | 20, 20, 20, 20, 20 }; // 25 - 29 |
michael@0 | 152 | |
michael@0 | 153 | for (AddressType key = 5; key < 30; ++key) { |
michael@0 | 154 | if (!test_map.Retrieve(key, &entry, &address)) { |
michael@0 | 155 | fprintf(stderr, |
michael@0 | 156 | "FAIL: retrieve %d expected true observed false @ %s:%d\n", |
michael@0 | 157 | key, __FILE__, __LINE__); |
michael@0 | 158 | return false; |
michael@0 | 159 | } |
michael@0 | 160 | if (entry->id() != id_verify[key]) { |
michael@0 | 161 | fprintf(stderr, |
michael@0 | 162 | "FAIL: retrieve %d expected entry %d observed %d @ %s:%d\n", |
michael@0 | 163 | key, id_verify[key], entry->id(), __FILE__, __LINE__); |
michael@0 | 164 | return false; |
michael@0 | 165 | } |
michael@0 | 166 | if (address != address_verify[key]) { |
michael@0 | 167 | fprintf(stderr, |
michael@0 | 168 | "FAIL: retrieve %d expected address %d observed %d @ %s:%d\n", |
michael@0 | 169 | key, address_verify[key], address, __FILE__, __LINE__); |
michael@0 | 170 | return false; |
michael@0 | 171 | } |
michael@0 | 172 | } |
michael@0 | 173 | |
michael@0 | 174 | // The stored objects should still be in the map. |
michael@0 | 175 | ASSERT_EQ(CountedObject::count(), 6); |
michael@0 | 176 | |
michael@0 | 177 | return true; |
michael@0 | 178 | } |
michael@0 | 179 | |
michael@0 | 180 | static bool RunTests() { |
michael@0 | 181 | if (!DoAddressMapTest()) |
michael@0 | 182 | return false; |
michael@0 | 183 | |
michael@0 | 184 | // Leak check. |
michael@0 | 185 | ASSERT_EQ(CountedObject::count(), 0); |
michael@0 | 186 | |
michael@0 | 187 | return true; |
michael@0 | 188 | } |
michael@0 | 189 | |
michael@0 | 190 | } // namespace |
michael@0 | 191 | |
michael@0 | 192 | int main(int argc, char **argv) { |
michael@0 | 193 | BPLOG_INIT(&argc, &argv); |
michael@0 | 194 | |
michael@0 | 195 | return RunTests() ? 0 : 1; |
michael@0 | 196 | } |