Merge "applypatch: Add testcases for applypatch executable."
am: 5696526ba4
Change-Id: I923ed0311335a798965cd83f0ba070223a0963b2
This commit is contained in:
+25
-5
@@ -68,21 +68,41 @@ LOCAL_STATIC_LIBRARIES += libcrypto libbz libz
|
|||||||
LOCAL_CFLAGS := -Werror
|
LOCAL_CFLAGS := -Werror
|
||||||
include $(BUILD_HOST_STATIC_LIBRARY)
|
include $(BUILD_HOST_STATIC_LIBRARY)
|
||||||
|
|
||||||
# applypatch (executable)
|
# libapplypatch_modes (static library)
|
||||||
# ===============================
|
# ===============================
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_CLANG := true
|
LOCAL_CLANG := true
|
||||||
LOCAL_SRC_FILES := main.cpp
|
LOCAL_SRC_FILES := \
|
||||||
|
applypatch_modes.cpp
|
||||||
|
LOCAL_MODULE := libapplypatch_modes
|
||||||
|
LOCAL_C_INCLUDES := bootable/recovery
|
||||||
|
LOCAL_STATIC_LIBRARIES := \
|
||||||
|
libapplypatch \
|
||||||
|
libbase \
|
||||||
|
libedify \
|
||||||
|
libcrypto
|
||||||
|
LOCAL_CFLAGS := -Werror
|
||||||
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
|
# applypatch (target executable)
|
||||||
|
# ===============================
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
LOCAL_CLANG := true
|
||||||
|
LOCAL_SRC_FILES := applypatch_main.cpp
|
||||||
LOCAL_MODULE := applypatch
|
LOCAL_MODULE := applypatch
|
||||||
LOCAL_C_INCLUDES += bootable/recovery
|
LOCAL_C_INCLUDES := bootable/recovery
|
||||||
LOCAL_STATIC_LIBRARIES += \
|
LOCAL_STATIC_LIBRARIES := \
|
||||||
|
libapplypatch_modes \
|
||||||
libapplypatch \
|
libapplypatch \
|
||||||
libbase \
|
libbase \
|
||||||
libedify \
|
libedify \
|
||||||
libotafault \
|
libotafault \
|
||||||
libcrypto \
|
libcrypto \
|
||||||
libbz
|
libbz
|
||||||
LOCAL_SHARED_LIBRARIES += libbase libz libcutils libc
|
LOCAL_SHARED_LIBRARIES := \
|
||||||
|
libbase \
|
||||||
|
libz \
|
||||||
|
libcutils
|
||||||
LOCAL_CFLAGS := -Werror
|
LOCAL_CFLAGS := -Werror
|
||||||
include $(BUILD_EXECUTABLE)
|
include $(BUILD_EXECUTABLE)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 "applypatch_modes.h"
|
||||||
|
|
||||||
|
// This program (applypatch) applies binary patches to files in a way that
|
||||||
|
// is safe (the original file is not touched until we have the desired
|
||||||
|
// replacement for it) and idempotent (it's okay to run this program
|
||||||
|
// multiple times).
|
||||||
|
//
|
||||||
|
// See the comments to applypatch_modes() function.
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
return applypatch_modes(argc, const_cast<const char**>(argv));
|
||||||
|
}
|
||||||
@@ -14,6 +14,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "applypatch_modes.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -23,12 +25,14 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <android-base/parseint.h>
|
||||||
|
#include <android-base/strings.h>
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
|
|
||||||
#include "applypatch/applypatch.h"
|
#include "applypatch/applypatch.h"
|
||||||
#include "edify/expr.h"
|
#include "edify/expr.h"
|
||||||
|
|
||||||
static int CheckMode(int argc, char** argv) {
|
static int CheckMode(int argc, const char** argv) {
|
||||||
if (argc < 3) {
|
if (argc < 3) {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
@@ -40,44 +44,42 @@ static int CheckMode(int argc, char** argv) {
|
|||||||
return applypatch_check(argv[2], sha1);
|
return applypatch_check(argv[2], sha1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int SpaceMode(int argc, char** argv) {
|
static int SpaceMode(int argc, const char** argv) {
|
||||||
if (argc != 3) {
|
if (argc != 3) {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
char* endptr;
|
|
||||||
size_t bytes = strtol(argv[2], &endptr, 10);
|
size_t bytes;
|
||||||
if (bytes == 0 && endptr == argv[2]) {
|
if (!android::base::ParseUint(argv[2], &bytes) || bytes == 0) {
|
||||||
printf("can't parse \"%s\" as byte count\n\n", argv[2]);
|
printf("can't parse \"%s\" as byte count\n\n", argv[2]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return CacheSizeCheck(bytes);
|
return CacheSizeCheck(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse arguments (which should be of the form "<sha1>:<filename>"
|
// Parse arguments (which should be of the form "<sha1>:<filename>" into the
|
||||||
// into the new parallel arrays *sha1s and *files.Returns true on
|
// new parallel arrays *sha1s and *files. Returns true on success.
|
||||||
// success.
|
static bool ParsePatchArgs(int argc, const char** argv, std::vector<std::string>* sha1s,
|
||||||
static bool ParsePatchArgs(int argc, char** argv, std::vector<std::string>* sha1s,
|
|
||||||
std::vector<FileContents>* files) {
|
std::vector<FileContents>* files) {
|
||||||
if (sha1s == nullptr) {
|
if (sha1s == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < argc; ++i) {
|
for (int i = 0; i < argc; ++i) {
|
||||||
uint8_t digest[SHA_DIGEST_LENGTH];
|
std::vector<std::string> pieces = android::base::Split(argv[i], ":");
|
||||||
char* colon = strchr(argv[i], ':');
|
if (pieces.size() != 2) {
|
||||||
if (colon == nullptr) {
|
printf("failed to parse patch argument \"%s\"\n", argv[i]);
|
||||||
printf("no ':' in patch argument \"%s\"\n", argv[i]);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*colon = '\0';
|
|
||||||
++colon;
|
uint8_t digest[SHA_DIGEST_LENGTH];
|
||||||
if (ParseSha1(argv[i], digest) != 0) {
|
if (ParseSha1(pieces[0].c_str(), digest) != 0) {
|
||||||
printf("failed to parse sha1 \"%s\"\n", argv[i]);
|
printf("failed to parse sha1 \"%s\"\n", argv[i]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
sha1s->push_back(argv[i]);
|
sha1s->push_back(pieces[0]);
|
||||||
FileContents fc;
|
FileContents fc;
|
||||||
if (LoadFileContents(colon, &fc) != 0) {
|
if (LoadFileContents(pieces[1].c_str(), &fc) != 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
files->push_back(std::move(fc));
|
files->push_back(std::move(fc));
|
||||||
@@ -90,7 +92,7 @@ static int FlashMode(const char* src_filename, const char* tgt_filename,
|
|||||||
return applypatch_flash(src_filename, tgt_filename, tgt_sha1, tgt_size);
|
return applypatch_flash(src_filename, tgt_filename, tgt_sha1, tgt_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PatchMode(int argc, char** argv) {
|
static int PatchMode(int argc, const char** argv) {
|
||||||
FileContents bonusFc;
|
FileContents bonusFc;
|
||||||
Value bonus(VAL_INVALID, "");
|
Value bonus(VAL_INVALID, "");
|
||||||
|
|
||||||
@@ -109,9 +111,8 @@ static int PatchMode(int argc, char** argv) {
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* endptr;
|
size_t target_size;
|
||||||
size_t target_size = strtol(argv[4], &endptr, 10);
|
if (!android::base::ParseUint(argv[4], &target_size) || target_size == 0) {
|
||||||
if (target_size == 0 && endptr == argv[4]) {
|
|
||||||
printf("can't parse \"%s\" as byte count\n\n", argv[4]);
|
printf("can't parse \"%s\" as byte count\n\n", argv[4]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -124,6 +125,7 @@ static int PatchMode(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
return FlashMode(argv[1], argv[2], argv[3], target_size);
|
return FlashMode(argv[1], argv[2], argv[3], target_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> sha1s;
|
std::vector<std::string> sha1s;
|
||||||
std::vector<FileContents> files;
|
std::vector<FileContents> files;
|
||||||
if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &files)) {
|
if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &files)) {
|
||||||
@@ -139,8 +141,8 @@ static int PatchMode(int argc, char** argv) {
|
|||||||
return applypatch(argv[1], argv[2], argv[3], target_size, sha1s, patches, &bonus);
|
return applypatch(argv[1], argv[2], argv[3], target_size, sha1s, patches, &bonus);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This program applies binary patches to files in a way that is safe
|
// This program (applypatch) applies binary patches to files in a way that
|
||||||
// (the original file is not touched until we have the desired
|
// is safe (the original file is not touched until we have the desired
|
||||||
// replacement for it) and idempotent (it's okay to run this program
|
// replacement for it) and idempotent (it's okay to run this program
|
||||||
// multiple times).
|
// multiple times).
|
||||||
//
|
//
|
||||||
@@ -166,7 +168,7 @@ static int PatchMode(int argc, char** argv) {
|
|||||||
// to read the source data. See the comments for the
|
// to read the source data. See the comments for the
|
||||||
// LoadPartitionContents() function for the format of such a filename.
|
// LoadPartitionContents() function for the format of such a filename.
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int applypatch_modes(int argc, const char** argv) {
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
usage:
|
usage:
|
||||||
printf(
|
printf(
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _APPLYPATCH_MODES_H
|
||||||
|
#define _APPLYPATCH_MODES_H
|
||||||
|
|
||||||
|
int applypatch_modes(int argc, const char** argv);
|
||||||
|
|
||||||
|
#endif // _APPLYPATCH_MODES_H
|
||||||
+2
-1
@@ -43,7 +43,7 @@ include $(BUILD_NATIVE_TEST)
|
|||||||
# Component tests
|
# Component tests
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_CLANG := true
|
LOCAL_CLANG := true
|
||||||
LOCAL_CFLAGS += -Wno-unused-parameter -Werror
|
LOCAL_CFLAGS := -Werror
|
||||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
||||||
LOCAL_MODULE := recovery_component_test
|
LOCAL_MODULE := recovery_component_test
|
||||||
LOCAL_C_INCLUDES := bootable/recovery
|
LOCAL_C_INCLUDES := bootable/recovery
|
||||||
@@ -63,6 +63,7 @@ tune2fs_static_libraries := \
|
|||||||
libext2fs
|
libext2fs
|
||||||
|
|
||||||
LOCAL_STATIC_LIBRARIES := \
|
LOCAL_STATIC_LIBRARIES := \
|
||||||
|
libapplypatch_modes \
|
||||||
libapplypatch \
|
libapplypatch \
|
||||||
libedify \
|
libedify \
|
||||||
libotafault \
|
libotafault \
|
||||||
|
|||||||
+309
-243
@@ -33,149 +33,155 @@
|
|||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
|
|
||||||
#include "applypatch/applypatch.h"
|
#include "applypatch/applypatch.h"
|
||||||
|
#include "applypatch/applypatch_modes.h"
|
||||||
#include "common/test_constants.h"
|
#include "common/test_constants.h"
|
||||||
#include "print_sha1.h"
|
#include "print_sha1.h"
|
||||||
|
|
||||||
static const std::string DATA_PATH = getenv("ANDROID_DATA");
|
static const std::string DATA_PATH = getenv("ANDROID_DATA");
|
||||||
static const std::string TESTDATA_PATH = "/recovery/testdata";
|
static const std::string TESTDATA_PATH = "/recovery/testdata";
|
||||||
|
|
||||||
static void sha1sum(const std::string& fname, std::string* sha1) {
|
static void sha1sum(const std::string& fname, std::string* sha1, size_t* fsize = nullptr) {
|
||||||
ASSERT_NE(nullptr, sha1);
|
ASSERT_NE(nullptr, sha1);
|
||||||
|
|
||||||
std::string data;
|
std::string data;
|
||||||
ASSERT_TRUE(android::base::ReadFileToString(fname, &data));
|
ASSERT_TRUE(android::base::ReadFileToString(fname, &data));
|
||||||
|
|
||||||
uint8_t digest[SHA_DIGEST_LENGTH];
|
if (fsize != nullptr) {
|
||||||
SHA1(reinterpret_cast<const uint8_t*>(data.c_str()), data.size(), digest);
|
*fsize = data.size();
|
||||||
*sha1 = print_sha1(digest);
|
}
|
||||||
|
|
||||||
|
uint8_t digest[SHA_DIGEST_LENGTH];
|
||||||
|
SHA1(reinterpret_cast<const uint8_t*>(data.c_str()), data.size(), digest);
|
||||||
|
*sha1 = print_sha1(digest);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mangle_file(const std::string& fname) {
|
static void mangle_file(const std::string& fname) {
|
||||||
std::string content;
|
std::string content;
|
||||||
content.reserve(1024);
|
content.reserve(1024);
|
||||||
for (size_t i = 0; i < 1024; i++) {
|
for (size_t i = 0; i < 1024; i++) {
|
||||||
content[i] = rand() % 256;
|
content[i] = rand() % 256;
|
||||||
}
|
}
|
||||||
ASSERT_TRUE(android::base::WriteStringToFile(content, fname));
|
ASSERT_TRUE(android::base::WriteStringToFile(content, fname));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool file_cmp(const std::string& f1, const std::string& f2) {
|
static bool file_cmp(const std::string& f1, const std::string& f2) {
|
||||||
std::string c1;
|
std::string c1;
|
||||||
android::base::ReadFileToString(f1, &c1);
|
android::base::ReadFileToString(f1, &c1);
|
||||||
std::string c2;
|
std::string c2;
|
||||||
android::base::ReadFileToString(f2, &c2);
|
android::base::ReadFileToString(f2, &c2);
|
||||||
return c1 == c2;
|
return c1 == c2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string from_testdata_base(const std::string& fname) {
|
static std::string from_testdata_base(const std::string& fname) {
|
||||||
return DATA_PATH + NATIVE_TEST_PATH + TESTDATA_PATH + "/" + fname;
|
return DATA_PATH + NATIVE_TEST_PATH + TESTDATA_PATH + "/" + fname;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ApplyPatchTest : public ::testing::Test {
|
class ApplyPatchTest : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
static void SetUpTestCase() {
|
static void SetUpTestCase() {
|
||||||
// set up files
|
// set up files
|
||||||
old_file = from_testdata_base("old.file");
|
old_file = from_testdata_base("old.file");
|
||||||
new_file = from_testdata_base("new.file");
|
new_file = from_testdata_base("new.file");
|
||||||
patch_file = from_testdata_base("patch.bsdiff");
|
patch_file = from_testdata_base("patch.bsdiff");
|
||||||
rand_file = "/cache/applypatch_test_rand.file";
|
rand_file = "/cache/applypatch_test_rand.file";
|
||||||
cache_file = "/cache/saved.file";
|
cache_file = "/cache/saved.file";
|
||||||
|
|
||||||
// write stuff to rand_file
|
// write stuff to rand_file
|
||||||
ASSERT_TRUE(android::base::WriteStringToFile("hello", rand_file));
|
ASSERT_TRUE(android::base::WriteStringToFile("hello", rand_file));
|
||||||
|
|
||||||
// set up SHA constants
|
// set up SHA constants
|
||||||
sha1sum(old_file, &old_sha1);
|
sha1sum(old_file, &old_sha1);
|
||||||
sha1sum(new_file, &new_sha1);
|
sha1sum(new_file, &new_sha1);
|
||||||
srand(time(NULL));
|
srand(time(nullptr));
|
||||||
bad_sha1_a = android::base::StringPrintf("%040x", rand());
|
bad_sha1_a = android::base::StringPrintf("%040x", rand());
|
||||||
bad_sha1_b = android::base::StringPrintf("%040x", rand());
|
bad_sha1_b = android::base::StringPrintf("%040x", rand());
|
||||||
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
stat(&new_file[0], &st);
|
stat(&new_file[0], &st);
|
||||||
new_size = st.st_size;
|
new_size = st.st_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string old_file;
|
static std::string old_file;
|
||||||
static std::string new_file;
|
static std::string new_file;
|
||||||
static std::string rand_file;
|
static std::string rand_file;
|
||||||
static std::string cache_file;
|
static std::string cache_file;
|
||||||
static std::string patch_file;
|
static std::string patch_file;
|
||||||
|
|
||||||
static std::string old_sha1;
|
static std::string old_sha1;
|
||||||
static std::string new_sha1;
|
static std::string new_sha1;
|
||||||
static std::string bad_sha1_a;
|
static std::string bad_sha1_a;
|
||||||
static std::string bad_sha1_b;
|
static std::string bad_sha1_b;
|
||||||
|
|
||||||
static size_t new_size;
|
static size_t new_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string ApplyPatchTest::old_file;
|
std::string ApplyPatchTest::old_file;
|
||||||
std::string ApplyPatchTest::new_file;
|
std::string ApplyPatchTest::new_file;
|
||||||
|
|
||||||
static void cp(const std::string& src, const std::string& tgt) {
|
static void cp(const std::string& src, const std::string& tgt) {
|
||||||
std::string cmd = "cp " + src + " " + tgt;
|
std::string cmd = "cp " + src + " " + tgt;
|
||||||
system(&cmd[0]);
|
system(cmd.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void backup_old() {
|
static void backup_old() {
|
||||||
cp(ApplyPatchTest::old_file, ApplyPatchTest::cache_file);
|
cp(ApplyPatchTest::old_file, ApplyPatchTest::cache_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void restore_old() {
|
static void restore_old() {
|
||||||
cp(ApplyPatchTest::cache_file, ApplyPatchTest::old_file);
|
cp(ApplyPatchTest::cache_file, ApplyPatchTest::old_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ApplyPatchCacheTest : public ApplyPatchTest {
|
class ApplyPatchCacheTest : public ApplyPatchTest {
|
||||||
public:
|
public:
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
backup_old();
|
backup_old();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void TearDown() {
|
virtual void TearDown() {
|
||||||
restore_old();
|
restore_old();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ApplyPatchFullTest : public ApplyPatchCacheTest {
|
class ApplyPatchFullTest : public ApplyPatchCacheTest {
|
||||||
public:
|
public:
|
||||||
static void SetUpTestCase() {
|
static void SetUpTestCase() {
|
||||||
ApplyPatchTest::SetUpTestCase();
|
ApplyPatchTest::SetUpTestCase();
|
||||||
|
|
||||||
output_f = new TemporaryFile();
|
output_f = new TemporaryFile();
|
||||||
output_loc = std::string(output_f->path);
|
output_loc = std::string(output_f->path);
|
||||||
|
|
||||||
struct FileContents fc;
|
struct FileContents fc;
|
||||||
|
|
||||||
ASSERT_EQ(0, LoadFileContents(&rand_file[0], &fc));
|
ASSERT_EQ(0, LoadFileContents(&rand_file[0], &fc));
|
||||||
patches.push_back(
|
patches.push_back(
|
||||||
std::make_unique<Value>(VAL_BLOB, std::string(fc.data.begin(), fc.data.end())));
|
std::make_unique<Value>(VAL_BLOB, std::string(fc.data.begin(), fc.data.end())));
|
||||||
|
|
||||||
ASSERT_EQ(0, LoadFileContents(&patch_file[0], &fc));
|
ASSERT_EQ(0, LoadFileContents(&patch_file[0], &fc));
|
||||||
patches.push_back(
|
patches.push_back(
|
||||||
std::make_unique<Value>(VAL_BLOB, std::string(fc.data.begin(), fc.data.end())));
|
std::make_unique<Value>(VAL_BLOB, std::string(fc.data.begin(), fc.data.end())));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TearDownTestCase() {
|
static void TearDownTestCase() {
|
||||||
delete output_f;
|
delete output_f;
|
||||||
}
|
patches.clear();
|
||||||
|
}
|
||||||
|
|
||||||
static std::vector<std::unique_ptr<Value>> patches;
|
static std::vector<std::unique_ptr<Value>> patches;
|
||||||
static TemporaryFile* output_f;
|
static TemporaryFile* output_f;
|
||||||
static std::string output_loc;
|
static std::string output_loc;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ApplyPatchDoubleCacheTest : public ApplyPatchFullTest {
|
class ApplyPatchDoubleCacheTest : public ApplyPatchFullTest {
|
||||||
public:
|
public:
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
ApplyPatchCacheTest::SetUp();
|
ApplyPatchCacheTest::SetUp();
|
||||||
cp(cache_file, "/cache/reallysaved.file");
|
cp(cache_file, "/cache/reallysaved.file");
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void TearDown() {
|
virtual void TearDown() {
|
||||||
cp("/cache/reallysaved.file", cache_file);
|
cp("/cache/reallysaved.file", cache_file);
|
||||||
ApplyPatchCacheTest::TearDown();
|
ApplyPatchCacheTest::TearDown();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string ApplyPatchTest::rand_file;
|
std::string ApplyPatchTest::rand_file;
|
||||||
@@ -193,203 +199,263 @@ TemporaryFile* ApplyPatchFullTest::output_f;
|
|||||||
std::string ApplyPatchFullTest::output_loc;
|
std::string ApplyPatchFullTest::output_loc;
|
||||||
|
|
||||||
TEST_F(ApplyPatchTest, CheckModeSkip) {
|
TEST_F(ApplyPatchTest, CheckModeSkip) {
|
||||||
std::vector<std::string> sha1s;
|
std::vector<std::string> sha1s;
|
||||||
ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
|
ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ApplyPatchTest, CheckModeSingle) {
|
TEST_F(ApplyPatchTest, CheckModeSingle) {
|
||||||
std::vector<std::string> sha1s = { old_sha1 };
|
std::vector<std::string> sha1s = { old_sha1 };
|
||||||
ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
|
ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ApplyPatchTest, CheckModeMultiple) {
|
TEST_F(ApplyPatchTest, CheckModeMultiple) {
|
||||||
std::vector<std::string> sha1s = {
|
std::vector<std::string> sha1s = { bad_sha1_a, old_sha1, bad_sha1_b };
|
||||||
bad_sha1_a,
|
ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
|
||||||
old_sha1,
|
|
||||||
bad_sha1_b
|
|
||||||
};
|
|
||||||
ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ApplyPatchTest, CheckModeFailure) {
|
TEST_F(ApplyPatchTest, CheckModeFailure) {
|
||||||
std::vector<std::string> sha1s = {
|
std::vector<std::string> sha1s = { bad_sha1_a, bad_sha1_b };
|
||||||
bad_sha1_a,
|
ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
|
||||||
bad_sha1_b
|
|
||||||
};
|
|
||||||
ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSingle) {
|
TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSingle) {
|
||||||
mangle_file(old_file);
|
mangle_file(old_file);
|
||||||
std::vector<std::string> sha1s = { old_sha1 };
|
std::vector<std::string> sha1s = { old_sha1 };
|
||||||
ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
|
ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedMultiple) {
|
TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedMultiple) {
|
||||||
mangle_file(old_file);
|
mangle_file(old_file);
|
||||||
std::vector<std::string> sha1s = {
|
std::vector<std::string> sha1s = { bad_sha1_a, old_sha1, bad_sha1_b };
|
||||||
bad_sha1_a,
|
ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
|
||||||
old_sha1,
|
|
||||||
bad_sha1_b
|
|
||||||
};
|
|
||||||
ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedFailure) {
|
TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedFailure) {
|
||||||
mangle_file(old_file);
|
mangle_file(old_file);
|
||||||
std::vector<std::string> sha1s = {
|
std::vector<std::string> sha1s = { bad_sha1_a, bad_sha1_b };
|
||||||
bad_sha1_a,
|
ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
|
||||||
bad_sha1_b
|
|
||||||
};
|
|
||||||
ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ApplyPatchCacheTest, CheckCacheMissingSingle) {
|
TEST_F(ApplyPatchCacheTest, CheckCacheMissingSingle) {
|
||||||
unlink(&old_file[0]);
|
unlink(&old_file[0]);
|
||||||
std::vector<std::string> sha1s = { old_sha1 };
|
std::vector<std::string> sha1s = { old_sha1 };
|
||||||
ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
|
ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ApplyPatchCacheTest, CheckCacheMissingMultiple) {
|
TEST_F(ApplyPatchCacheTest, CheckCacheMissingMultiple) {
|
||||||
unlink(&old_file[0]);
|
unlink(&old_file[0]);
|
||||||
std::vector<std::string> sha1s = {
|
std::vector<std::string> sha1s = { bad_sha1_a, old_sha1, bad_sha1_b };
|
||||||
bad_sha1_a,
|
ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
|
||||||
old_sha1,
|
|
||||||
bad_sha1_b
|
|
||||||
};
|
|
||||||
ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ApplyPatchCacheTest, CheckCacheMissingFailure) {
|
TEST_F(ApplyPatchCacheTest, CheckCacheMissingFailure) {
|
||||||
unlink(&old_file[0]);
|
unlink(&old_file[0]);
|
||||||
std::vector<std::string> sha1s = {
|
std::vector<std::string> sha1s = { bad_sha1_a, bad_sha1_b };
|
||||||
bad_sha1_a,
|
ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
|
||||||
bad_sha1_b
|
|
||||||
};
|
|
||||||
ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ApplyPatchFullTest, ApplyInPlace) {
|
TEST_F(ApplyPatchFullTest, ApplyInPlace) {
|
||||||
std::vector<std::string> sha1s = {
|
std::vector<std::string> sha1s = { bad_sha1_a, old_sha1 };
|
||||||
bad_sha1_a,
|
ASSERT_EQ(0, applypatch(&old_file[0], "-", &new_sha1[0], new_size, sha1s, patches, nullptr));
|
||||||
old_sha1
|
ASSERT_TRUE(file_cmp(old_file, new_file));
|
||||||
};
|
|
||||||
int ap_result = applypatch(&old_file[0],
|
// reapply, applypatch is idempotent so it should succeed
|
||||||
"-",
|
ASSERT_EQ(0, applypatch(&old_file[0], "-", &new_sha1[0], new_size, sha1s, patches, nullptr));
|
||||||
&new_sha1[0],
|
ASSERT_TRUE(file_cmp(old_file, new_file));
|
||||||
new_size,
|
|
||||||
sha1s,
|
|
||||||
patches,
|
|
||||||
nullptr);
|
|
||||||
ASSERT_EQ(0, ap_result);
|
|
||||||
ASSERT_TRUE(file_cmp(old_file, new_file));
|
|
||||||
// reapply, applypatch is idempotent so it should succeed
|
|
||||||
ap_result = applypatch(&old_file[0],
|
|
||||||
"-",
|
|
||||||
&new_sha1[0],
|
|
||||||
new_size,
|
|
||||||
sha1s,
|
|
||||||
patches,
|
|
||||||
nullptr);
|
|
||||||
ASSERT_EQ(0, ap_result);
|
|
||||||
ASSERT_TRUE(file_cmp(old_file, new_file));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ApplyPatchFullTest, ApplyInNewLocation) {
|
TEST_F(ApplyPatchFullTest, ApplyInNewLocation) {
|
||||||
std::vector<std::string> sha1s = {
|
std::vector<std::string> sha1s = { bad_sha1_a, old_sha1 };
|
||||||
bad_sha1_a,
|
// Apply bsdiff patch to new location.
|
||||||
old_sha1
|
ASSERT_EQ(
|
||||||
};
|
0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr));
|
||||||
// Apply bsdiff patch to new location.
|
ASSERT_TRUE(file_cmp(output_loc, new_file));
|
||||||
ASSERT_EQ(0, applypatch(&old_file[0],
|
|
||||||
&output_loc[0],
|
|
||||||
&new_sha1[0],
|
|
||||||
new_size,
|
|
||||||
sha1s,
|
|
||||||
patches,
|
|
||||||
nullptr));
|
|
||||||
ASSERT_TRUE(file_cmp(output_loc, new_file));
|
|
||||||
|
|
||||||
// Reapply to the same location.
|
// Reapply to the same location.
|
||||||
ASSERT_EQ(0, applypatch(&old_file[0],
|
ASSERT_EQ(
|
||||||
&output_loc[0],
|
0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr));
|
||||||
&new_sha1[0],
|
ASSERT_TRUE(file_cmp(output_loc, new_file));
|
||||||
new_size,
|
|
||||||
sha1s,
|
|
||||||
patches,
|
|
||||||
nullptr));
|
|
||||||
ASSERT_TRUE(file_cmp(output_loc, new_file));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ApplyPatchFullTest, ApplyCorruptedInNewLocation) {
|
TEST_F(ApplyPatchFullTest, ApplyCorruptedInNewLocation) {
|
||||||
std::vector<std::string> sha1s = {
|
std::vector<std::string> sha1s = { bad_sha1_a, old_sha1 };
|
||||||
bad_sha1_a,
|
// Apply bsdiff patch to new location with corrupted source.
|
||||||
old_sha1
|
mangle_file(old_file);
|
||||||
};
|
ASSERT_EQ(
|
||||||
// Apply bsdiff patch to new location with corrupted source.
|
0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr));
|
||||||
mangle_file(old_file);
|
ASSERT_TRUE(file_cmp(output_loc, new_file));
|
||||||
int ap_result = applypatch(&old_file[0],
|
|
||||||
&output_loc[0],
|
|
||||||
&new_sha1[0],
|
|
||||||
new_size,
|
|
||||||
sha1s,
|
|
||||||
patches,
|
|
||||||
nullptr);
|
|
||||||
ASSERT_EQ(0, ap_result);
|
|
||||||
ASSERT_TRUE(file_cmp(output_loc, new_file));
|
|
||||||
|
|
||||||
// Reapply bsdiff patch to new location with corrupted source.
|
// Reapply bsdiff patch to new location with corrupted source.
|
||||||
ap_result = applypatch(&old_file[0],
|
ASSERT_EQ(
|
||||||
&output_loc[0],
|
0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr));
|
||||||
&new_sha1[0],
|
ASSERT_TRUE(file_cmp(output_loc, new_file));
|
||||||
new_size,
|
|
||||||
sha1s,
|
|
||||||
patches,
|
|
||||||
nullptr);
|
|
||||||
ASSERT_EQ(0, ap_result);
|
|
||||||
ASSERT_TRUE(file_cmp(output_loc, new_file));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ApplyPatchDoubleCacheTest, ApplyDoubleCorruptedInNewLocation) {
|
TEST_F(ApplyPatchDoubleCacheTest, ApplyDoubleCorruptedInNewLocation) {
|
||||||
std::vector<std::string> sha1s = {
|
std::vector<std::string> sha1s = { bad_sha1_a, old_sha1 };
|
||||||
bad_sha1_a,
|
|
||||||
old_sha1
|
|
||||||
};
|
|
||||||
|
|
||||||
// Apply bsdiff patch to new location with corrupted source and copy (no new file).
|
// Apply bsdiff patch to new location with corrupted source and copy (no new file).
|
||||||
// Expected to fail.
|
// Expected to fail.
|
||||||
mangle_file(old_file);
|
mangle_file(old_file);
|
||||||
mangle_file(cache_file);
|
mangle_file(cache_file);
|
||||||
int ap_result = applypatch(&old_file[0],
|
ASSERT_NE(
|
||||||
&output_loc[0],
|
0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr));
|
||||||
&new_sha1[0],
|
ASSERT_FALSE(file_cmp(output_loc, new_file));
|
||||||
new_size,
|
|
||||||
sha1s,
|
|
||||||
patches,
|
|
||||||
nullptr);
|
|
||||||
ASSERT_NE(0, ap_result);
|
|
||||||
ASSERT_FALSE(file_cmp(output_loc, new_file));
|
|
||||||
|
|
||||||
// Expected to fail again on retry.
|
// Expected to fail again on retry.
|
||||||
ap_result = applypatch(&old_file[0],
|
ASSERT_NE(
|
||||||
&output_loc[0],
|
0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr));
|
||||||
&new_sha1[0],
|
ASSERT_FALSE(file_cmp(output_loc, new_file));
|
||||||
new_size,
|
|
||||||
sha1s,
|
|
||||||
patches,
|
|
||||||
nullptr);
|
|
||||||
ASSERT_NE(0, ap_result);
|
|
||||||
ASSERT_FALSE(file_cmp(output_loc, new_file));
|
|
||||||
|
|
||||||
// Expected to fail with incorrect new file.
|
// Expected to fail with incorrect new file.
|
||||||
mangle_file(output_loc);
|
mangle_file(output_loc);
|
||||||
ap_result = applypatch(&old_file[0],
|
ASSERT_NE(
|
||||||
&output_loc[0],
|
0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr));
|
||||||
&new_sha1[0],
|
ASSERT_FALSE(file_cmp(output_loc, new_file));
|
||||||
new_size,
|
}
|
||||||
sha1s,
|
|
||||||
patches,
|
TEST(ApplyPatchModes, InvalidArgs) {
|
||||||
nullptr);
|
// At least two args (including the filename).
|
||||||
ASSERT_NE(0, ap_result);
|
ASSERT_EQ(2, applypatch_modes(1, (const char* []){ "applypatch" }));
|
||||||
ASSERT_FALSE(file_cmp(output_loc, new_file));
|
|
||||||
|
// Unrecognized args.
|
||||||
|
ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-x" }));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ApplyPatchModes, PatchMode) {
|
||||||
|
std::string boot_img = from_testdata_base("boot.img");
|
||||||
|
size_t boot_img_size;
|
||||||
|
std::string boot_img_sha1;
|
||||||
|
sha1sum(boot_img, &boot_img_sha1, &boot_img_size);
|
||||||
|
|
||||||
|
std::string recovery_img = from_testdata_base("recovery.img");
|
||||||
|
size_t recovery_img_size;
|
||||||
|
std::string recovery_img_sha1;
|
||||||
|
sha1sum(recovery_img, &recovery_img_sha1, &recovery_img_size);
|
||||||
|
|
||||||
|
std::string bonus_file = from_testdata_base("bonus.file");
|
||||||
|
|
||||||
|
// applypatch -b <bonus-file> <src-file> <tgt-file> <tgt-sha1> <tgt-size> <src-sha1>:<patch>
|
||||||
|
TemporaryFile tmp1;
|
||||||
|
std::vector<const char*> args = {
|
||||||
|
"applypatch",
|
||||||
|
"-b",
|
||||||
|
bonus_file.c_str(),
|
||||||
|
boot_img.c_str(),
|
||||||
|
tmp1.path,
|
||||||
|
recovery_img_sha1.c_str(),
|
||||||
|
std::to_string(recovery_img_size).c_str(),
|
||||||
|
(boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p")).c_str()
|
||||||
|
};
|
||||||
|
ASSERT_EQ(0, applypatch_modes(args.size(), args.data()));
|
||||||
|
|
||||||
|
// applypatch <src-file> <tgt-file> <tgt-sha1> <tgt-size> <src-sha1>:<patch>
|
||||||
|
TemporaryFile tmp2;
|
||||||
|
std::vector<const char*> args2 = {
|
||||||
|
"applypatch",
|
||||||
|
boot_img.c_str(),
|
||||||
|
tmp2.path,
|
||||||
|
recovery_img_sha1.c_str(),
|
||||||
|
std::to_string(recovery_img_size).c_str(),
|
||||||
|
(boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p")).c_str()
|
||||||
|
};
|
||||||
|
ASSERT_EQ(0, applypatch_modes(args2.size(), args2.data()));
|
||||||
|
|
||||||
|
// applypatch -b <bonus-file> <src-file> <tgt-file> <tgt-sha1> <tgt-size> \
|
||||||
|
// <src-sha1-fake>:<patch1> <src-sha1>:<patch2>
|
||||||
|
TemporaryFile tmp3;
|
||||||
|
std::string bad_sha1_a = android::base::StringPrintf("%040x", rand());
|
||||||
|
std::string bad_sha1_b = android::base::StringPrintf("%040x", rand());
|
||||||
|
std::vector<const char*> args3 = {
|
||||||
|
"applypatch",
|
||||||
|
"-b",
|
||||||
|
bonus_file.c_str(),
|
||||||
|
boot_img.c_str(),
|
||||||
|
tmp3.path,
|
||||||
|
recovery_img_sha1.c_str(),
|
||||||
|
std::to_string(recovery_img_size).c_str(),
|
||||||
|
(bad_sha1_a + ":" + from_testdata_base("recovery-from-boot.p")).c_str(),
|
||||||
|
(boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p")).c_str(),
|
||||||
|
(bad_sha1_b + ":" + from_testdata_base("recovery-from-boot.p")).c_str(),
|
||||||
|
};
|
||||||
|
ASSERT_EQ(0, applypatch_modes(args3.size(), args3.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ApplyPatchModes, PatchModeInvalidArgs) {
|
||||||
|
// Invalid bonus file.
|
||||||
|
ASSERT_NE(0, applypatch_modes(3, (const char* []){ "applypatch", "-b", "/doesntexist" }));
|
||||||
|
|
||||||
|
std::string bonus_file = from_testdata_base("bonus.file");
|
||||||
|
// With bonus file, but missing args.
|
||||||
|
ASSERT_EQ(2, applypatch_modes(3, (const char* []){ "applypatch", "-b", bonus_file.c_str() }));
|
||||||
|
|
||||||
|
std::string boot_img = from_testdata_base("boot.img");
|
||||||
|
size_t boot_img_size;
|
||||||
|
std::string boot_img_sha1;
|
||||||
|
sha1sum(boot_img, &boot_img_sha1, &boot_img_size);
|
||||||
|
|
||||||
|
std::string recovery_img = from_testdata_base("recovery.img");
|
||||||
|
size_t recovery_img_size;
|
||||||
|
std::string recovery_img_sha1;
|
||||||
|
sha1sum(recovery_img, &recovery_img_sha1, &recovery_img_size);
|
||||||
|
|
||||||
|
// Bonus file is not supported in flash mode.
|
||||||
|
// applypatch -b <bonus-file> <src-file> <tgt-file> <tgt-sha1> <tgt-size>
|
||||||
|
TemporaryFile tmp4;
|
||||||
|
std::vector<const char*> args4 = {
|
||||||
|
"applypatch",
|
||||||
|
"-b",
|
||||||
|
bonus_file.c_str(),
|
||||||
|
boot_img.c_str(),
|
||||||
|
tmp4.path,
|
||||||
|
recovery_img_sha1.c_str(),
|
||||||
|
std::to_string(recovery_img_size).c_str() };
|
||||||
|
ASSERT_NE(0, applypatch_modes(args4.size(), args4.data()));
|
||||||
|
|
||||||
|
// Failed to parse patch args.
|
||||||
|
TemporaryFile tmp5;
|
||||||
|
std::vector<const char*> args5 = {
|
||||||
|
"applypatch",
|
||||||
|
boot_img.c_str(),
|
||||||
|
tmp5.path,
|
||||||
|
recovery_img_sha1.c_str(),
|
||||||
|
std::to_string(recovery_img_size).c_str(),
|
||||||
|
("invalid-sha1:filename" + from_testdata_base("recovery-from-boot-with-bonus.p")).c_str(),
|
||||||
|
};
|
||||||
|
ASSERT_NE(0, applypatch_modes(args5.size(), args5.data()));
|
||||||
|
|
||||||
|
// Target size cannot be zero.
|
||||||
|
TemporaryFile tmp6;
|
||||||
|
std::vector<const char*> args6 = {
|
||||||
|
"applypatch",
|
||||||
|
boot_img.c_str(),
|
||||||
|
tmp6.path,
|
||||||
|
recovery_img_sha1.c_str(),
|
||||||
|
"0", // target size
|
||||||
|
(boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p")).c_str()
|
||||||
|
};
|
||||||
|
ASSERT_NE(0, applypatch_modes(args6.size(), args6.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ApplyPatchModes, CheckModeInvalidArgs) {
|
||||||
|
// Insufficient args.
|
||||||
|
ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-c" }));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ApplyPatchModes, SpaceModeInvalidArgs) {
|
||||||
|
// Insufficient args.
|
||||||
|
ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-s" }));
|
||||||
|
|
||||||
|
// Invalid bytes arg.
|
||||||
|
ASSERT_EQ(1, applypatch_modes(3, (const char* []){ "applypatch", "-s", "x" }));
|
||||||
|
|
||||||
|
// 0 is invalid.
|
||||||
|
ASSERT_EQ(1, applypatch_modes(3, (const char* []){ "applypatch", "-s", "0" }));
|
||||||
|
|
||||||
|
// 0x10 is fine.
|
||||||
|
ASSERT_EQ(0, applypatch_modes(3, (const char* []){ "applypatch", "-s", "0x10" }));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ApplyPatchModes, ShowLicenses) {
|
||||||
|
ASSERT_EQ(0, applypatch_modes(2, (const char* []){ "applypatch", "-l" }));
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Reference in New Issue
Block a user