summaryrefslogtreecommitdiffstats
path: root/tests/unit
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit')
-rw-r--r--tests/unit/asn1_decoder_test.cpp397
-rw-r--r--tests/unit/dirutil_test.cpp150
-rw-r--r--tests/unit/locale_test.cpp18
-rw-r--r--tests/unit/recovery_test.cpp92
-rw-r--r--tests/unit/sysutil_test.cpp140
-rw-r--r--tests/unit/zip_test.cpp90
-rw-r--r--tests/unit/ziputil_test.cpp191
7 files changed, 762 insertions, 316 deletions
diff --git a/tests/unit/asn1_decoder_test.cpp b/tests/unit/asn1_decoder_test.cpp
index af96d87d2..b334a655b 100644
--- a/tests/unit/asn1_decoder_test.cpp
+++ b/tests/unit/asn1_decoder_test.cpp
@@ -14,225 +14,188 @@
* limitations under the License.
*/
-#define LOG_TAG "asn1_decoder_test"
+#include <stdint.h>
+
+#include <memory>
-#include <cutils/log.h>
#include <gtest/gtest.h>
-#include <stdint.h>
-#include <unistd.h>
#include "asn1_decoder.h"
-namespace android {
-
-class Asn1DecoderTest : public testing::Test {
-};
-
-TEST_F(Asn1DecoderTest, Empty_Failure) {
- uint8_t empty[] = { };
- asn1_context_t* ctx = asn1_context_new(empty, sizeof(empty));
-
- EXPECT_EQ(NULL, asn1_constructed_get(ctx));
- EXPECT_FALSE(asn1_constructed_skip_all(ctx));
- EXPECT_EQ(0, asn1_constructed_type(ctx));
- EXPECT_EQ(NULL, asn1_sequence_get(ctx));
- EXPECT_EQ(NULL, asn1_set_get(ctx));
- EXPECT_FALSE(asn1_sequence_next(ctx));
-
- uint8_t* junk;
- size_t length;
- EXPECT_FALSE(asn1_oid_get(ctx, &junk, &length));
- EXPECT_FALSE(asn1_octet_string_get(ctx, &junk, &length));
-
- asn1_context_free(ctx);
-}
-
-TEST_F(Asn1DecoderTest, ConstructedGet_TruncatedLength_Failure) {
- uint8_t truncated[] = { 0xA0, 0x82, };
- asn1_context_t* ctx = asn1_context_new(truncated, sizeof(truncated));
- EXPECT_EQ(NULL, asn1_constructed_get(ctx));
- asn1_context_free(ctx);
-}
-
-TEST_F(Asn1DecoderTest, ConstructedGet_LengthTooBig_Failure) {
- uint8_t truncated[] = { 0xA0, 0x8a, 0xA5, 0x5A, 0xA5, 0x5A,
- 0xA5, 0x5A, 0xA5, 0x5A, 0xA5, 0x5A, };
- asn1_context_t* ctx = asn1_context_new(truncated, sizeof(truncated));
- EXPECT_EQ(NULL, asn1_constructed_get(ctx));
- asn1_context_free(ctx);
-}
-
-TEST_F(Asn1DecoderTest, ConstructedGet_TooSmallForChild_Failure) {
- uint8_t data[] = { 0xA5, 0x02, 0x06, 0x01, 0x01, };
- asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
- asn1_context_t* ptr = asn1_constructed_get(ctx);
- ASSERT_NE((asn1_context_t*)NULL, ptr);
- EXPECT_EQ(5, asn1_constructed_type(ptr));
- uint8_t* oid;
- size_t length;
- EXPECT_FALSE(asn1_oid_get(ptr, &oid, &length));
- asn1_context_free(ptr);
- asn1_context_free(ctx);
-}
-
-TEST_F(Asn1DecoderTest, ConstructedGet_Success) {
- uint8_t data[] = { 0xA5, 0x03, 0x06, 0x01, 0x01, };
- asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
- asn1_context_t* ptr = asn1_constructed_get(ctx);
- ASSERT_NE((asn1_context_t*)NULL, ptr);
- EXPECT_EQ(5, asn1_constructed_type(ptr));
- uint8_t* oid;
- size_t length;
- ASSERT_TRUE(asn1_oid_get(ptr, &oid, &length));
- EXPECT_EQ(1U, length);
- EXPECT_EQ(0x01U, *oid);
- asn1_context_free(ptr);
- asn1_context_free(ctx);
-}
-
-TEST_F(Asn1DecoderTest, ConstructedSkipAll_TruncatedLength_Failure) {
- uint8_t truncated[] = { 0xA2, 0x82, };
- asn1_context_t* ctx = asn1_context_new(truncated, sizeof(truncated));
- EXPECT_FALSE(asn1_constructed_skip_all(ctx));
- asn1_context_free(ctx);
-}
-
-TEST_F(Asn1DecoderTest, ConstructedSkipAll_Success) {
- uint8_t data[] = { 0xA0, 0x03, 0x02, 0x01, 0x01,
- 0xA1, 0x03, 0x02, 0x01, 0x01,
- 0x06, 0x01, 0xA5, };
- asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
- ASSERT_TRUE(asn1_constructed_skip_all(ctx));
- uint8_t* oid;
- size_t length;
- ASSERT_TRUE(asn1_oid_get(ctx, &oid, &length));
- EXPECT_EQ(1U, length);
- EXPECT_EQ(0xA5U, *oid);
- asn1_context_free(ctx);
-}
-
-TEST_F(Asn1DecoderTest, SequenceGet_TruncatedLength_Failure) {
- uint8_t truncated[] = { 0x30, 0x82, };
- asn1_context_t* ctx = asn1_context_new(truncated, sizeof(truncated));
- EXPECT_EQ(NULL, asn1_sequence_get(ctx));
- asn1_context_free(ctx);
-}
-
-TEST_F(Asn1DecoderTest, SequenceGet_TooSmallForChild_Failure) {
- uint8_t data[] = { 0x30, 0x02, 0x06, 0x01, 0x01, };
- asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
- asn1_context_t* ptr = asn1_sequence_get(ctx);
- ASSERT_NE((asn1_context_t*)NULL, ptr);
- uint8_t* oid;
- size_t length;
- EXPECT_FALSE(asn1_oid_get(ptr, &oid, &length));
- asn1_context_free(ptr);
- asn1_context_free(ctx);
-}
-
-TEST_F(Asn1DecoderTest, SequenceGet_Success) {
- uint8_t data[] = { 0x30, 0x03, 0x06, 0x01, 0x01, };
- asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
- asn1_context_t* ptr = asn1_sequence_get(ctx);
- ASSERT_NE((asn1_context_t*)NULL, ptr);
- uint8_t* oid;
- size_t length;
- ASSERT_TRUE(asn1_oid_get(ptr, &oid, &length));
- EXPECT_EQ(1U, length);
- EXPECT_EQ(0x01U, *oid);
- asn1_context_free(ptr);
- asn1_context_free(ctx);
-}
-
-TEST_F(Asn1DecoderTest, SetGet_TruncatedLength_Failure) {
- uint8_t truncated[] = { 0x31, 0x82, };
- asn1_context_t* ctx = asn1_context_new(truncated, sizeof(truncated));
- EXPECT_EQ(NULL, asn1_set_get(ctx));
- asn1_context_free(ctx);
-}
-
-TEST_F(Asn1DecoderTest, SetGet_TooSmallForChild_Failure) {
- uint8_t data[] = { 0x31, 0x02, 0x06, 0x01, 0x01, };
- asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
- asn1_context_t* ptr = asn1_set_get(ctx);
- ASSERT_NE((asn1_context_t*)NULL, ptr);
- uint8_t* oid;
- size_t length;
- EXPECT_FALSE(asn1_oid_get(ptr, &oid, &length));
- asn1_context_free(ptr);
- asn1_context_free(ctx);
-}
-
-TEST_F(Asn1DecoderTest, SetGet_Success) {
- uint8_t data[] = { 0x31, 0x03, 0x06, 0x01, 0xBA, };
- asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
- asn1_context_t* ptr = asn1_set_get(ctx);
- ASSERT_NE((asn1_context_t*)NULL, ptr);
- uint8_t* oid;
- size_t length;
- ASSERT_TRUE(asn1_oid_get(ptr, &oid, &length));
- EXPECT_EQ(1U, length);
- EXPECT_EQ(0xBAU, *oid);
- asn1_context_free(ptr);
- asn1_context_free(ctx);
-}
-
-TEST_F(Asn1DecoderTest, OidGet_LengthZero_Failure) {
- uint8_t data[] = { 0x06, 0x00, 0x01, };
- asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
- uint8_t* oid;
- size_t length;
- EXPECT_FALSE(asn1_oid_get(ctx, &oid, &length));
- asn1_context_free(ctx);
-}
-
-TEST_F(Asn1DecoderTest, OidGet_TooSmall_Failure) {
- uint8_t data[] = { 0x06, 0x01, };
- asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
- uint8_t* oid;
- size_t length;
- EXPECT_FALSE(asn1_oid_get(ctx, &oid, &length));
- asn1_context_free(ctx);
-}
-
-TEST_F(Asn1DecoderTest, OidGet_Success) {
- uint8_t data[] = { 0x06, 0x01, 0x99, };
- asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
- uint8_t* oid;
- size_t length;
- ASSERT_TRUE(asn1_oid_get(ctx, &oid, &length));
- EXPECT_EQ(1U, length);
- EXPECT_EQ(0x99U, *oid);
- asn1_context_free(ctx);
-}
-
-TEST_F(Asn1DecoderTest, OctetStringGet_LengthZero_Failure) {
- uint8_t data[] = { 0x04, 0x00, 0x55, };
- asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
- uint8_t* string;
- size_t length;
- ASSERT_FALSE(asn1_octet_string_get(ctx, &string, &length));
- asn1_context_free(ctx);
-}
-
-TEST_F(Asn1DecoderTest, OctetStringGet_TooSmall_Failure) {
- uint8_t data[] = { 0x04, 0x01, };
- asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
- uint8_t* string;
- size_t length;
- ASSERT_FALSE(asn1_octet_string_get(ctx, &string, &length));
- asn1_context_free(ctx);
-}
-
-TEST_F(Asn1DecoderTest, OctetStringGet_Success) {
- uint8_t data[] = { 0x04, 0x01, 0xAA, };
- asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
- uint8_t* string;
- size_t length;
- ASSERT_TRUE(asn1_octet_string_get(ctx, &string, &length));
- EXPECT_EQ(1U, length);
- EXPECT_EQ(0xAAU, *string);
- asn1_context_free(ctx);
-}
-
-} // namespace android
+TEST(Asn1DecoderTest, Empty_Failure) {
+ uint8_t empty[] = {};
+ asn1_context ctx(empty, sizeof(empty));
+
+ ASSERT_EQ(nullptr, ctx.asn1_constructed_get());
+ ASSERT_FALSE(ctx.asn1_constructed_skip_all());
+ ASSERT_EQ(0, ctx.asn1_constructed_type());
+ ASSERT_EQ(nullptr, ctx.asn1_sequence_get());
+ ASSERT_EQ(nullptr, ctx.asn1_set_get());
+ ASSERT_FALSE(ctx.asn1_sequence_next());
+
+ const uint8_t* junk;
+ size_t length;
+ ASSERT_FALSE(ctx.asn1_oid_get(&junk, &length));
+ ASSERT_FALSE(ctx.asn1_octet_string_get(&junk, &length));
+}
+
+TEST(Asn1DecoderTest, ConstructedGet_TruncatedLength_Failure) {
+ uint8_t truncated[] = { 0xA0, 0x82 };
+ asn1_context ctx(truncated, sizeof(truncated));
+ ASSERT_EQ(nullptr, ctx.asn1_constructed_get());
+}
+
+TEST(Asn1DecoderTest, ConstructedGet_LengthTooBig_Failure) {
+ uint8_t truncated[] = { 0xA0, 0x8a, 0xA5, 0x5A, 0xA5, 0x5A, 0xA5, 0x5A, 0xA5, 0x5A, 0xA5, 0x5A };
+ asn1_context ctx(truncated, sizeof(truncated));
+ ASSERT_EQ(nullptr, ctx.asn1_constructed_get());
+}
+
+TEST(Asn1DecoderTest, ConstructedGet_TooSmallForChild_Failure) {
+ uint8_t data[] = { 0xA5, 0x02, 0x06, 0x01, 0x01 };
+ asn1_context ctx(data, sizeof(data));
+ std::unique_ptr<asn1_context> ptr(ctx.asn1_constructed_get());
+ ASSERT_NE(nullptr, ptr);
+ ASSERT_EQ(5, ptr->asn1_constructed_type());
+ const uint8_t* oid;
+ size_t length;
+ ASSERT_FALSE(ptr->asn1_oid_get(&oid, &length));
+}
+
+TEST(Asn1DecoderTest, ConstructedGet_Success) {
+ uint8_t data[] = { 0xA5, 0x03, 0x06, 0x01, 0x01 };
+ asn1_context ctx(data, sizeof(data));
+ std::unique_ptr<asn1_context> ptr(ctx.asn1_constructed_get());
+ ASSERT_NE(nullptr, ptr);
+ ASSERT_EQ(5, ptr->asn1_constructed_type());
+ const uint8_t* oid;
+ size_t length;
+ ASSERT_TRUE(ptr->asn1_oid_get(&oid, &length));
+ ASSERT_EQ(1U, length);
+ ASSERT_EQ(0x01U, *oid);
+}
+
+TEST(Asn1DecoderTest, ConstructedSkipAll_TruncatedLength_Failure) {
+ uint8_t truncated[] = { 0xA2, 0x82 };
+ asn1_context ctx(truncated, sizeof(truncated));
+ ASSERT_FALSE(ctx.asn1_constructed_skip_all());
+}
+
+TEST(Asn1DecoderTest, ConstructedSkipAll_Success) {
+ uint8_t data[] = { 0xA0, 0x03, 0x02, 0x01, 0x01, 0xA1, 0x03, 0x02, 0x01, 0x01, 0x06, 0x01, 0xA5 };
+ asn1_context ctx(data, sizeof(data));
+ ASSERT_TRUE(ctx.asn1_constructed_skip_all());
+ const uint8_t* oid;
+ size_t length;
+ ASSERT_TRUE(ctx.asn1_oid_get(&oid, &length));
+ ASSERT_EQ(1U, length);
+ ASSERT_EQ(0xA5U, *oid);
+}
+
+TEST(Asn1DecoderTest, SequenceGet_TruncatedLength_Failure) {
+ uint8_t truncated[] = { 0x30, 0x82 };
+ asn1_context ctx(truncated, sizeof(truncated));
+ ASSERT_EQ(nullptr, ctx.asn1_sequence_get());
+}
+
+TEST(Asn1DecoderTest, SequenceGet_TooSmallForChild_Failure) {
+ uint8_t data[] = { 0x30, 0x02, 0x06, 0x01, 0x01 };
+ asn1_context ctx(data, sizeof(data));
+ std::unique_ptr<asn1_context> ptr(ctx.asn1_sequence_get());
+ ASSERT_NE(nullptr, ptr);
+ const uint8_t* oid;
+ size_t length;
+ ASSERT_FALSE(ptr->asn1_oid_get(&oid, &length));
+}
+
+TEST(Asn1DecoderTest, SequenceGet_Success) {
+ uint8_t data[] = { 0x30, 0x03, 0x06, 0x01, 0x01 };
+ asn1_context ctx(data, sizeof(data));
+ std::unique_ptr<asn1_context> ptr(ctx.asn1_sequence_get());
+ ASSERT_NE(nullptr, ptr);
+ const uint8_t* oid;
+ size_t length;
+ ASSERT_TRUE(ptr->asn1_oid_get(&oid, &length));
+ ASSERT_EQ(1U, length);
+ ASSERT_EQ(0x01U, *oid);
+}
+
+TEST(Asn1DecoderTest, SetGet_TruncatedLength_Failure) {
+ uint8_t truncated[] = { 0x31, 0x82 };
+ asn1_context ctx(truncated, sizeof(truncated));
+ ASSERT_EQ(nullptr, ctx.asn1_set_get());
+}
+
+TEST(Asn1DecoderTest, SetGet_TooSmallForChild_Failure) {
+ uint8_t data[] = { 0x31, 0x02, 0x06, 0x01, 0x01 };
+ asn1_context ctx(data, sizeof(data));
+ std::unique_ptr<asn1_context> ptr(ctx.asn1_set_get());
+ ASSERT_NE(nullptr, ptr);
+ const uint8_t* oid;
+ size_t length;
+ ASSERT_FALSE(ptr->asn1_oid_get(&oid, &length));
+}
+
+TEST(Asn1DecoderTest, SetGet_Success) {
+ uint8_t data[] = { 0x31, 0x03, 0x06, 0x01, 0xBA };
+ asn1_context ctx(data, sizeof(data));
+ std::unique_ptr<asn1_context> ptr(ctx.asn1_set_get());
+ ASSERT_NE(nullptr, ptr);
+ const uint8_t* oid;
+ size_t length;
+ ASSERT_TRUE(ptr->asn1_oid_get(&oid, &length));
+ ASSERT_EQ(1U, length);
+ ASSERT_EQ(0xBAU, *oid);
+}
+
+TEST(Asn1DecoderTest, OidGet_LengthZero_Failure) {
+ uint8_t data[] = { 0x06, 0x00, 0x01 };
+ asn1_context ctx(data, sizeof(data));
+ const uint8_t* oid;
+ size_t length;
+ ASSERT_FALSE(ctx.asn1_oid_get(&oid, &length));
+}
+
+TEST(Asn1DecoderTest, OidGet_TooSmall_Failure) {
+ uint8_t data[] = { 0x06, 0x01 };
+ asn1_context ctx(data, sizeof(data));
+ const uint8_t* oid;
+ size_t length;
+ ASSERT_FALSE(ctx.asn1_oid_get(&oid, &length));
+}
+
+TEST(Asn1DecoderTest, OidGet_Success) {
+ uint8_t data[] = { 0x06, 0x01, 0x99 };
+ asn1_context ctx(data, sizeof(data));
+ const uint8_t* oid;
+ size_t length;
+ ASSERT_TRUE(ctx.asn1_oid_get(&oid, &length));
+ ASSERT_EQ(1U, length);
+ ASSERT_EQ(0x99U, *oid);
+}
+
+TEST(Asn1DecoderTest, OctetStringGet_LengthZero_Failure) {
+ uint8_t data[] = { 0x04, 0x00, 0x55 };
+ asn1_context ctx(data, sizeof(data));
+ const uint8_t* string;
+ size_t length;
+ ASSERT_FALSE(ctx.asn1_octet_string_get(&string, &length));
+}
+
+TEST(Asn1DecoderTest, OctetStringGet_TooSmall_Failure) {
+ uint8_t data[] = { 0x04, 0x01 };
+ asn1_context ctx(data, sizeof(data));
+ const uint8_t* string;
+ size_t length;
+ ASSERT_FALSE(ctx.asn1_octet_string_get(&string, &length));
+}
+
+TEST(Asn1DecoderTest, OctetStringGet_Success) {
+ uint8_t data[] = { 0x04, 0x01, 0xAA };
+ asn1_context ctx(data, sizeof(data));
+ const uint8_t* string;
+ size_t length;
+ ASSERT_TRUE(ctx.asn1_octet_string_get(&string, &length));
+ ASSERT_EQ(1U, length);
+ ASSERT_EQ(0xAAU, *string);
+}
diff --git a/tests/unit/dirutil_test.cpp b/tests/unit/dirutil_test.cpp
new file mode 100644
index 000000000..5e2ae4fb5
--- /dev/null
+++ b/tests/unit/dirutil_test.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <android-base/test_utils.h>
+#include <gtest/gtest.h>
+#include <otautil/DirUtil.h>
+
+TEST(DirUtilTest, create_invalid) {
+ // Requesting to create an empty dir is invalid.
+ ASSERT_EQ(-1, dirCreateHierarchy("", 0755, nullptr, false, nullptr));
+ ASSERT_EQ(ENOENT, errno);
+
+ // Requesting to strip the name with no slash present.
+ ASSERT_EQ(-1, dirCreateHierarchy("abc", 0755, nullptr, true, nullptr));
+ ASSERT_EQ(ENOENT, errno);
+
+ // Creating a dir that already exists.
+ TemporaryDir td;
+ ASSERT_EQ(0, dirCreateHierarchy(td.path, 0755, nullptr, false, nullptr));
+
+ // "///" is a valid dir.
+ ASSERT_EQ(0, dirCreateHierarchy("///", 0755, nullptr, false, nullptr));
+
+ // Request to create a dir, but a file with the same name already exists.
+ TemporaryFile tf;
+ ASSERT_EQ(-1, dirCreateHierarchy(tf.path, 0755, nullptr, false, nullptr));
+ ASSERT_EQ(ENOTDIR, errno);
+}
+
+TEST(DirUtilTest, create_smoke) {
+ TemporaryDir td;
+ std::string prefix(td.path);
+ std::string path = prefix + "/a/b";
+ constexpr mode_t mode = 0755;
+ ASSERT_EQ(0, dirCreateHierarchy(path.c_str(), mode, nullptr, false, nullptr));
+
+ // Verify.
+ struct stat sb;
+ ASSERT_EQ(0, stat(path.c_str(), &sb)) << strerror(errno);
+ ASSERT_TRUE(S_ISDIR(sb.st_mode));
+ constexpr mode_t mask = S_IRWXU | S_IRWXG | S_IRWXO;
+ ASSERT_EQ(mode, sb.st_mode & mask);
+
+ // Clean up.
+ ASSERT_EQ(0, rmdir((prefix + "/a/b").c_str()));
+ ASSERT_EQ(0, rmdir((prefix + "/a").c_str()));
+}
+
+TEST(DirUtilTest, create_strip_filename) {
+ TemporaryDir td;
+ std::string prefix(td.path);
+ std::string path = prefix + "/a/b";
+ ASSERT_EQ(0, dirCreateHierarchy(path.c_str(), 0755, nullptr, true, nullptr));
+
+ // Verify that "../a" exists but not "../a/b".
+ struct stat sb;
+ ASSERT_EQ(0, stat((prefix + "/a").c_str(), &sb)) << strerror(errno);
+ ASSERT_TRUE(S_ISDIR(sb.st_mode));
+
+ ASSERT_EQ(-1, stat(path.c_str(), &sb));
+ ASSERT_EQ(ENOENT, errno);
+
+ // Clean up.
+ ASSERT_EQ(0, rmdir((prefix + "/a").c_str()));
+}
+
+TEST(DirUtilTest, create_mode_and_timestamp) {
+ TemporaryDir td;
+ std::string prefix(td.path);
+ std::string path = prefix + "/a/b";
+ // Set the timestamp to 8/1/2008.
+ constexpr struct utimbuf timestamp = { 1217592000, 1217592000 };
+ constexpr mode_t mode = 0751;
+ ASSERT_EQ(0, dirCreateHierarchy(path.c_str(), mode, &timestamp, false, nullptr));
+
+ // Verify the mode and timestamp for "../a/b".
+ struct stat sb;
+ ASSERT_EQ(0, stat(path.c_str(), &sb)) << strerror(errno);
+ ASSERT_TRUE(S_ISDIR(sb.st_mode));
+ constexpr mode_t mask = S_IRWXU | S_IRWXG | S_IRWXO;
+ ASSERT_EQ(mode, sb.st_mode & mask);
+
+ timespec time;
+ time.tv_sec = 1217592000;
+ time.tv_nsec = 0;
+
+ ASSERT_EQ(time.tv_sec, static_cast<long>(sb.st_atime));
+ ASSERT_EQ(time.tv_sec, static_cast<long>(sb.st_mtime));
+
+ // Verify the mode for "../a". Note that the timestamp for intermediate directories (e.g. "../a")
+ // may not be 'timestamp' according to the current implementation.
+ ASSERT_EQ(0, stat((prefix + "/a").c_str(), &sb)) << strerror(errno);
+ ASSERT_TRUE(S_ISDIR(sb.st_mode));
+ ASSERT_EQ(mode, sb.st_mode & mask);
+
+ // Clean up.
+ ASSERT_EQ(0, rmdir((prefix + "/a/b").c_str()));
+ ASSERT_EQ(0, rmdir((prefix + "/a").c_str()));
+}
+
+TEST(DirUtilTest, unlink_invalid) {
+ // File doesn't exist.
+ ASSERT_EQ(-1, dirUnlinkHierarchy("doesntexist"));
+
+ // Nonexistent directory.
+ TemporaryDir td;
+ std::string path(td.path);
+ ASSERT_EQ(-1, dirUnlinkHierarchy((path + "/a").c_str()));
+ ASSERT_EQ(ENOENT, errno);
+}
+
+TEST(DirUtilTest, unlink_smoke) {
+ // Unlink a file.
+ TemporaryFile tf;
+ ASSERT_EQ(0, dirUnlinkHierarchy(tf.path));
+ ASSERT_EQ(-1, access(tf.path, F_OK));
+
+ TemporaryDir td;
+ std::string path(td.path);
+ constexpr mode_t mode = 0700;
+ ASSERT_EQ(0, mkdir((path + "/a").c_str(), mode));
+ ASSERT_EQ(0, mkdir((path + "/a/b").c_str(), mode));
+ ASSERT_EQ(0, mkdir((path + "/a/b/c").c_str(), mode));
+ ASSERT_EQ(0, mkdir((path + "/a/d").c_str(), mode));
+
+ // Remove "../a" recursively.
+ ASSERT_EQ(0, dirUnlinkHierarchy((path + "/a").c_str()));
+
+ // Verify it's gone.
+ ASSERT_EQ(-1, access((path + "/a").c_str(), F_OK));
+}
diff --git a/tests/unit/locale_test.cpp b/tests/unit/locale_test.cpp
index 0e515f8c1..cdaba0e8b 100644
--- a/tests/unit/locale_test.cpp
+++ b/tests/unit/locale_test.cpp
@@ -19,11 +19,15 @@
#include "minui/minui.h"
TEST(LocaleTest, Misc) {
- EXPECT_TRUE(matches_locale("zh_CN", "zh_CN_#Hans"));
- EXPECT_TRUE(matches_locale("zh", "zh_CN_#Hans"));
- EXPECT_FALSE(matches_locale("zh_HK", "zh_CN_#Hans"));
- EXPECT_TRUE(matches_locale("en_GB", "en_GB"));
- EXPECT_TRUE(matches_locale("en", "en_GB"));
- EXPECT_FALSE(matches_locale("en_GB", "en"));
- EXPECT_FALSE(matches_locale("en_GB", "en_US"));
+ EXPECT_TRUE(matches_locale("zh-CN", "zh-Hans-CN"));
+ EXPECT_TRUE(matches_locale("zh", "zh-Hans-CN"));
+ EXPECT_FALSE(matches_locale("zh-HK", "zh-Hans-CN"));
+ EXPECT_TRUE(matches_locale("en-GB", "en-GB"));
+ EXPECT_TRUE(matches_locale("en", "en-GB"));
+ EXPECT_FALSE(matches_locale("en-GB", "en"));
+ EXPECT_FALSE(matches_locale("en-GB", "en-US"));
+ EXPECT_FALSE(matches_locale("en-US", ""));
+ // Empty locale prefix in the PNG file will match the input locale.
+ EXPECT_TRUE(matches_locale("", "en-US"));
+ EXPECT_TRUE(matches_locale("sr-Latn", "sr-Latn-BA"));
}
diff --git a/tests/unit/recovery_test.cpp b/tests/unit/recovery_test.cpp
deleted file mode 100644
index f397f258e..000000000
--- a/tests/unit/recovery_test.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#include <fcntl.h>
-#include <string.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <android/log.h>
-#include <gtest/gtest.h>
-#include <log/logger.h>
-#include <private/android_logger.h>
-
-static const char myFilename[] = "/data/misc/recovery/inject.txt";
-static const char myContent[] = "Hello World\nWelcome to my recovery\n";
-
-// Failure is expected on systems that do not deliver either the
-// recovery-persist or recovery-refresh executables. Tests also require
-// a reboot sequence of test to truly verify.
-
-static ssize_t __pmsg_fn(log_id_t logId, char prio, const char *filename,
- const char *buf, size_t len, void *arg) {
- EXPECT_EQ(LOG_ID_SYSTEM, logId);
- EXPECT_EQ(ANDROID_LOG_INFO, prio);
- EXPECT_EQ(0, NULL == strstr(myFilename,filename));
- EXPECT_EQ(0, strcmp(myContent, buf));
- EXPECT_EQ(sizeof(myContent), len);
- EXPECT_EQ(0, NULL != arg);
- return len;
-}
-
-// recovery.refresh - May fail. Requires recovery.inject, two reboots,
-// then expect success after second reboot.
-TEST(recovery, refresh) {
- EXPECT_EQ(0, access("/system/bin/recovery-refresh", F_OK));
-
- ssize_t ret = __android_log_pmsg_file_read(
- LOG_ID_SYSTEM, ANDROID_LOG_INFO, "recovery/", __pmsg_fn, NULL);
- if (ret == -ENOENT) {
- EXPECT_LT(0, __android_log_pmsg_file_write(
- LOG_ID_SYSTEM, ANDROID_LOG_INFO,
- myFilename, myContent, sizeof(myContent)));
- fprintf(stderr, "injected test data, "
- "requires two intervening reboots "
- "to check for replication\n");
- }
- EXPECT_EQ((ssize_t)sizeof(myContent), ret);
-}
-
-// recovery.persist - Requires recovery.inject, then a reboot, then
-// expect success after for this test on that boot.
-TEST(recovery, persist) {
- EXPECT_EQ(0, access("/system/bin/recovery-persist", F_OK));
-
- ssize_t ret = __android_log_pmsg_file_read(
- LOG_ID_SYSTEM, ANDROID_LOG_INFO, "recovery/", __pmsg_fn, NULL);
- if (ret == -ENOENT) {
- EXPECT_LT(0, __android_log_pmsg_file_write(
- LOG_ID_SYSTEM, ANDROID_LOG_INFO,
- myFilename, myContent, sizeof(myContent)));
- fprintf(stderr, "injected test data, "
- "requires intervening reboot "
- "to check for storage\n");
- }
-
- int fd = open(myFilename, O_RDONLY);
- EXPECT_LE(0, fd);
-
- char buf[sizeof(myContent) + 32];
- ret = read(fd, buf, sizeof(buf));
- close(fd);
- EXPECT_EQ(ret, (ssize_t)sizeof(myContent));
- EXPECT_EQ(0, strcmp(myContent, buf));
- if (fd >= 0) {
- fprintf(stderr, "Removing persistent test data, "
- "check if reconstructed on reboot\n");
- }
- EXPECT_EQ(0, unlink(myFilename));
-}
diff --git a/tests/unit/sysutil_test.cpp b/tests/unit/sysutil_test.cpp
new file mode 100644
index 000000000..f4699664b
--- /dev/null
+++ b/tests/unit/sysutil_test.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+
+#include "otautil/SysUtil.h"
+
+TEST(SysUtilTest, InvalidArgs) {
+ MemMapping mapping;
+
+ // Invalid argument.
+ ASSERT_EQ(-1, sysMapFile(nullptr, &mapping));
+ ASSERT_EQ(-1, sysMapFile("/somefile", nullptr));
+}
+
+TEST(SysUtilTest, sysMapFileRegularFile) {
+ TemporaryFile temp_file1;
+ std::string content = "abc";
+ ASSERT_TRUE(android::base::WriteStringToFile(content, temp_file1.path));
+
+ // sysMapFile() should map the file to one range.
+ MemMapping mapping;
+ ASSERT_EQ(0, sysMapFile(temp_file1.path, &mapping));
+ ASSERT_NE(nullptr, mapping.addr);
+ ASSERT_EQ(content.size(), mapping.length);
+ ASSERT_EQ(1U, mapping.ranges.size());
+
+ sysReleaseMap(&mapping);
+ ASSERT_EQ(0U, mapping.ranges.size());
+}
+
+TEST(SysUtilTest, sysMapFileBlockMap) {
+ // Create a file that has 10 blocks.
+ TemporaryFile package;
+ std::string content;
+ constexpr size_t file_size = 4096 * 10;
+ content.reserve(file_size);
+ ASSERT_TRUE(android::base::WriteStringToFile(content, package.path));
+
+ TemporaryFile block_map_file;
+ std::string filename = std::string("@") + block_map_file.path;
+ MemMapping mapping;
+
+ // One range.
+ std::string block_map_content = std::string(package.path) + "\n40960 4096\n1\n0 10\n";
+ ASSERT_TRUE(android::base::WriteStringToFile(block_map_content, block_map_file.path));
+
+ ASSERT_EQ(0, sysMapFile(filename.c_str(), &mapping));
+ ASSERT_EQ(file_size, mapping.length);
+ ASSERT_EQ(1U, mapping.ranges.size());
+
+ // It's okay to not have the trailing '\n'.
+ block_map_content = std::string(package.path) + "\n40960 4096\n1\n0 10";
+ ASSERT_TRUE(android::base::WriteStringToFile(block_map_content, block_map_file.path));
+
+ ASSERT_EQ(0, sysMapFile(filename.c_str(), &mapping));
+ ASSERT_EQ(file_size, mapping.length);
+ ASSERT_EQ(1U, mapping.ranges.size());
+
+ // Or having multiple trailing '\n's.
+ block_map_content = std::string(package.path) + "\n40960 4096\n1\n0 10\n\n\n";
+ ASSERT_TRUE(android::base::WriteStringToFile(block_map_content, block_map_file.path));
+
+ ASSERT_EQ(0, sysMapFile(filename.c_str(), &mapping));
+ ASSERT_EQ(file_size, mapping.length);
+ ASSERT_EQ(1U, mapping.ranges.size());
+
+ // Multiple ranges.
+ block_map_content = std::string(package.path) + "\n40960 4096\n3\n0 3\n3 5\n5 10\n";
+ ASSERT_TRUE(android::base::WriteStringToFile(block_map_content, block_map_file.path));
+
+ ASSERT_EQ(0, sysMapFile(filename.c_str(), &mapping));
+ ASSERT_EQ(file_size, mapping.length);
+ ASSERT_EQ(3U, mapping.ranges.size());
+
+ sysReleaseMap(&mapping);
+ ASSERT_EQ(0U, mapping.ranges.size());
+}
+
+TEST(SysUtilTest, sysMapFileBlockMapInvalidBlockMap) {
+ MemMapping mapping;
+ TemporaryFile temp_file;
+ std::string filename = std::string("@") + temp_file.path;
+
+ // Block map file is too short.
+ ASSERT_TRUE(android::base::WriteStringToFile("/somefile\n", temp_file.path));
+ ASSERT_EQ(-1, sysMapFile(filename.c_str(), &mapping));
+
+ ASSERT_TRUE(android::base::WriteStringToFile("/somefile\n4096 4096\n0\n", temp_file.path));
+ ASSERT_EQ(-1, sysMapFile(filename.c_str(), &mapping));
+
+ // Block map file has unexpected number of lines.
+ ASSERT_TRUE(android::base::WriteStringToFile("/somefile\n4096 4096\n1\n", temp_file.path));
+ ASSERT_EQ(-1, sysMapFile(filename.c_str(), &mapping));
+
+ ASSERT_TRUE(android::base::WriteStringToFile("/somefile\n4096 4096\n2\n0 1\n", temp_file.path));
+ ASSERT_EQ(-1, sysMapFile(filename.c_str(), &mapping));
+
+ // Invalid size/blksize/range_count.
+ ASSERT_TRUE(android::base::WriteStringToFile("/somefile\nabc 4096\n1\n0 1\n", temp_file.path));
+ ASSERT_EQ(-1, sysMapFile(filename.c_str(), &mapping));
+
+ ASSERT_TRUE(android::base::WriteStringToFile("/somefile\n4096 4096\n\n0 1\n", temp_file.path));
+ ASSERT_EQ(-1, sysMapFile(filename.c_str(), &mapping));
+
+ // size/blksize/range_count don't match.
+ ASSERT_TRUE(android::base::WriteStringToFile("/somefile\n0 4096\n1\n0 1\n", temp_file.path));
+ ASSERT_EQ(-1, sysMapFile(filename.c_str(), &mapping));
+
+ ASSERT_TRUE(android::base::WriteStringToFile("/somefile\n4096 0\n1\n0 1\n", temp_file.path));
+ ASSERT_EQ(-1, sysMapFile(filename.c_str(), &mapping));
+
+ ASSERT_TRUE(android::base::WriteStringToFile("/somefile\n4096 4096\n0\n0 1\n", temp_file.path));
+ ASSERT_EQ(-1, sysMapFile(filename.c_str(), &mapping));
+
+ // Invalid block dev path.
+ ASSERT_TRUE(android::base::WriteStringToFile("/doesntexist\n4096 4096\n1\n0 1\n", temp_file.path));
+ ASSERT_EQ(-1, sysMapFile(filename.c_str(), &mapping));
+
+ sysReleaseMap(&mapping);
+ ASSERT_EQ(0U, mapping.ranges.size());
+}
diff --git a/tests/unit/zip_test.cpp b/tests/unit/zip_test.cpp
new file mode 100644
index 000000000..4a1a49b97
--- /dev/null
+++ b/tests/unit/zip_test.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <memory>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+#include <gtest/gtest.h>
+#include <otautil/SysUtil.h>
+#include <otautil/ZipUtil.h>
+#include <ziparchive/zip_archive.h>
+
+#include "common/test_constants.h"
+
+TEST(ZipTest, ExtractPackageRecursive) {
+ std::string zip_path = from_testdata_base("ziptest_valid.zip");
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle));
+
+ // Extract the whole package into a temp directory.
+ TemporaryDir td;
+ ASSERT_NE(nullptr, td.path);
+ ExtractPackageRecursive(handle, "", td.path, nullptr, nullptr);
+
+ // Make sure all the files are extracted correctly.
+ std::string path(td.path);
+ ASSERT_EQ(0, access((path + "/a.txt").c_str(), F_OK));
+ ASSERT_EQ(0, access((path + "/b.txt").c_str(), F_OK));
+ ASSERT_EQ(0, access((path + "/b/c.txt").c_str(), F_OK));
+ ASSERT_EQ(0, access((path + "/b/d.txt").c_str(), F_OK));
+
+ // The content of the file is the same as expected.
+ std::string content1;
+ ASSERT_TRUE(android::base::ReadFileToString(path + "/a.txt", &content1));
+ ASSERT_EQ(kATxtContents, content1);
+
+ std::string content2;
+ ASSERT_TRUE(android::base::ReadFileToString(path + "/b/d.txt", &content2));
+ ASSERT_EQ(kDTxtContents, content2);
+
+ CloseArchive(handle);
+
+ // Clean up.
+ ASSERT_EQ(0, unlink((path + "/a.txt").c_str()));
+ ASSERT_EQ(0, unlink((path + "/b.txt").c_str()));
+ ASSERT_EQ(0, unlink((path + "/b/c.txt").c_str()));
+ ASSERT_EQ(0, unlink((path + "/b/d.txt").c_str()));
+ ASSERT_EQ(0, rmdir((path + "/b").c_str()));
+}
+
+TEST(ZipTest, OpenFromMemory) {
+ MemMapping map;
+ std::string zip_path = from_testdata_base("ziptest_dummy-update.zip");
+ ASSERT_EQ(0, sysMapFile(zip_path.c_str(), &map));
+
+ // Map an update package into memory and open the archive from there.
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_path.c_str(), &handle));
+
+ static constexpr const char* BINARY_PATH = "META-INF/com/google/android/update-binary";
+ ZipString binary_path(BINARY_PATH);
+ ZipEntry binary_entry;
+ // Make sure the package opens correctly and its entry can be read.
+ ASSERT_EQ(0, FindEntry(handle, binary_path, &binary_entry));
+
+ TemporaryFile tmp_binary;
+ ASSERT_NE(-1, tmp_binary.fd);
+ ASSERT_EQ(0, ExtractEntryToFile(handle, &binary_entry, tmp_binary.fd));
+
+ CloseArchive(handle);
+ sysReleaseMap(&map);
+}
+
diff --git a/tests/unit/ziputil_test.cpp b/tests/unit/ziputil_test.cpp
new file mode 100644
index 000000000..14e541690
--- /dev/null
+++ b/tests/unit/ziputil_test.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+#include <gtest/gtest.h>
+#include <otautil/ZipUtil.h>
+#include <ziparchive/zip_archive.h>
+
+#include "common/test_constants.h"
+
+TEST(ZipUtilTest, invalid_args) {
+ std::string zip_path = from_testdata_base("ziptest_valid.zip");
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle));
+
+ // zip_path must be a relative path.
+ ASSERT_FALSE(ExtractPackageRecursive(handle, "/a/b", "/tmp", nullptr, nullptr));
+
+ // dest_path must be an absolute path.
+ ASSERT_FALSE(ExtractPackageRecursive(handle, "a/b", "tmp", nullptr, nullptr));
+ ASSERT_FALSE(ExtractPackageRecursive(handle, "a/b", "", nullptr, nullptr));
+
+ CloseArchive(handle);
+}
+
+TEST(ZipUtilTest, extract_all) {
+ std::string zip_path = from_testdata_base("ziptest_valid.zip");
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle));
+
+ // Extract the whole package into a temp directory.
+ TemporaryDir td;
+ ExtractPackageRecursive(handle, "", td.path, nullptr, nullptr);
+
+ // Make sure all the files are extracted correctly.
+ std::string path(td.path);
+ ASSERT_EQ(0, access((path + "/a.txt").c_str(), F_OK));
+ ASSERT_EQ(0, access((path + "/b.txt").c_str(), F_OK));
+ ASSERT_EQ(0, access((path + "/b/c.txt").c_str(), F_OK));
+ ASSERT_EQ(0, access((path + "/b/d.txt").c_str(), F_OK));
+
+ // The content of the file is the same as expected.
+ std::string content1;
+ ASSERT_TRUE(android::base::ReadFileToString(path + "/a.txt", &content1));
+ ASSERT_EQ(kATxtContents, content1);
+
+ std::string content2;
+ ASSERT_TRUE(android::base::ReadFileToString(path + "/b/d.txt", &content2));
+ ASSERT_EQ(kDTxtContents, content2);
+
+ // Clean up the temp files under td.
+ ASSERT_EQ(0, unlink((path + "/a.txt").c_str()));
+ ASSERT_EQ(0, unlink((path + "/b.txt").c_str()));
+ ASSERT_EQ(0, unlink((path + "/b/c.txt").c_str()));
+ ASSERT_EQ(0, unlink((path + "/b/d.txt").c_str()));
+ ASSERT_EQ(0, rmdir((path + "/b").c_str()));
+
+ CloseArchive(handle);
+}
+
+TEST(ZipUtilTest, extract_prefix_with_slash) {
+ std::string zip_path = from_testdata_base("ziptest_valid.zip");
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle));
+
+ // Extract all the entries starting with "b/".
+ TemporaryDir td;
+ ExtractPackageRecursive(handle, "b/", td.path, nullptr, nullptr);
+
+ // Make sure all the files with "b/" prefix are extracted correctly.
+ std::string path(td.path);
+ ASSERT_EQ(0, access((path + "/c.txt").c_str(), F_OK));
+ ASSERT_EQ(0, access((path + "/d.txt").c_str(), F_OK));
+
+ // And the rest are not extracted.
+ ASSERT_EQ(-1, access((path + "/a.txt").c_str(), F_OK));
+ ASSERT_EQ(ENOENT, errno);
+ ASSERT_EQ(-1, access((path + "/b.txt").c_str(), F_OK));
+ ASSERT_EQ(ENOENT, errno);
+
+ // The content of the file is the same as expected.
+ std::string content1;
+ ASSERT_TRUE(android::base::ReadFileToString(path + "/c.txt", &content1));
+ ASSERT_EQ(kCTxtContents, content1);
+
+ std::string content2;
+ ASSERT_TRUE(android::base::ReadFileToString(path + "/d.txt", &content2));
+ ASSERT_EQ(kDTxtContents, content2);
+
+ // Clean up the temp files under td.
+ ASSERT_EQ(0, unlink((path + "/c.txt").c_str()));
+ ASSERT_EQ(0, unlink((path + "/d.txt").c_str()));
+
+ CloseArchive(handle);
+}
+
+TEST(ZipUtilTest, extract_prefix_without_slash) {
+ std::string zip_path = from_testdata_base("ziptest_valid.zip");
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle));
+
+ // Extract all the file entries starting with "b/".
+ TemporaryDir td;
+ ExtractPackageRecursive(handle, "b", td.path, nullptr, nullptr);
+
+ // Make sure all the files with "b/" prefix are extracted correctly.
+ std::string path(td.path);
+ ASSERT_EQ(0, access((path + "/c.txt").c_str(), F_OK));
+ ASSERT_EQ(0, access((path + "/d.txt").c_str(), F_OK));
+
+ // And the rest are not extracted.
+ ASSERT_EQ(-1, access((path + "/a.txt").c_str(), F_OK));
+ ASSERT_EQ(ENOENT, errno);
+ ASSERT_EQ(-1, access((path + "/b.txt").c_str(), F_OK));
+ ASSERT_EQ(ENOENT, errno);
+
+ // The content of the file is the same as expected.
+ std::string content1;
+ ASSERT_TRUE(android::base::ReadFileToString(path + "/c.txt", &content1));
+ ASSERT_EQ(kCTxtContents, content1);
+
+ std::string content2;
+ ASSERT_TRUE(android::base::ReadFileToString(path + "/d.txt", &content2));
+ ASSERT_EQ(kDTxtContents, content2);
+
+ // Clean up the temp files under td.
+ ASSERT_EQ(0, unlink((path + "/c.txt").c_str()));
+ ASSERT_EQ(0, unlink((path + "/d.txt").c_str()));
+
+ CloseArchive(handle);
+}
+
+TEST(ZipUtilTest, set_timestamp) {
+ std::string zip_path = from_testdata_base("ziptest_valid.zip");
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle));
+
+ // Set the timestamp to 8/1/2008.
+ constexpr struct utimbuf timestamp = { 1217592000, 1217592000 };
+
+ // Extract all the entries starting with "b/".
+ TemporaryDir td;
+ ExtractPackageRecursive(handle, "b", td.path, &timestamp, nullptr);
+
+ // Make sure all the files with "b/" prefix are extracted correctly.
+ std::string path(td.path);
+ std::string file_c = path + "/c.txt";
+ std::string file_d = path + "/d.txt";
+ ASSERT_EQ(0, access(file_c.c_str(), F_OK));
+ ASSERT_EQ(0, access(file_d.c_str(), F_OK));
+
+ // Verify the timestamp.
+ timespec time;
+ time.tv_sec = 1217592000;
+ time.tv_nsec = 0;
+
+ struct stat sb;
+ ASSERT_EQ(0, stat(file_c.c_str(), &sb)) << strerror(errno);
+ ASSERT_EQ(time.tv_sec, static_cast<long>(sb.st_atime));
+ ASSERT_EQ(time.tv_sec, static_cast<long>(sb.st_mtime));
+
+ ASSERT_EQ(0, stat(file_d.c_str(), &sb)) << strerror(errno);
+ ASSERT_EQ(time.tv_sec, static_cast<long>(sb.st_atime));
+ ASSERT_EQ(time.tv_sec, static_cast<long>(sb.st_mtime));
+
+ // Clean up the temp files under td.
+ ASSERT_EQ(0, unlink(file_c.c_str()));
+ ASSERT_EQ(0, unlink(file_d.c_str()));
+
+ CloseArchive(handle);
+}