system/core: fix iterator for LruCache

Was failing to return the first element

Change-Id: Ic803f5d463a56519212014d0d190407cf4b859cf
diff --git a/include/utils/LruCache.h b/include/utils/LruCache.h
index 7818b4e..20a379e 100644
--- a/include/utils/LruCache.h
+++ b/include/utils/LruCache.h
@@ -99,17 +99,29 @@
     TValue mNullValue;
 
 public:
+    // To be used like:
+    // while (it.next()) {
+    //   it.value(); it.key();
+    // }
     class Iterator {
     public:
-        Iterator(const LruCache<TKey, TValue>& cache): mCache(cache), mIterator(mCache.mSet->begin()) {
+        Iterator(const LruCache<TKey, TValue>& cache):
+                mCache(cache), mIterator(mCache.mSet->begin()), mBeginReturned(false) {
         }
 
         bool next() {
             if (mIterator == mCache.mSet->end()) {
                 return false;
             }
-            std::advance(mIterator, 1);
-            return mIterator != mCache.mSet->end();
+            if (!mBeginReturned) {
+                // mIterator has been initialized to the beginning and
+                // hasn't been returned. Do not advance:
+                mBeginReturned = true;
+            } else {
+                std::advance(mIterator, 1);
+            }
+            bool ret = (mIterator != mCache.mSet->end());
+            return ret;
         }
 
         const TValue& value() const {
@@ -122,6 +134,7 @@
     private:
         const LruCache<TKey, TValue>& mCache;
         typename LruCacheSet::iterator mIterator;
+        bool mBeginReturned;
     };
 };
 
diff --git a/libutils/tests/LruCache_test.cpp b/libutils/tests/LruCache_test.cpp
index 2ed84d7..580b980 100644
--- a/libutils/tests/LruCache_test.cpp
+++ b/libutils/tests/LruCache_test.cpp
@@ -293,4 +293,110 @@
     EXPECT_EQ(3, callback.callbackCount);
 }
 
+TEST_F(LruCacheTest, IteratorCheck) {
+    LruCache<int, int> cache(100);
+
+    cache.put(1, 4);
+    cache.put(2, 5);
+    cache.put(3, 6);
+    EXPECT_EQ(3U, cache.size());
+
+    LruCache<int, int>::Iterator it(cache);
+    std::unordered_set<int> returnedValues;
+    while (it.next()) {
+        int v = it.value();
+        // Check we haven't seen the value before.
+        EXPECT_TRUE(returnedValues.find(v) == returnedValues.end());
+        returnedValues.insert(v);
+    }
+    EXPECT_EQ(std::unordered_set<int>({4, 5, 6}), returnedValues);
+}
+
+TEST_F(LruCacheTest, EmptyCacheIterator) {
+    // Check that nothing crashes...
+    LruCache<int, int> cache(100);
+
+    LruCache<int, int>::Iterator it(cache);
+    std::unordered_set<int> returnedValues;
+    while (it.next()) {
+        returnedValues.insert(it.value());
+    }
+    EXPECT_EQ(std::unordered_set<int>(), returnedValues);
+}
+
+TEST_F(LruCacheTest, OneElementCacheIterator) {
+    // Check that nothing crashes...
+    LruCache<int, int> cache(100);
+    cache.put(1, 2);
+
+    LruCache<int, int>::Iterator it(cache);
+    std::unordered_set<int> returnedValues;
+    while (it.next()) {
+        returnedValues.insert(it.value());
+    }
+    EXPECT_EQ(std::unordered_set<int>({ 2 }), returnedValues);
+}
+
+TEST_F(LruCacheTest, OneElementCacheRemove) {
+    LruCache<int, int> cache(100);
+    cache.put(1, 2);
+
+    cache.remove(1);
+
+    LruCache<int, int>::Iterator it(cache);
+    std::unordered_set<int> returnedValues;
+    while (it.next()) {
+        returnedValues.insert(it.value());
+    }
+    EXPECT_EQ(std::unordered_set<int>({ }), returnedValues);
+}
+
+TEST_F(LruCacheTest, Remove) {
+    LruCache<int, int> cache(100);
+    cache.put(1, 4);
+    cache.put(2, 5);
+    cache.put(3, 6);
+
+    cache.remove(2);
+
+    LruCache<int, int>::Iterator it(cache);
+    std::unordered_set<int> returnedValues;
+    while (it.next()) {
+        returnedValues.insert(it.value());
+    }
+    EXPECT_EQ(std::unordered_set<int>({ 4, 6 }), returnedValues);
+}
+
+TEST_F(LruCacheTest, RemoveYoungest) {
+    LruCache<int, int> cache(100);
+    cache.put(1, 4);
+    cache.put(2, 5);
+    cache.put(3, 6);
+
+    cache.remove(3);
+
+    LruCache<int, int>::Iterator it(cache);
+    std::unordered_set<int> returnedValues;
+    while (it.next()) {
+        returnedValues.insert(it.value());
+    }
+    EXPECT_EQ(std::unordered_set<int>({ 4, 5 }), returnedValues);
+}
+
+TEST_F(LruCacheTest, RemoveNonMember) {
+    LruCache<int, int> cache(100);
+    cache.put(1, 4);
+    cache.put(2, 5);
+    cache.put(3, 6);
+
+    cache.remove(7);
+
+    LruCache<int, int>::Iterator it(cache);
+    std::unordered_set<int> returnedValues;
+    while (it.next()) {
+        returnedValues.insert(it.value());
+    }
+    EXPECT_EQ(std::unordered_set<int>({ 4, 5, 6 }), returnedValues);
+}
+
 }