|
1 // Copyright (c) 2008, Google Inc. |
|
2 // All rights reserved. |
|
3 // |
|
4 // Redistribution and use in source and binary forms, with or without |
|
5 // modification, are permitted provided that the following conditions are |
|
6 // met: |
|
7 // |
|
8 // * Redistributions of source code must retain the above copyright |
|
9 // notice, this list of conditions and the following disclaimer. |
|
10 // * Redistributions in binary form must reproduce the above |
|
11 // copyright notice, this list of conditions and the following disclaimer |
|
12 // in the documentation and/or other materials provided with the |
|
13 // distribution. |
|
14 // * Neither the name of Google Inc. nor the names of its |
|
15 // contributors may be used to endorse or promote products derived from |
|
16 // this software without specific prior written permission. |
|
17 // |
|
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
29 |
|
30 #import "SimpleStringDictionaryTest.h" |
|
31 #import "SimpleStringDictionary.h" |
|
32 |
|
33 using google_breakpad::KeyValueEntry; |
|
34 using google_breakpad::SimpleStringDictionary; |
|
35 using google_breakpad::SimpleStringDictionaryIterator; |
|
36 |
|
37 @implementation SimpleStringDictionaryTest |
|
38 |
|
39 //============================================================================== |
|
40 - (void)testKeyValueEntry { |
|
41 KeyValueEntry entry; |
|
42 |
|
43 // Verify that initial state is correct |
|
44 STAssertFalse(entry.IsActive(), @"Initial key value entry is active!"); |
|
45 STAssertEquals(strlen(entry.GetKey()), (size_t)0, @"Empty key value did not " |
|
46 @"have length 0"); |
|
47 STAssertEquals(strlen(entry.GetValue()), (size_t)0, @"Empty key value did not " |
|
48 @"have length 0"); |
|
49 |
|
50 // Try setting a key/value and then verify |
|
51 entry.SetKeyValue("key1", "value1"); |
|
52 STAssertEqualCStrings(entry.GetKey(), "key1", @"key was not equal to key1"); |
|
53 STAssertEqualCStrings(entry.GetValue(), "value1", @"value was not equal"); |
|
54 |
|
55 // Try setting a new value |
|
56 entry.SetValue("value3"); |
|
57 |
|
58 // Make sure the new value took |
|
59 STAssertEqualCStrings(entry.GetValue(), "value3", @"value was not equal"); |
|
60 |
|
61 // Make sure the key didn't change |
|
62 STAssertEqualCStrings(entry.GetKey(), "key1", @"key changed after setting " |
|
63 @"value!"); |
|
64 |
|
65 // Try setting a new key/value and then verify |
|
66 entry.SetKeyValue("key2", "value2"); |
|
67 STAssertEqualCStrings(entry.GetKey(), "key2", @"New key was not equal to " |
|
68 @"key2"); |
|
69 STAssertEqualCStrings(entry.GetValue(), "value2", @"New value was not equal " |
|
70 @"to value2"); |
|
71 |
|
72 // Clear the entry and verify the key and value are empty strings |
|
73 entry.Clear(); |
|
74 STAssertFalse(entry.IsActive(), @"Key value clear did not clear object"); |
|
75 STAssertEquals(strlen(entry.GetKey()), (size_t)0, @"Length of cleared key " |
|
76 @"was not 0"); |
|
77 STAssertEquals(strlen(entry.GetValue()), (size_t)0, @"Length of cleared " |
|
78 @"value was not 0!"); |
|
79 } |
|
80 |
|
81 - (void)testEmptyKeyValueCombos { |
|
82 KeyValueEntry entry; |
|
83 entry.SetKeyValue(NULL, NULL); |
|
84 STAssertEqualCStrings(entry.GetKey(), "", @"Setting NULL key did not return " |
|
85 @"empty key!"); |
|
86 STAssertEqualCStrings(entry.GetValue(), "", @"Setting NULL value did not " |
|
87 @"set empty string value!"); |
|
88 } |
|
89 |
|
90 |
|
91 //============================================================================== |
|
92 - (void)testSimpleStringDictionary { |
|
93 // Make a new dictionary |
|
94 SimpleStringDictionary *dict = new SimpleStringDictionary(); |
|
95 STAssertTrue(dict != NULL, nil); |
|
96 |
|
97 // try passing in NULL for key |
|
98 //dict->SetKeyValue(NULL, "bad"); // causes assert() to fire |
|
99 |
|
100 // Set three distinct values on three keys |
|
101 dict->SetKeyValue("key1", "value1"); |
|
102 dict->SetKeyValue("key2", "value2"); |
|
103 dict->SetKeyValue("key3", "value3"); |
|
104 |
|
105 STAssertTrue(!strcmp(dict->GetValueForKey("key1"), "value1"), nil); |
|
106 STAssertTrue(!strcmp(dict->GetValueForKey("key2"), "value2"), nil); |
|
107 STAssertTrue(!strcmp(dict->GetValueForKey("key3"), "value3"), nil); |
|
108 STAssertEquals(dict->GetCount(), 3, @"GetCount did not return 3"); |
|
109 // try an unknown key |
|
110 STAssertTrue(dict->GetValueForKey("key4") == NULL, nil); |
|
111 |
|
112 // try a NULL key |
|
113 //STAssertTrue(dict->GetValueForKey(NULL) == NULL, nil); // asserts |
|
114 |
|
115 // Remove a key |
|
116 dict->RemoveKey("key3"); |
|
117 |
|
118 // Now make sure it's not there anymore |
|
119 STAssertTrue(dict->GetValueForKey("key3") == NULL, nil); |
|
120 |
|
121 // Remove a NULL key |
|
122 //dict->RemoveKey(NULL); // will cause assert() to fire |
|
123 |
|
124 // Remove by setting value to NULL |
|
125 dict->SetKeyValue("key2", NULL); |
|
126 |
|
127 // Now make sure it's not there anymore |
|
128 STAssertTrue(dict->GetValueForKey("key2") == NULL, nil); |
|
129 } |
|
130 |
|
131 //============================================================================== |
|
132 // The idea behind this test is to add a bunch of values to the dictionary, |
|
133 // remove some in the middle, then add a few more in. We then create a |
|
134 // SimpleStringDictionaryIterator and iterate through the dictionary, taking |
|
135 // note of the key/value pairs we see. We then verify that it iterates |
|
136 // through exactly the number of key/value pairs we expect, and that they |
|
137 // match one-for-one with what we would expect. In all cases we're setting |
|
138 // key value pairs of the form: |
|
139 // |
|
140 // key<n>/value<n> (like key0/value0, key17,value17, etc.) |
|
141 // |
|
142 - (void)testSimpleStringDictionaryIterator { |
|
143 SimpleStringDictionary *dict = new SimpleStringDictionary(); |
|
144 STAssertTrue(dict != NULL, nil); |
|
145 |
|
146 char key[KeyValueEntry::MAX_STRING_STORAGE_SIZE]; |
|
147 char value[KeyValueEntry::MAX_STRING_STORAGE_SIZE]; |
|
148 |
|
149 const int kDictionaryCapacity = SimpleStringDictionary::MAX_NUM_ENTRIES; |
|
150 const int kPartitionIndex = kDictionaryCapacity - 5; |
|
151 |
|
152 // We assume at least this size in the tests below |
|
153 STAssertTrue(kDictionaryCapacity >= 64, nil); |
|
154 |
|
155 // We'll keep track of the number of key/value pairs we think should |
|
156 // be in the dictionary |
|
157 int expectedDictionarySize = 0; |
|
158 |
|
159 // Set a bunch of key/value pairs like key0/value0, key1/value1, ... |
|
160 for (int i = 0; i < kPartitionIndex; ++i) { |
|
161 sprintf(key, "key%d", i); |
|
162 sprintf(value, "value%d", i); |
|
163 dict->SetKeyValue(key, value); |
|
164 } |
|
165 expectedDictionarySize = kPartitionIndex; |
|
166 |
|
167 // set a couple of the keys twice (with the same value) - should be nop |
|
168 dict->SetKeyValue("key2", "value2"); |
|
169 dict->SetKeyValue("key4", "value4"); |
|
170 dict->SetKeyValue("key15", "value15"); |
|
171 |
|
172 // Remove some random elements in the middle |
|
173 dict->RemoveKey("key7"); |
|
174 dict->RemoveKey("key18"); |
|
175 dict->RemoveKey("key23"); |
|
176 dict->RemoveKey("key31"); |
|
177 expectedDictionarySize -= 4; // we just removed four key/value pairs |
|
178 |
|
179 // Set some more key/value pairs like key59/value59, key60/value60, ... |
|
180 for (int i = kPartitionIndex; i < kDictionaryCapacity; ++i) { |
|
181 sprintf(key, "key%d", i); |
|
182 sprintf(value, "value%d", i); |
|
183 dict->SetKeyValue(key, value); |
|
184 } |
|
185 expectedDictionarySize += kDictionaryCapacity - kPartitionIndex; |
|
186 |
|
187 // Now create an iterator on the dictionary |
|
188 SimpleStringDictionaryIterator iter(*dict); |
|
189 |
|
190 // We then verify that it iterates through exactly the number of |
|
191 // key/value pairs we expect, and that they match one-for-one with what we |
|
192 // would expect. The ordering of the iteration does not matter... |
|
193 |
|
194 // used to keep track of number of occurrences found for key/value pairs |
|
195 int count[kDictionaryCapacity]; |
|
196 memset(count, 0, sizeof(count)); |
|
197 |
|
198 int totalCount = 0; |
|
199 |
|
200 const KeyValueEntry *entry; |
|
201 |
|
202 while ((entry = iter.Next())) { |
|
203 totalCount++; |
|
204 |
|
205 // Extract keyNumber from a string of the form key<keyNumber> |
|
206 int keyNumber; |
|
207 sscanf(entry->GetKey(), "key%d", &keyNumber); |
|
208 |
|
209 // Extract valueNumber from a string of the form value<valueNumber> |
|
210 int valueNumber; |
|
211 sscanf(entry->GetValue(), "value%d", &valueNumber); |
|
212 |
|
213 // The value number should equal the key number since that's how we set them |
|
214 STAssertTrue(keyNumber == valueNumber, nil); |
|
215 |
|
216 // Key and value numbers should be in proper range: |
|
217 // 0 <= keyNumber < kDictionaryCapacity |
|
218 bool isKeyInGoodRange = |
|
219 (keyNumber >= 0 && keyNumber < kDictionaryCapacity); |
|
220 bool isValueInGoodRange = |
|
221 (valueNumber >= 0 && valueNumber < kDictionaryCapacity); |
|
222 STAssertTrue(isKeyInGoodRange, nil); |
|
223 STAssertTrue(isValueInGoodRange, nil); |
|
224 |
|
225 if (isKeyInGoodRange && isValueInGoodRange) { |
|
226 ++count[keyNumber]; |
|
227 } |
|
228 } |
|
229 |
|
230 // Make sure each of the key/value pairs showed up exactly one time, except |
|
231 // for the ones which we removed. |
|
232 for (int i = 0; i < kDictionaryCapacity; ++i) { |
|
233 // Skip over key7, key18, key23, and key31, since we removed them |
|
234 if (!(i == 7 || i == 18 || i == 23 || i == 31)) { |
|
235 STAssertTrue(count[i] == 1, nil); |
|
236 } |
|
237 } |
|
238 |
|
239 // Make sure the number of iterations matches the expected dictionary size. |
|
240 STAssertTrue(totalCount == expectedDictionarySize, nil); |
|
241 } |
|
242 |
|
243 @end |