Move libandroidfw from frameworks/base

Change-Id: I8228c9a796e68e920c6a7dfc154c4b70ba66b082
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
new file mode 100644
index 0000000..c8e3f2b
--- /dev/null
+++ b/libs/androidfw/tests/Android.mk
@@ -0,0 +1,32 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# Build the unit tests.
+test_src_files := \
+    BackupData_test.cpp \
+    ObbFile_test.cpp \
+    ZipFileRO_test.cpp
+
+shared_libraries := \
+    libandroidfw \
+    libcutils \
+    libutils \
+    libui \
+    libstlport
+
+static_libraries := \
+    libgtest \
+    libgtest_main
+
+$(foreach file,$(test_src_files), \
+    $(eval include $(CLEAR_VARS)) \
+    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+    $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
+    $(eval LOCAL_SRC_FILES := $(file)) \
+    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+    $(eval include $(BUILD_NATIVE_TEST)) \
+)
+
+# Build the manual test programs.
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/libs/androidfw/tests/BackupData_test.cpp b/libs/androidfw/tests/BackupData_test.cpp
new file mode 100644
index 0000000..17f91ca
--- /dev/null
+++ b/libs/androidfw/tests/BackupData_test.cpp
@@ -0,0 +1,438 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ObbFile_test"
+#include <androidfw/BackupHelpers.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include <gtest/gtest.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+
+namespace android {
+
+#define TEST_FILENAME "/test.bd"
+
+// keys of different lengths to test padding
+#define KEY1 "key1"
+#define KEY2 "key2a"
+#define KEY3 "key3bc"
+#define KEY4 "key4def"
+
+// payloads of different lengths to test padding
+#define DATA1 "abcdefg"
+#define DATA2 "hijklmnopq"
+#define DATA3 "rstuvwxyz"
+// KEY4 is only ever deleted
+
+class BackupDataTest : public testing::Test {
+protected:
+    char* m_external_storage;
+    char* m_filename;
+    String8 mKey1;
+    String8 mKey2;
+    String8 mKey3;
+    String8 mKey4;
+
+    virtual void SetUp() {
+        m_external_storage = getenv("EXTERNAL_STORAGE");
+
+        const int totalLen = strlen(m_external_storage) + strlen(TEST_FILENAME) + 1;
+        m_filename = new char[totalLen];
+        snprintf(m_filename, totalLen, "%s%s", m_external_storage, TEST_FILENAME);
+
+        ::unlink(m_filename);
+        int fd = ::open(m_filename, O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+        if (fd < 0) {
+            FAIL() << "Couldn't create " << m_filename << " for writing";
+        }
+        mKey1 = String8(KEY1);
+        mKey2 = String8(KEY2);
+        mKey3 = String8(KEY3);
+        mKey4 = String8(KEY4);
+   }
+
+    virtual void TearDown() {
+    }
+};
+
+TEST_F(BackupDataTest, WriteAndReadSingle) {
+  int fd = ::open(m_filename, O_WRONLY);
+  BackupDataWriter* writer = new BackupDataWriter(fd);
+
+  EXPECT_EQ(NO_ERROR, writer->WriteEntityHeader(mKey1, sizeof(DATA1)))
+          << "WriteEntityHeader returned an error";
+  EXPECT_EQ(NO_ERROR, writer->WriteEntityData(DATA1, sizeof(DATA1)))
+          << "WriteEntityData returned an error";
+
+  ::close(fd);
+  fd = ::open(m_filename, O_RDONLY);
+  BackupDataReader* reader = new BackupDataReader(fd);
+  EXPECT_EQ(NO_ERROR, reader->Status())
+          << "Reader ctor failed";
+
+  bool done;
+  int type;
+  reader->ReadNextHeader(&done, &type);
+  EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+          << "wrong type from ReadNextHeader";
+
+  String8 key;
+  size_t dataSize;
+  EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+          << "ReadEntityHeader returned an error";
+  EXPECT_EQ(mKey1, key)
+          << "wrong key from ReadEntityHeader";
+  EXPECT_EQ(sizeof(DATA1), dataSize)
+          << "wrong size from ReadEntityHeader";
+
+  char* dataBytes = new char[dataSize];
+  EXPECT_EQ((int) dataSize, reader->ReadEntityData(dataBytes, dataSize))
+          << "ReadEntityData returned an error";
+  for (unsigned int i = 0; i < sizeof(DATA1); i++) {
+    EXPECT_EQ(DATA1[i], dataBytes[i])
+             << "data character " << i << " should be equal";
+  }
+  delete dataBytes;
+  delete writer;
+  delete reader;
+}
+
+TEST_F(BackupDataTest, WriteAndReadMultiple) {
+  int fd = ::open(m_filename, O_WRONLY);
+  BackupDataWriter* writer = new BackupDataWriter(fd);
+  writer->WriteEntityHeader(mKey1, sizeof(DATA1));
+  writer->WriteEntityData(DATA1, sizeof(DATA1));
+  writer->WriteEntityHeader(mKey2, sizeof(DATA2));
+  writer->WriteEntityData(DATA2, sizeof(DATA2));
+
+  ::close(fd);
+  fd = ::open(m_filename, O_RDONLY);
+  BackupDataReader* reader = new BackupDataReader(fd);
+
+  bool done;
+  int type;
+  String8 key;
+  size_t dataSize;
+  char* dataBytes;
+  // read first entity
+  reader->ReadNextHeader(&done, &type);
+  reader->ReadEntityHeader(&key, &dataSize);
+  dataBytes = new char[dataSize];
+  reader->ReadEntityData(dataBytes, dataSize);
+  delete dataBytes;
+
+  // read and verify second entity
+  reader->ReadNextHeader(&done, &type);
+  EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+          << "wrong type from ReadNextHeader";
+
+  EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+          << "ReadEntityHeader returned an error on second entity";
+  EXPECT_EQ(mKey2, key)
+          << "wrong key from ReadEntityHeader on second entity";
+  EXPECT_EQ(sizeof(DATA2), dataSize)
+          << "wrong size from ReadEntityHeader on second entity";
+
+  dataBytes = new char[dataSize];
+  EXPECT_EQ((int)dataSize, reader->ReadEntityData(dataBytes, dataSize))
+          << "ReadEntityData returned an error on second entity";
+  for (unsigned int i = 0; i < sizeof(DATA2); i++) {
+    EXPECT_EQ(DATA2[i], dataBytes[i])
+             << "data character " << i << " should be equal";
+  }
+  delete dataBytes;
+  delete writer;
+  delete reader;
+}
+
+TEST_F(BackupDataTest, SkipEntity) {
+  int fd = ::open(m_filename, O_WRONLY);
+  BackupDataWriter* writer = new BackupDataWriter(fd);
+  writer->WriteEntityHeader(mKey1, sizeof(DATA1));
+  writer->WriteEntityData(DATA1, sizeof(DATA1));
+  writer->WriteEntityHeader(mKey2, sizeof(DATA2));
+  writer->WriteEntityData(DATA2, sizeof(DATA2));
+  writer->WriteEntityHeader(mKey3, sizeof(DATA3));
+  writer->WriteEntityData(DATA3, sizeof(DATA3));
+
+  ::close(fd);
+  fd = ::open(m_filename, O_RDONLY);
+  BackupDataReader* reader = new BackupDataReader(fd);
+
+  bool done;
+  int type;
+  String8 key;
+  size_t dataSize;
+  char* dataBytes;
+  // read first entity
+  reader->ReadNextHeader(&done, &type);
+  reader->ReadEntityHeader(&key, &dataSize);
+  dataBytes = new char[dataSize];
+  reader->ReadEntityData(dataBytes, dataSize);
+  delete dataBytes;
+
+  // skip second entity
+  reader->ReadNextHeader(&done, &type);
+  reader->ReadEntityHeader(&key, &dataSize);
+  reader->SkipEntityData();
+
+  // read and verify third entity
+  reader->ReadNextHeader(&done, &type);
+  EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+          << "wrong type from ReadNextHeader after skip";
+
+  EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+          << "ReadEntityHeader returned an error on third entity";
+  EXPECT_EQ(mKey3, key)
+          << "wrong key from ReadEntityHeader on third entity";
+  EXPECT_EQ(sizeof(DATA3), dataSize)
+          << "wrong size from ReadEntityHeader on third entity";
+
+  dataBytes = new char[dataSize];
+  EXPECT_EQ((int) dataSize, reader->ReadEntityData(dataBytes, dataSize))
+          << "ReadEntityData returned an error on third entity";
+  for (unsigned int i = 0; i < sizeof(DATA3); i++) {
+    EXPECT_EQ(DATA3[i], dataBytes[i])
+             << "data character " << i << " should be equal";
+  }
+  delete dataBytes;
+  delete writer;
+  delete reader;
+}
+
+TEST_F(BackupDataTest, DeleteEntity) {
+  int fd = ::open(m_filename, O_WRONLY);
+  BackupDataWriter* writer = new BackupDataWriter(fd);
+  writer->WriteEntityHeader(mKey1, sizeof(DATA1));
+  writer->WriteEntityData(DATA1, sizeof(DATA1));
+  writer->WriteEntityHeader(mKey2, -1);
+
+  ::close(fd);
+  fd = ::open(m_filename, O_RDONLY);
+  BackupDataReader* reader = new BackupDataReader(fd);
+
+  bool done;
+  int type;
+  String8 key;
+  size_t dataSize;
+  char* dataBytes;
+  // read first entity
+  reader->ReadNextHeader(&done, &type);
+  reader->ReadEntityHeader(&key, &dataSize);
+  dataBytes = new char[dataSize];
+  reader->ReadEntityData(dataBytes, dataSize);
+  delete dataBytes;
+
+  // read and verify deletion
+  reader->ReadNextHeader(&done, &type);
+  EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+          << "wrong type from ReadNextHeader on deletion";
+
+  EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+          << "ReadEntityHeader returned an error on second entity";
+  EXPECT_EQ(mKey2, key)
+          << "wrong key from ReadEntityHeader on second entity";
+  EXPECT_EQ(-1, (int) dataSize)
+          << "not recognizing deletion on second entity";
+
+  delete writer;
+  delete reader;
+}
+
+TEST_F(BackupDataTest, EneityAfterDelete) {
+  int fd = ::open(m_filename, O_WRONLY);
+  BackupDataWriter* writer = new BackupDataWriter(fd);
+  writer->WriteEntityHeader(mKey1, sizeof(DATA1));
+  writer->WriteEntityData(DATA1, sizeof(DATA1));
+  writer->WriteEntityHeader(mKey2, -1);
+  writer->WriteEntityHeader(mKey3, sizeof(DATA3));
+  writer->WriteEntityData(DATA3, sizeof(DATA3));
+
+  ::close(fd);
+  fd = ::open(m_filename, O_RDONLY);
+  BackupDataReader* reader = new BackupDataReader(fd);
+
+  bool done;
+  int type;
+  String8 key;
+  size_t dataSize;
+  char* dataBytes;
+  // read first entity
+  reader->ReadNextHeader(&done, &type);
+  reader->ReadEntityHeader(&key, &dataSize);
+  dataBytes = new char[dataSize];
+  reader->ReadEntityData(dataBytes, dataSize);
+  delete dataBytes;
+
+  // read and verify deletion
+  reader->ReadNextHeader(&done, &type);
+  EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+          << "wrong type from ReadNextHeader on deletion";
+
+  EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+          << "ReadEntityHeader returned an error on second entity";
+  EXPECT_EQ(mKey2, key)
+          << "wrong key from ReadEntityHeader on second entity";
+  EXPECT_EQ(-1, (int)dataSize)
+          << "not recognizing deletion on second entity";
+
+  // read and verify third entity
+  reader->ReadNextHeader(&done, &type);
+  EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+          << "wrong type from ReadNextHeader after deletion";
+
+  EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+          << "ReadEntityHeader returned an error on third entity";
+  EXPECT_EQ(mKey3, key)
+          << "wrong key from ReadEntityHeader on third entity";
+  EXPECT_EQ(sizeof(DATA3), dataSize)
+          << "wrong size from ReadEntityHeader on third entity";
+
+  dataBytes = new char[dataSize];
+  EXPECT_EQ((int) dataSize, reader->ReadEntityData(dataBytes, dataSize))
+          << "ReadEntityData returned an error on third entity";
+  for (unsigned int i = 0; i < sizeof(DATA3); i++) {
+    EXPECT_EQ(DATA3[i], dataBytes[i])
+             << "data character " << i << " should be equal";
+  }
+  delete dataBytes;
+  delete writer;
+  delete reader;
+}
+
+TEST_F(BackupDataTest, OnlyDeleteEntities) {
+  int fd = ::open(m_filename, O_WRONLY);
+  BackupDataWriter* writer = new BackupDataWriter(fd);
+  writer->WriteEntityHeader(mKey1, -1);
+  writer->WriteEntityHeader(mKey2, -1);
+  writer->WriteEntityHeader(mKey3, -1);
+  writer->WriteEntityHeader(mKey4, -1);
+
+  ::close(fd);
+  fd = ::open(m_filename, O_RDONLY);
+  BackupDataReader* reader = new BackupDataReader(fd);
+
+  bool done;
+  int type;
+  String8 key;
+  size_t dataSize;
+  // read and verify first deletion
+  reader->ReadNextHeader(&done, &type);
+  EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+          << "wrong type from ReadNextHeader first deletion";
+
+  EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+          << "ReadEntityHeader returned an error on first entity";
+  EXPECT_EQ(mKey1, key)
+          << "wrong key from ReadEntityHeader on first entity";
+  EXPECT_EQ(-1, (int) dataSize)
+          << "not recognizing deletion on first entity";
+
+  // read and verify second deletion
+  reader->ReadNextHeader(&done, &type);
+  EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+          << "wrong type from ReadNextHeader second deletion";
+
+  EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+          << "ReadEntityHeader returned an error on second entity";
+  EXPECT_EQ(mKey2, key)
+          << "wrong key from ReadEntityHeader on second entity";
+  EXPECT_EQ(-1, (int) dataSize)
+          << "not recognizing deletion on second entity";
+
+  // read and verify third deletion
+  reader->ReadNextHeader(&done, &type);
+  EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+          << "wrong type from ReadNextHeader third deletion";
+
+  EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+          << "ReadEntityHeader returned an error on third entity";
+  EXPECT_EQ(mKey3, key)
+          << "wrong key from ReadEntityHeader on third entity";
+  EXPECT_EQ(-1, (int) dataSize)
+          << "not recognizing deletion on third entity";
+
+  // read and verify fourth deletion
+  reader->ReadNextHeader(&done, &type);
+  EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+          << "wrong type from ReadNextHeader fourth deletion";
+
+  EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+          << "ReadEntityHeader returned an error on fourth entity";
+  EXPECT_EQ(mKey4, key)
+          << "wrong key from ReadEntityHeader on fourth entity";
+  EXPECT_EQ(-1, (int) dataSize)
+          << "not recognizing deletion on fourth entity";
+
+  delete writer;
+  delete reader;
+}
+
+TEST_F(BackupDataTest, ReadDeletedEntityData) {
+  int fd = ::open(m_filename, O_WRONLY);
+  BackupDataWriter* writer = new BackupDataWriter(fd);
+  writer->WriteEntityHeader(mKey1, -1);
+  writer->WriteEntityHeader(mKey2, -1);
+
+  ::close(fd);
+  fd = ::open(m_filename, O_RDONLY);
+  BackupDataReader* reader = new BackupDataReader(fd);
+
+  bool done;
+  int type;
+  String8 key;
+  size_t dataSize;
+  // read and verify first deletion
+  reader->ReadNextHeader(&done, &type);
+  EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+          << "wrong type from ReadNextHeader first deletion";
+
+  EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+          << "ReadEntityHeader returned an error on first entity";
+  EXPECT_EQ(mKey1, key)
+          << "wrong key from ReadEntityHeader on first entity";
+  EXPECT_EQ(-1, (int) dataSize)
+          << "not recognizing deletion on first entity";
+
+  // erroneously try to read first entity data
+  char* dataBytes = new char[10];
+  dataBytes[0] = 'A';
+  EXPECT_EQ(NO_ERROR, reader->ReadEntityData(dataBytes, dataSize));
+  // expect dataBytes to be unmodofied
+  EXPECT_EQ('A', dataBytes[0]);
+
+  // read and verify second deletion
+  reader->ReadNextHeader(&done, &type);
+  EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+          << "wrong type from ReadNextHeader second deletion";
+
+  EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+          << "ReadEntityHeader returned an error on second entity";
+  EXPECT_EQ(mKey2, key)
+          << "wrong key from ReadEntityHeader on second entity";
+  EXPECT_EQ(-1, (int) dataSize)
+          << "not recognizing deletion on second entity";
+
+  delete writer;
+  delete reader;
+}
+
+}
diff --git a/libs/androidfw/tests/ObbFile_test.cpp b/libs/androidfw/tests/ObbFile_test.cpp
new file mode 100644
index 0000000..2c9f650
--- /dev/null
+++ b/libs/androidfw/tests/ObbFile_test.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ObbFile_test"
+#include <androidfw/ObbFile.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+#include <gtest/gtest.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+
+namespace android {
+
+#define TEST_FILENAME "/test.obb"
+
+class ObbFileTest : public testing::Test {
+protected:
+    sp<ObbFile> mObbFile;
+    char* mExternalStorage;
+    char* mFileName;
+
+    virtual void SetUp() {
+        mObbFile = new ObbFile();
+        mExternalStorage = getenv("EXTERNAL_STORAGE");
+
+        const int totalLen = strlen(mExternalStorage) + strlen(TEST_FILENAME) + 1;
+        mFileName = new char[totalLen];
+        snprintf(mFileName, totalLen, "%s%s", mExternalStorage, TEST_FILENAME);
+
+        int fd = ::open(mFileName, O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+        if (fd < 0) {
+            FAIL() << "Couldn't create " << mFileName << " for tests";
+        }
+    }
+
+    virtual void TearDown() {
+    }
+};
+
+TEST_F(ObbFileTest, ReadFailure) {
+    EXPECT_FALSE(mObbFile->readFrom(-1))
+            << "No failure on invalid file descriptor";
+}
+
+TEST_F(ObbFileTest, WriteThenRead) {
+    const char* packageName = "com.example.obbfile";
+    const int32_t versionNum = 1;
+
+    mObbFile->setPackageName(String8(packageName));
+    mObbFile->setVersion(versionNum);
+#define SALT_SIZE 8
+    unsigned char salt[SALT_SIZE] = {0x01, 0x10, 0x55, 0xAA, 0xFF, 0x00, 0x5A, 0xA5};
+    EXPECT_TRUE(mObbFile->setSalt(salt, SALT_SIZE))
+            << "Salt should be successfully set";
+
+    EXPECT_TRUE(mObbFile->writeTo(mFileName))
+            << "couldn't write to fake .obb file";
+
+    mObbFile = new ObbFile();
+
+    EXPECT_TRUE(mObbFile->readFrom(mFileName))
+            << "couldn't read from fake .obb file";
+
+    EXPECT_EQ(versionNum, mObbFile->getVersion())
+            << "version didn't come out the same as it went in";
+    const char* currentPackageName = mObbFile->getPackageName().string();
+    EXPECT_STREQ(packageName, currentPackageName)
+            << "package name didn't come out the same as it went in";
+
+    size_t saltLen;
+    const unsigned char* newSalt = mObbFile->getSalt(&saltLen);
+
+    EXPECT_EQ(sizeof(salt), saltLen)
+            << "salt sizes were not the same";
+
+    for (int i = 0; i < sizeof(salt); i++) {
+        EXPECT_EQ(salt[i], newSalt[i])
+                << "salt character " << i << " should be equal";
+    }
+    EXPECT_TRUE(memcmp(newSalt, salt, sizeof(salt)) == 0)
+            << "salts should be the same";
+}
+
+}
diff --git a/libs/androidfw/tests/ZipFileRO_test.cpp b/libs/androidfw/tests/ZipFileRO_test.cpp
new file mode 100644
index 0000000..cb9c721
--- /dev/null
+++ b/libs/androidfw/tests/ZipFileRO_test.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ZipFileRO_test"
+#include <utils/Log.h>
+#include <androidfw/ZipFileRO.h>
+
+#include <gtest/gtest.h>
+
+#include <fcntl.h>
+#include <string.h>
+
+namespace android {
+
+class ZipFileROTest : public testing::Test {
+protected:
+    virtual void SetUp() {
+    }
+
+    virtual void TearDown() {
+    }
+};
+
+TEST_F(ZipFileROTest, ZipTimeConvertSuccess) {
+    struct tm t;
+
+    // 2011-06-29 14:40:40
+    long when = 0x3EDD7514;
+
+    ZipFileRO::zipTimeToTimespec(when, &t);
+
+    EXPECT_EQ(2011, t.tm_year + 1900)
+            << "Year was improperly converted.";
+
+    EXPECT_EQ(6, t.tm_mon)
+            << "Month was improperly converted.";
+
+    EXPECT_EQ(29, t.tm_mday)
+            << "Day was improperly converted.";
+
+    EXPECT_EQ(14, t.tm_hour)
+            << "Hour was improperly converted.";
+
+    EXPECT_EQ(40, t.tm_min)
+            << "Minute was improperly converted.";
+
+    EXPECT_EQ(40, t.tm_sec)
+            << "Second was improperly converted.";
+}
+
+}