From 30bb1ab6015b462b5f2c4b3ce1986dec96d1f716 Mon Sep 17 00:00:00 2001 From: "rsesek@chromium.org" Date: Thu, 18 Apr 2013 20:17:29 +0000 Subject: Move SimpleStringDictionary from common/mac/ to just common/. This also cleans up some things like the file name, trailing whitespace, and making the test use gtest instead of sentest, since there's nothing Mac specific about this. BUG=https://code.google.com/p/chromium/issues/detail?id=77656 Review URL: https://breakpad.appspot.com/561003 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1154 4c0a9323-5329-0410-9bdc-e9ce6186880e --- src/common/mac/SimpleStringDictionary.h | 195 --------------------- src/common/mac/SimpleStringDictionary.mm | 133 -------------- src/common/simple_string_dictionary.cc | 129 ++++++++++++++ src/common/simple_string_dictionary.h | 192 ++++++++++++++++++++ src/common/simple_string_dictionary_unittest.cc | 221 ++++++++++++++++++++++++ 5 files changed, 542 insertions(+), 328 deletions(-) delete mode 100644 src/common/mac/SimpleStringDictionary.h delete mode 100644 src/common/mac/SimpleStringDictionary.mm create mode 100644 src/common/simple_string_dictionary.cc create mode 100644 src/common/simple_string_dictionary.h create mode 100644 src/common/simple_string_dictionary_unittest.cc (limited to 'src/common') diff --git a/src/common/mac/SimpleStringDictionary.h b/src/common/mac/SimpleStringDictionary.h deleted file mode 100644 index 814a6f7a..00000000 --- a/src/common/mac/SimpleStringDictionary.h +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// SimpleStringDictionary.h -// - -#ifndef SimpleStringDictionary_H__ -#define SimpleStringDictionary_H__ - -#import -#import - -namespace google_breakpad { - -//============================================================================== -// SimpleStringDictionary (and associated class KeyValueEntry) implement a very -// basic dictionary container class. It has the property of not making any -// memory allocations when getting and setting values. But it is not very -// efficient, with calls to get and set values operating in linear time. -// It has the additional limitation of having a fairly small fixed capacity of -// SimpleStringDictionary::MAX_NUM_ENTRIES entries. An assert() will fire if -// the client attempts to set more than this number of key/value pairs. -// Ordinarilly a C++ programmer would use something like the std::map template -// class, or on the Macintosh would often choose CFDictionary or NSDictionary. -// But these dictionary classes may call malloc() during get and set operations. -// Google Breakpad requires that no memory allocations be made in code running -// in its exception handling thread, so it uses SimpleStringDictionary as the -// underlying implementation for the GoogleBreakpad.framework APIs: -// GoogleBreakpadSetKeyValue(), GoogleBreakpadKeyValue(), and -// GoogleBreakpadRemoveKeyValue() -// - -//============================================================================== -// KeyValueEntry -// -// A helper class used by SimpleStringDictionary representing a single -// storage cell for a key/value pair. Each key and value string are -// limited to MAX_STRING_STORAGE_SIZE-1 bytes (not glyphs). This class -// performs no memory allocations. It has methods for setting and getting -// key and value strings. -// -class KeyValueEntry { - public: - KeyValueEntry() { - Clear(); - } - - KeyValueEntry(const char *key, const char *value) { - SetKeyValue(key, value); - } - - void SetKeyValue(const char *key, const char *value) { - if (!key) { - key = ""; - } - if (!value) { - value = ""; - } - - strlcpy(key_, key, sizeof(key_)); - strlcpy(value_, value, sizeof(value_)); - } - - void SetValue(const char *value) { - if (!value) { - value = ""; - } - strlcpy(value_, value, sizeof(value_)); - }; - - // Removes the key/value - void Clear() { - memset(key_, 0, sizeof(key_)); - memset(value_, 0, sizeof(value_)); - } - - bool IsActive() const { return key_[0] != '\0'; } - const char *GetKey() const { return key_; } - const char *GetValue() const { return value_; } - - // Don't change this without considering the fixed size - // of MachMessage (in MachIPC.h) - // (see also struct KeyValueMessageData in Inspector.h) - enum {MAX_STRING_STORAGE_SIZE = 256}; - - private: - char key_[MAX_STRING_STORAGE_SIZE]; - char value_[MAX_STRING_STORAGE_SIZE]; -}; - -//============================================================================== -// This class is not an efficient dictionary, but for the purposes of breakpad -// will be just fine. We're just dealing with ten or so distinct -// key/value pairs. The idea is to avoid any malloc() or free() calls -// in certain important methods to be called when a process is in a -// crashed state. Each key and value string are limited to -// KeyValueEntry::MAX_STRING_STORAGE_SIZE-1 bytes (not glyphs). Strings passed -// in exceeding this length will be truncated. -// -class SimpleStringDictionary { - public: - SimpleStringDictionary() {}; // entries will all be cleared - - // Returns the number of active key/value pairs. The upper limit for this - // is MAX_NUM_ENTRIES. - int GetCount() const; - - // Given |key|, returns its corresponding |value|. - // If |key| is NULL, an assert will fire or NULL will be returned. If |key| - // is not found or is an empty string, NULL is returned. - const char *GetValueForKey(const char *key) const; - - // Stores a string |value| represented by |key|. If |key| is NULL or an empty - // string, this will assert (or do nothing). If |value| is NULL then - // the |key| will be removed. An empty string is OK for |value|. - void SetKeyValue(const char *key, const char *value); - - // Given |key|, removes any associated value. It will assert (or do nothing) - // if NULL is passed in. It will do nothing if |key| is not found. - void RemoveKey(const char *key); - - // This is the maximum number of key/value pairs which may be set in the - // dictionary. An assert may fire if more values than this are set. - // Don't change this without also changing comment in GoogleBreakpad.h - enum {MAX_NUM_ENTRIES = 64}; - - private: - friend class SimpleStringDictionaryIterator; - - const KeyValueEntry *GetEntry(int i) const; - - KeyValueEntry entries_[MAX_NUM_ENTRIES]; -}; - -//============================================================================== -class SimpleStringDictionaryIterator { - public: - SimpleStringDictionaryIterator(const SimpleStringDictionary &dict) - : dict_(dict), i_(0) { - } - - // Initializes iterator to the beginning (may later call Next() ) - void Start() { - i_ = 0; - } - - // like the nextObject method of NSEnumerator (in Cocoa) - // returns NULL when there are no more entries - // - const KeyValueEntry* Next() { - for (; i_ < SimpleStringDictionary::MAX_NUM_ENTRIES; ++i_) { - const KeyValueEntry *entry = dict_.GetEntry(i_); - if (entry->IsActive()) { - i_++; // move to next entry for next time - return entry; - } - } - - return NULL; // reached end of array - } - - private: - const SimpleStringDictionary& dict_; - int i_; -}; - -} // namespace google_breakpad - -#endif // SimpleStringDictionary_H__ diff --git a/src/common/mac/SimpleStringDictionary.mm b/src/common/mac/SimpleStringDictionary.mm deleted file mode 100644 index b97b760c..00000000 --- a/src/common/mac/SimpleStringDictionary.mm +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// SimpleStringDictionary.mm -// Simple string dictionary that does not allocate memory -// - -#include - -#import "SimpleStringDictionary.h" - -namespace google_breakpad { - -//============================================================================== -const KeyValueEntry *SimpleStringDictionary::GetEntry(int i) const { - return (i >= 0 && i < MAX_NUM_ENTRIES) ? &entries_[i] : NULL; -} - -//============================================================================== -int SimpleStringDictionary::GetCount() const { - int count = 0; - for (int i = 0; i < MAX_NUM_ENTRIES; ++i) { - if (entries_[i].IsActive() ) { - ++count; - } - } - - return count; -} - -//============================================================================== -const char *SimpleStringDictionary::GetValueForKey(const char *key) const { - assert(key); - if (!key) - return NULL; - - for (int i = 0; i < MAX_NUM_ENTRIES; ++i) { - const KeyValueEntry &entry = entries_[i]; - if (entry.IsActive() && !strcmp(entry.GetKey(), key)) { - return entry.GetValue(); - } - } - - return NULL; -} - -//============================================================================== -void SimpleStringDictionary::SetKeyValue(const char *key, - const char *value) { - if (!value) { - RemoveKey(key); - return; - } - - // key must not be NULL - assert(key); - if (!key) - return; - - // key must not be empty string - assert(key[0] != '\0'); - if (key[0] == '\0') - return; - - int free_index = -1; - - // check if key already exists - for (int i = 0; i < MAX_NUM_ENTRIES; ++i) { - KeyValueEntry &entry = entries_[i]; - - if (entry.IsActive()) { - if (!strcmp(entry.GetKey(), key)) { - entry.SetValue(value); - return; - } - } else { - // Make a note of an empty slot - if (free_index == -1) { - free_index = i; - } - } - } - - // check if we've run out of space - assert(free_index != -1); - - // Put new key into an empty slot (if found) - if (free_index != -1) { - entries_[free_index].SetKeyValue(key, value); - } -} - -//============================================================================== -void SimpleStringDictionary::RemoveKey(const char *key) { - assert(key); - if (!key) - return; - - for (int i = 0; i < MAX_NUM_ENTRIES; ++i) { - if (!strcmp(entries_[i].GetKey(), key)) { - entries_[i].Clear(); - return; - } - } -} - -} // namespace google_breakpad diff --git a/src/common/simple_string_dictionary.cc b/src/common/simple_string_dictionary.cc new file mode 100644 index 00000000..f28ee9ef --- /dev/null +++ b/src/common/simple_string_dictionary.cc @@ -0,0 +1,129 @@ +// Copyright (c) 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include + +#include "common/simple_string_dictionary.h" + +namespace google_breakpad { + +//============================================================================== +const KeyValueEntry *SimpleStringDictionary::GetEntry(int i) const { + return (i >= 0 && i < MAX_NUM_ENTRIES) ? &entries_[i] : NULL; +} + +//============================================================================== +int SimpleStringDictionary::GetCount() const { + int count = 0; + for (int i = 0; i < MAX_NUM_ENTRIES; ++i) { + if (entries_[i].IsActive() ) { + ++count; + } + } + + return count; +} + +//============================================================================== +const char *SimpleStringDictionary::GetValueForKey(const char *key) const { + assert(key); + if (!key) + return NULL; + + for (int i = 0; i < MAX_NUM_ENTRIES; ++i) { + const KeyValueEntry &entry = entries_[i]; + if (entry.IsActive() && !strcmp(entry.GetKey(), key)) { + return entry.GetValue(); + } + } + + return NULL; +} + +//============================================================================== +void SimpleStringDictionary::SetKeyValue(const char *key, + const char *value) { + if (!value) { + RemoveKey(key); + return; + } + + // key must not be NULL + assert(key); + if (!key) + return; + + // key must not be empty string + assert(key[0] != '\0'); + if (key[0] == '\0') + return; + + int free_index = -1; + + // check if key already exists + for (int i = 0; i < MAX_NUM_ENTRIES; ++i) { + KeyValueEntry &entry = entries_[i]; + + if (entry.IsActive()) { + if (!strcmp(entry.GetKey(), key)) { + entry.SetValue(value); + return; + } + } else { + // Make a note of an empty slot + if (free_index == -1) { + free_index = i; + } + } + } + + // check if we've run out of space + assert(free_index != -1); + + // Put new key into an empty slot (if found) + if (free_index != -1) { + entries_[free_index].SetKeyValue(key, value); + } +} + +//============================================================================== +void SimpleStringDictionary::RemoveKey(const char *key) { + assert(key); + if (!key) + return; + + for (int i = 0; i < MAX_NUM_ENTRIES; ++i) { + if (!strcmp(entries_[i].GetKey(), key)) { + entries_[i].Clear(); + return; + } + } +} + +} // namespace google_breakpad diff --git a/src/common/simple_string_dictionary.h b/src/common/simple_string_dictionary.h new file mode 100644 index 00000000..dbeaabc0 --- /dev/null +++ b/src/common/simple_string_dictionary.h @@ -0,0 +1,192 @@ +// Copyright (c) 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef COMMON_SIMPLE_STRING_DICTIONARY_H_ +#define COMMON_SIMPLE_STRING_DICTIONARY_H_ + +#import +#import + +namespace google_breakpad { + +//============================================================================== +// SimpleStringDictionary (and associated class KeyValueEntry) implement a very +// basic dictionary container class. It has the property of not making any +// memory allocations when getting and setting values. But it is not very +// efficient, with calls to get and set values operating in linear time. +// It has the additional limitation of having a fairly small fixed capacity of +// SimpleStringDictionary::MAX_NUM_ENTRIES entries. An assert() will fire if +// the client attempts to set more than this number of key/value pairs. +// Ordinarilly a C++ programmer would use something like the std::map template +// class, or on the Macintosh would often choose CFDictionary or NSDictionary. +// But these dictionary classes may call malloc() during get and set operations. +// Google Breakpad requires that no memory allocations be made in code running +// in its exception handling thread, so it uses SimpleStringDictionary as the +// underlying implementation for the GoogleBreakpad.framework APIs: +// GoogleBreakpadSetKeyValue(), GoogleBreakpadKeyValue(), and +// GoogleBreakpadRemoveKeyValue() +// + +//============================================================================== +// KeyValueEntry +// +// A helper class used by SimpleStringDictionary representing a single +// storage cell for a key/value pair. Each key and value string are +// limited to MAX_STRING_STORAGE_SIZE-1 bytes (not glyphs). This class +// performs no memory allocations. It has methods for setting and getting +// key and value strings. +// +class KeyValueEntry { + public: + KeyValueEntry() { + Clear(); + } + + KeyValueEntry(const char *key, const char *value) { + SetKeyValue(key, value); + } + + void SetKeyValue(const char *key, const char *value) { + if (!key) { + key = ""; + } + if (!value) { + value = ""; + } + + strlcpy(key_, key, sizeof(key_)); + strlcpy(value_, value, sizeof(value_)); + } + + void SetValue(const char *value) { + if (!value) { + value = ""; + } + strlcpy(value_, value, sizeof(value_)); + }; + + // Removes the key/value + void Clear() { + memset(key_, 0, sizeof(key_)); + memset(value_, 0, sizeof(value_)); + } + + bool IsActive() const { return key_[0] != '\0'; } + const char *GetKey() const { return key_; } + const char *GetValue() const { return value_; } + + // Don't change this without considering the fixed size + // of MachMessage (in MachIPC.h) + // (see also struct KeyValueMessageData in Inspector.h) + enum {MAX_STRING_STORAGE_SIZE = 256}; + + private: + char key_[MAX_STRING_STORAGE_SIZE]; + char value_[MAX_STRING_STORAGE_SIZE]; +}; + +//============================================================================== +// This class is not an efficient dictionary, but for the purposes of breakpad +// will be just fine. We're just dealing with ten or so distinct +// key/value pairs. The idea is to avoid any malloc() or free() calls +// in certain important methods to be called when a process is in a +// crashed state. Each key and value string are limited to +// KeyValueEntry::MAX_STRING_STORAGE_SIZE-1 bytes (not glyphs). Strings passed +// in exceeding this length will be truncated. +// +class SimpleStringDictionary { + public: + SimpleStringDictionary() {}; // entries will all be cleared + + // Returns the number of active key/value pairs. The upper limit for this + // is MAX_NUM_ENTRIES. + int GetCount() const; + + // Given |key|, returns its corresponding |value|. + // If |key| is NULL, an assert will fire or NULL will be returned. If |key| + // is not found or is an empty string, NULL is returned. + const char *GetValueForKey(const char *key) const; + + // Stores a string |value| represented by |key|. If |key| is NULL or an empty + // string, this will assert (or do nothing). If |value| is NULL then + // the |key| will be removed. An empty string is OK for |value|. + void SetKeyValue(const char *key, const char *value); + + // Given |key|, removes any associated value. It will assert (or do nothing) + // if NULL is passed in. It will do nothing if |key| is not found. + void RemoveKey(const char *key); + + // This is the maximum number of key/value pairs which may be set in the + // dictionary. An assert may fire if more values than this are set. + // Don't change this without also changing comment in GoogleBreakpad.h + enum {MAX_NUM_ENTRIES = 64}; + + private: + friend class SimpleStringDictionaryIterator; + + const KeyValueEntry *GetEntry(int i) const; + + KeyValueEntry entries_[MAX_NUM_ENTRIES]; +}; + +//============================================================================== +class SimpleStringDictionaryIterator { + public: + SimpleStringDictionaryIterator(const SimpleStringDictionary &dict) + : dict_(dict), i_(0) { + } + + // Initializes iterator to the beginning (may later call Next() ) + void Start() { + i_ = 0; + } + + // like the nextObject method of NSEnumerator (in Cocoa) + // returns NULL when there are no more entries + // + const KeyValueEntry* Next() { + for (; i_ < SimpleStringDictionary::MAX_NUM_ENTRIES; ++i_) { + const KeyValueEntry *entry = dict_.GetEntry(i_); + if (entry->IsActive()) { + i_++; // move to next entry for next time + return entry; + } + } + + return NULL; // reached end of array + } + + private: + const SimpleStringDictionary& dict_; + int i_; +}; + +} // namespace google_breakpad + +#endif // COMMON_SIMPLE_STRING_DICTIONARY_H_ diff --git a/src/common/simple_string_dictionary_unittest.cc b/src/common/simple_string_dictionary_unittest.cc new file mode 100644 index 00000000..ff02115e --- /dev/null +++ b/src/common/simple_string_dictionary_unittest.cc @@ -0,0 +1,221 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "breakpad_googletest_includes.h" +#include "common/simple_string_dictionary.h" + +namespace google_breakpad { + +//============================================================================== +TEST(SimpleStringDictionaryTest, KeyValueEntry) { + KeyValueEntry entry; + + // Verify that initial state is correct + EXPECT_FALSE(entry.IsActive()); + EXPECT_EQ(strlen(entry.GetKey()), 0u); + EXPECT_EQ(strlen(entry.GetValue()), 0u); + + // Try setting a key/value and then verify + entry.SetKeyValue("key1", "value1"); + EXPECT_STREQ(entry.GetKey(), "key1"); + EXPECT_STREQ(entry.GetValue(), "value1"); + + // Try setting a new value + entry.SetValue("value3"); + + // Make sure the new value took + EXPECT_STREQ(entry.GetValue(), "value3"); + + // Make sure the key didn't change + EXPECT_STREQ(entry.GetKey(), "key1"); + + // Try setting a new key/value and then verify + entry.SetKeyValue("key2", "value2"); + EXPECT_STREQ(entry.GetKey(), "key2"); + EXPECT_STREQ(entry.GetValue(), "value2"); + + // Clear the entry and verify the key and value are empty strings + entry.Clear(); + EXPECT_FALSE(entry.IsActive()); + EXPECT_EQ(strlen(entry.GetKey()), 0u); + EXPECT_EQ(strlen(entry.GetValue()), 0u); +} + +TEST(SimpleStringDictionaryTest, EmptyKeyValueCombos) { + KeyValueEntry entry; + entry.SetKeyValue(NULL, NULL); + EXPECT_STREQ(entry.GetKey(), ""); + EXPECT_STREQ(entry.GetValue(), ""); +} + + +//============================================================================== +TEST(SimpleStringDictionaryTest, SimpleStringDictionary) { + // Make a new dictionary + SimpleStringDictionary *dict = new SimpleStringDictionary(); + ASSERT_TRUE(dict); + + // Set three distinct values on three keys + dict->SetKeyValue("key1", "value1"); + dict->SetKeyValue("key2", "value2"); + dict->SetKeyValue("key3", "value3"); + + EXPECT_NE(dict->GetValueForKey("key1"), "value1"); + EXPECT_NE(dict->GetValueForKey("key2"), "value2"); + EXPECT_NE(dict->GetValueForKey("key3"), "value3"); + EXPECT_EQ(dict->GetCount(), 3); + // try an unknown key + EXPECT_FALSE(dict->GetValueForKey("key4")); + + // Remove a key + dict->RemoveKey("key3"); + + // Now make sure it's not there anymore + EXPECT_FALSE(dict->GetValueForKey("key3")); + + // Remove by setting value to NULL + dict->SetKeyValue("key2", NULL); + + // Now make sure it's not there anymore + EXPECT_FALSE(dict->GetValueForKey("key2")); +} + +//============================================================================== +// The idea behind this test is to add a bunch of values to the dictionary, +// remove some in the middle, then add a few more in. We then create a +// SimpleStringDictionaryIterator and iterate through the dictionary, taking +// note of the key/value pairs we see. We then verify that it iterates +// through exactly the number of key/value pairs we expect, and that they +// match one-for-one with what we would expect. In all cases we're setting +// key value pairs of the form: +// +// key/value (like key0/value0, key17,value17, etc.) +// +TEST(SimpleStringDictionaryTest, SimpleStringDictionaryIterator) { + SimpleStringDictionary *dict = new SimpleStringDictionary(); + ASSERT_TRUE(dict); + + char key[KeyValueEntry::MAX_STRING_STORAGE_SIZE]; + char value[KeyValueEntry::MAX_STRING_STORAGE_SIZE]; + + const int kDictionaryCapacity = SimpleStringDictionary::MAX_NUM_ENTRIES; + const int kPartitionIndex = kDictionaryCapacity - 5; + + // We assume at least this size in the tests below + ASSERT_GE(kDictionaryCapacity, 64); + + // We'll keep track of the number of key/value pairs we think should + // be in the dictionary + int expectedDictionarySize = 0; + + // Set a bunch of key/value pairs like key0/value0, key1/value1, ... + for (int i = 0; i < kPartitionIndex; ++i) { + sprintf(key, "key%d", i); + sprintf(value, "value%d", i); + dict->SetKeyValue(key, value); + } + expectedDictionarySize = kPartitionIndex; + + // set a couple of the keys twice (with the same value) - should be nop + dict->SetKeyValue("key2", "value2"); + dict->SetKeyValue("key4", "value4"); + dict->SetKeyValue("key15", "value15"); + + // Remove some random elements in the middle + dict->RemoveKey("key7"); + dict->RemoveKey("key18"); + dict->RemoveKey("key23"); + dict->RemoveKey("key31"); + expectedDictionarySize -= 4; // we just removed four key/value pairs + + // Set some more key/value pairs like key59/value59, key60/value60, ... + for (int i = kPartitionIndex; i < kDictionaryCapacity; ++i) { + sprintf(key, "key%d", i); + sprintf(value, "value%d", i); + dict->SetKeyValue(key, value); + } + expectedDictionarySize += kDictionaryCapacity - kPartitionIndex; + + // Now create an iterator on the dictionary + SimpleStringDictionaryIterator iter(*dict); + + // We then verify that it iterates through exactly the number of + // key/value pairs we expect, and that they match one-for-one with what we + // would expect. The ordering of the iteration does not matter... + + // used to keep track of number of occurrences found for key/value pairs + int count[kDictionaryCapacity]; + memset(count, 0, sizeof(count)); + + int totalCount = 0; + + const KeyValueEntry *entry; + + while ((entry = iter.Next())) { + totalCount++; + + // Extract keyNumber from a string of the form key + int keyNumber; + sscanf(entry->GetKey(), "key%d", &keyNumber); + + // Extract valueNumber from a string of the form value + int valueNumber; + sscanf(entry->GetValue(), "value%d", &valueNumber); + + // The value number should equal the key number since that's how we set them + EXPECT_EQ(keyNumber, valueNumber); + + // Key and value numbers should be in proper range: + // 0 <= keyNumber < kDictionaryCapacity + bool isKeyInGoodRange = + (keyNumber >= 0 && keyNumber < kDictionaryCapacity); + bool isValueInGoodRange = + (valueNumber >= 0 && valueNumber < kDictionaryCapacity); + EXPECT_TRUE(isKeyInGoodRange); + EXPECT_TRUE(isValueInGoodRange); + + if (isKeyInGoodRange && isValueInGoodRange) { + ++count[keyNumber]; + } + } + + // Make sure each of the key/value pairs showed up exactly one time, except + // for the ones which we removed. + for (int i = 0; i < kDictionaryCapacity; ++i) { + // Skip over key7, key18, key23, and key31, since we removed them + if (!(i == 7 || i == 18 || i == 23 || i == 31)) { + EXPECT_EQ(count[i], 1); + } + } + + // Make sure the number of iterations matches the expected dictionary size. + EXPECT_EQ(totalCount, expectedDictionarySize); +} + +} // namespace google_breakpad -- cgit v1.2.1