Convert aes_test to GTest.
This introduces machinery to start embedding the test data files into the crypto_test binary. Figuring out every CI's test data story is more trouble than is worth it. The GTest FileTest runner is considerably different from the old one: - It returns void and expects failures to use the GTest EXPECT_* and ASSERT_* macros, rather than ExpectBytesEqual. This is more monkey work to convert, but ultimately less work to add new tests. I think it's also valuable for our FileTest and normal test patterns to align as much as possible. The line number is emitted via SCOPED_TRACE. - I've intentionally omitted the Error attribute handling, since that doesn't work very well with the new callback. This means evp_test.cc will take a little more work to convert, but this is again to keep our two test patterns aligned. - The callback takes a std::function rather than a C-style void pointer. This means we can go nuts with lambdas. It also places the path first so clang-format doesn't go nuts. BUG=129 Change-Id: I0d1920a342b00e64043e3ea05f5f5af57bfe77b3 Reviewed-on: https://boringssl-review.googlesource.com/16507 Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
committed by
Adam Langley
parent
8726d8fe0c
commit
3ecd0a5fca
@@ -9,6 +9,8 @@ if(WIN32)
|
||||
set(CMAKE_GENERATOR_CC cl)
|
||||
endif()
|
||||
|
||||
include(sources.cmake)
|
||||
|
||||
enable_language(C)
|
||||
enable_language(CXX)
|
||||
|
||||
@@ -265,6 +267,15 @@ include_directories(third_party/googletest/include)
|
||||
# themselves as dependencies next to the target definition.
|
||||
add_custom_target(all_tests)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT crypto_test_data.cc
|
||||
COMMAND ${GO_EXECUTABLE} run util/embed_test_data.go ${CRYPTO_TEST_DATA} >
|
||||
${CMAKE_CURRENT_BINARY_DIR}/crypto_test_data.cc
|
||||
DEPENDS util/embed_test_data.go ${CRYPTO_TEST_DATA}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
add_library(crypto_test_data OBJECT crypto_test_data.cc)
|
||||
|
||||
add_subdirectory(crypto)
|
||||
add_subdirectory(ssl)
|
||||
add_subdirectory(ssl/test)
|
||||
|
||||
@@ -251,10 +251,13 @@ add_executable(
|
||||
dsa/dsa_test.cc
|
||||
err/err_test.cc
|
||||
evp/evp_extra_test.cc
|
||||
fipsmodule/aes/aes_test.cc
|
||||
fipsmodule/ec/ec_test.cc
|
||||
fipsmodule/rand/ctrdrbg_test.cc
|
||||
test/file_test_gtest.cc
|
||||
rsa_extra/rsa_test.cc
|
||||
|
||||
$<TARGET_OBJECTS:crypto_test_data>
|
||||
$<TARGET_OBJECTS:gtest_main>
|
||||
$<TARGET_OBJECTS:test_support>
|
||||
)
|
||||
|
||||
@@ -198,16 +198,6 @@ else()
|
||||
)
|
||||
endif()
|
||||
|
||||
add_executable(
|
||||
aes_test
|
||||
|
||||
aes/aes_test.cc
|
||||
$<TARGET_OBJECTS:test_support>
|
||||
)
|
||||
|
||||
target_link_libraries(aes_test crypto)
|
||||
add_dependencies(all_tests aes_test)
|
||||
|
||||
add_executable(
|
||||
bn_test
|
||||
|
||||
|
||||
@@ -18,77 +18,50 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
#include "../../internal.h"
|
||||
#include "../../test/file_test.h"
|
||||
#include "../../test/test_util.h"
|
||||
|
||||
|
||||
static bool TestRaw(FileTest *t) {
|
||||
static void TestRaw(FileTest *t) {
|
||||
std::vector<uint8_t> key, plaintext, ciphertext;
|
||||
if (!t->GetBytes(&key, "Key") ||
|
||||
!t->GetBytes(&plaintext, "Plaintext") ||
|
||||
!t->GetBytes(&ciphertext, "Ciphertext")) {
|
||||
return false;
|
||||
}
|
||||
ASSERT_TRUE(t->GetBytes(&key, "Key"));
|
||||
ASSERT_TRUE(t->GetBytes(&plaintext, "Plaintext"));
|
||||
ASSERT_TRUE(t->GetBytes(&ciphertext, "Ciphertext"));
|
||||
|
||||
if (plaintext.size() != AES_BLOCK_SIZE ||
|
||||
ciphertext.size() != AES_BLOCK_SIZE) {
|
||||
t->PrintLine("Plaintext or Ciphertext not a block size.");
|
||||
return false;
|
||||
}
|
||||
ASSERT_EQ(static_cast<unsigned>(AES_BLOCK_SIZE), plaintext.size());
|
||||
ASSERT_EQ(static_cast<unsigned>(AES_BLOCK_SIZE), ciphertext.size());
|
||||
|
||||
AES_KEY aes_key;
|
||||
if (AES_set_encrypt_key(key.data(), 8 * key.size(), &aes_key) != 0) {
|
||||
t->PrintLine("AES_set_encrypt_key failed.");
|
||||
return false;
|
||||
}
|
||||
ASSERT_EQ(0, AES_set_encrypt_key(key.data(), 8 * key.size(), &aes_key));
|
||||
|
||||
// Test encryption.
|
||||
uint8_t block[AES_BLOCK_SIZE];
|
||||
AES_encrypt(plaintext.data(), block, &aes_key);
|
||||
if (!t->ExpectBytesEqual(block, AES_BLOCK_SIZE, ciphertext.data(),
|
||||
ciphertext.size())) {
|
||||
t->PrintLine("AES_encrypt gave the wrong output.");
|
||||
return false;
|
||||
}
|
||||
EXPECT_EQ(Bytes(ciphertext), Bytes(block));
|
||||
|
||||
// Test in-place encryption.
|
||||
OPENSSL_memcpy(block, plaintext.data(), AES_BLOCK_SIZE);
|
||||
AES_encrypt(block, block, &aes_key);
|
||||
if (!t->ExpectBytesEqual(block, AES_BLOCK_SIZE, ciphertext.data(),
|
||||
ciphertext.size())) {
|
||||
t->PrintLine("In-place AES_encrypt gave the wrong output.");
|
||||
return false;
|
||||
}
|
||||
EXPECT_EQ(Bytes(ciphertext), Bytes(block));
|
||||
|
||||
if (AES_set_decrypt_key(key.data(), 8 * key.size(), &aes_key) != 0) {
|
||||
t->PrintLine("AES_set_decrypt_key failed.");
|
||||
return false;
|
||||
}
|
||||
ASSERT_EQ(0, AES_set_decrypt_key(key.data(), 8 * key.size(), &aes_key));
|
||||
|
||||
// Test decryption.
|
||||
AES_decrypt(ciphertext.data(), block, &aes_key);
|
||||
if (!t->ExpectBytesEqual(block, AES_BLOCK_SIZE, plaintext.data(),
|
||||
plaintext.size())) {
|
||||
t->PrintLine("AES_decrypt gave the wrong output.");
|
||||
return false;
|
||||
}
|
||||
EXPECT_EQ(Bytes(plaintext), Bytes(block));
|
||||
|
||||
// Test in-place decryption.
|
||||
OPENSSL_memcpy(block, ciphertext.data(), AES_BLOCK_SIZE);
|
||||
AES_decrypt(block, block, &aes_key);
|
||||
if (!t->ExpectBytesEqual(block, AES_BLOCK_SIZE, plaintext.data(),
|
||||
plaintext.size())) {
|
||||
t->PrintLine("In-place AES_decrypt gave the wrong output.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
EXPECT_EQ(Bytes(plaintext), Bytes(block));
|
||||
}
|
||||
|
||||
static bool TestKeyWrap(FileTest *t) {
|
||||
static void TestKeyWrap(FileTest *t) {
|
||||
// All test vectors use the default IV, so test both with implicit and
|
||||
// explicit IV.
|
||||
//
|
||||
@@ -98,93 +71,61 @@ static bool TestKeyWrap(FileTest *t) {
|
||||
};
|
||||
|
||||
std::vector<uint8_t> key, plaintext, ciphertext;
|
||||
if (!t->GetBytes(&key, "Key") ||
|
||||
!t->GetBytes(&plaintext, "Plaintext") ||
|
||||
!t->GetBytes(&ciphertext, "Ciphertext")) {
|
||||
return false;
|
||||
}
|
||||
ASSERT_TRUE(t->GetBytes(&key, "Key"));
|
||||
ASSERT_TRUE(t->GetBytes(&plaintext, "Plaintext"));
|
||||
ASSERT_TRUE(t->GetBytes(&ciphertext, "Ciphertext"));
|
||||
|
||||
if (plaintext.size() + 8 != ciphertext.size()) {
|
||||
t->PrintLine("Invalid Plaintext and Ciphertext lengths.");
|
||||
return false;
|
||||
}
|
||||
ASSERT_EQ(plaintext.size() + 8, ciphertext.size())
|
||||
<< "Invalid Plaintext and Ciphertext lengths.";
|
||||
|
||||
// Test encryption.
|
||||
AES_KEY aes_key;
|
||||
if (AES_set_encrypt_key(key.data(), 8 * key.size(), &aes_key) != 0) {
|
||||
t->PrintLine("AES_set_encrypt_key failed.");
|
||||
return false;
|
||||
}
|
||||
ASSERT_EQ(0, AES_set_encrypt_key(key.data(), 8 * key.size(), &aes_key));
|
||||
|
||||
// Test with implicit IV.
|
||||
std::unique_ptr<uint8_t[]> buf(new uint8_t[ciphertext.size()]);
|
||||
if (AES_wrap_key(&aes_key, nullptr /* iv */, buf.get(), plaintext.data(),
|
||||
plaintext.size()) != static_cast<int>(ciphertext.size()) ||
|
||||
!t->ExpectBytesEqual(buf.get(), ciphertext.size(), ciphertext.data(),
|
||||
ciphertext.size())) {
|
||||
t->PrintLine("AES_wrap_key with implicit IV failed.");
|
||||
return false;
|
||||
}
|
||||
int len = AES_wrap_key(&aes_key, nullptr /* iv */, buf.get(),
|
||||
plaintext.data(), plaintext.size());
|
||||
ASSERT_GE(len, 0);
|
||||
EXPECT_EQ(Bytes(ciphertext), Bytes(buf.get(), static_cast<size_t>(len)));
|
||||
|
||||
// Test with explicit IV.
|
||||
OPENSSL_memset(buf.get(), 0, ciphertext.size());
|
||||
if (AES_wrap_key(&aes_key, kDefaultIV, buf.get(), plaintext.data(),
|
||||
plaintext.size()) != static_cast<int>(ciphertext.size()) ||
|
||||
!t->ExpectBytesEqual(buf.get(), ciphertext.size(), ciphertext.data(),
|
||||
ciphertext.size())) {
|
||||
t->PrintLine("AES_wrap_key with explicit IV failed.");
|
||||
return false;
|
||||
}
|
||||
len = AES_wrap_key(&aes_key, kDefaultIV, buf.get(), plaintext.data(),
|
||||
plaintext.size());
|
||||
ASSERT_GE(len, 0);
|
||||
EXPECT_EQ(Bytes(ciphertext), Bytes(buf.get(), static_cast<size_t>(len)));
|
||||
|
||||
if (AES_set_decrypt_key(key.data(), 8 * key.size(), &aes_key) != 0) {
|
||||
t->PrintLine("AES_set_decrypt_key failed.");
|
||||
return false;
|
||||
}
|
||||
// Test decryption.
|
||||
ASSERT_EQ(0, AES_set_decrypt_key(key.data(), 8 * key.size(), &aes_key));
|
||||
|
||||
// Test with implicit IV.
|
||||
buf.reset(new uint8_t[plaintext.size()]);
|
||||
if (AES_unwrap_key(&aes_key, nullptr /* iv */, buf.get(), ciphertext.data(),
|
||||
ciphertext.size()) != static_cast<int>(plaintext.size()) ||
|
||||
!t->ExpectBytesEqual(buf.get(), plaintext.size(), plaintext.data(),
|
||||
plaintext.size())) {
|
||||
t->PrintLine("AES_unwrap_key with implicit IV failed.");
|
||||
return false;
|
||||
}
|
||||
len = AES_unwrap_key(&aes_key, nullptr /* iv */, buf.get(), ciphertext.data(),
|
||||
ciphertext.size());
|
||||
ASSERT_GE(len, 0);
|
||||
EXPECT_EQ(Bytes(plaintext), Bytes(buf.get(), static_cast<size_t>(len)));
|
||||
|
||||
// Test with explicit IV.
|
||||
OPENSSL_memset(buf.get(), 0, plaintext.size());
|
||||
if (AES_unwrap_key(&aes_key, kDefaultIV, buf.get(), ciphertext.data(),
|
||||
ciphertext.size()) != static_cast<int>(plaintext.size()) ||
|
||||
!t->ExpectBytesEqual(buf.get(), plaintext.size(), plaintext.data(),
|
||||
plaintext.size())) {
|
||||
t->PrintLine("AES_unwrap_key with explicit IV failed.");
|
||||
return false;
|
||||
}
|
||||
len = AES_unwrap_key(&aes_key, kDefaultIV, buf.get(), ciphertext.data(),
|
||||
ciphertext.size());
|
||||
ASSERT_GE(len, 0);
|
||||
|
||||
// Test corrupted ciphertext.
|
||||
ciphertext[0] ^= 1;
|
||||
if (AES_unwrap_key(&aes_key, nullptr /* iv */, buf.get(), ciphertext.data(),
|
||||
ciphertext.size()) != -1) {
|
||||
t->PrintLine("AES_unwrap_key with bad input unexpectedly succeeded.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
EXPECT_EQ(-1, AES_unwrap_key(&aes_key, nullptr /* iv */, buf.get(),
|
||||
ciphertext.data(), ciphertext.size()));
|
||||
}
|
||||
|
||||
static bool TestAES(FileTest *t, void *arg) {
|
||||
if (t->GetParameter() == "Raw") {
|
||||
return TestRaw(t);
|
||||
}
|
||||
if (t->GetParameter() == "KeyWrap") {
|
||||
return TestKeyWrap(t);
|
||||
}
|
||||
|
||||
t->PrintLine("Unknown mode '%s'.", t->GetParameter().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
CRYPTO_library_init();
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "%s <test file.txt>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return FileTestMain(TestAES, nullptr, argv[1]);
|
||||
TEST(AESTest, TestVectors) {
|
||||
FileTestGTest("crypto/fipsmodule/aes/aes_tests.txt", [](FileTest *t) {
|
||||
if (t->GetParameter() == "Raw") {
|
||||
TestRaw(t);
|
||||
} else if (t->GetParameter() == "KeyWrap") {
|
||||
TestKeyWrap(t);
|
||||
} else {
|
||||
ADD_FAILURE() << "Unknown mode " << t->GetParameter();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
OPENSSL_MSVC_PRAGMA(warning(push))
|
||||
OPENSSL_MSVC_PRAGMA(warning(disable : 4702))
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
@@ -219,4 +220,8 @@ int FileTestMain(FileTestFunc run_test, void *arg, const char *path);
|
||||
// FAIL/PASS message to stdout.
|
||||
int FileTestMainSilent(FileTestFunc run_test, void *arg, const char *path);
|
||||
|
||||
// FileTestGTest behaves like FileTestMain, but for GTest. |path| must be the
|
||||
// name of a test file embedded in the test binary.
|
||||
void FileTestGTest(const char *path, std::function<void(FileTest *)> run_test);
|
||||
|
||||
#endif /* OPENSSL_HEADER_CRYPTO_TEST_FILE_TEST_H */
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/* Copyright (c) 2017, Google Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
#include "file_test.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
std::string GetTestData(const char *path);
|
||||
|
||||
class StringLineReader : public FileTest::LineReader {
|
||||
public:
|
||||
explicit StringLineReader(const std::string &data)
|
||||
: data_(data), offset_(0) {}
|
||||
|
||||
FileTest::ReadResult ReadLine(char *out, size_t len) override {
|
||||
assert(len > 0);
|
||||
if (offset_ == data_.size()) {
|
||||
return FileTest::kReadEOF;
|
||||
}
|
||||
|
||||
size_t idx = data_.find('\n', offset_);
|
||||
if (idx == std::string::npos) {
|
||||
idx = data_.size();
|
||||
} else {
|
||||
idx++; // Include the newline.
|
||||
}
|
||||
|
||||
if (idx - offset_ > len - 1) {
|
||||
ADD_FAILURE() << "Line too long.";
|
||||
return FileTest::kReadError;
|
||||
}
|
||||
|
||||
memcpy(out, data_.data() + offset_, idx - offset_);
|
||||
out[idx - offset_] = '\0';
|
||||
offset_ = idx;
|
||||
return FileTest::kReadSuccess;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string data_;
|
||||
size_t offset_;
|
||||
|
||||
StringLineReader(const StringLineReader &) = delete;
|
||||
StringLineReader &operator=(const StringLineReader &) = delete;
|
||||
};
|
||||
|
||||
void FileTestGTest(const char *path, std::function<void(FileTest *)> run_test) {
|
||||
std::unique_ptr<StringLineReader> reader(
|
||||
new StringLineReader(GetTestData(path)));
|
||||
FileTest t(std::move(reader));
|
||||
|
||||
while (true) {
|
||||
switch (t.ReadNext()) {
|
||||
case FileTest::kReadError:
|
||||
ADD_FAILURE() << "Error reading test.";
|
||||
return;
|
||||
case FileTest::kReadEOF:
|
||||
return;
|
||||
case FileTest::kReadSuccess:
|
||||
break;
|
||||
}
|
||||
|
||||
SCOPED_TRACE(testing::Message() << path << ", line " << t.start_line());
|
||||
run_test(&t);
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../internal.h"
|
||||
|
||||
@@ -42,6 +43,8 @@ struct Bytes {
|
||||
: data(reinterpret_cast<const uint8_t *>(str)), len(strlen(str)) {}
|
||||
explicit Bytes(const std::string &str)
|
||||
: data(reinterpret_cast<const uint8_t *>(str.data())), len(str.size()) {}
|
||||
explicit Bytes(const std::vector<uint8_t> &vec)
|
||||
: data(vec.data()), len(vec.size()) {}
|
||||
|
||||
template <size_t N>
|
||||
explicit Bytes(const uint8_t (&array)[N]) : data(array), len(N) {}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# This file contains source lists that are also consumed by
|
||||
# generate_build_files.py.
|
||||
#
|
||||
# TODO(davidben): Move the other source lists into this file.
|
||||
|
||||
set(
|
||||
CRYPTO_TEST_DATA
|
||||
|
||||
crypto/fipsmodule/aes/aes_tests.txt
|
||||
)
|
||||
@@ -36,7 +36,6 @@
|
||||
["crypto/ecdh/ecdh_test", "crypto/ecdh/ecdh_tests.txt"],
|
||||
["crypto/evp/evp_test", "crypto/evp/evp_tests.txt"],
|
||||
["crypto/evp/pbkdf_test"],
|
||||
["crypto/fipsmodule/aes_test", "crypto/fipsmodule/aes/aes_tests.txt"],
|
||||
["crypto/fipsmodule/bn_test", "crypto/fipsmodule/bn/bn_tests.txt"],
|
||||
["crypto/fipsmodule/ctrdrbg_vector_test", "crypto/fipsmodule/rand/ctrdrbg_vectors.txt"],
|
||||
["crypto/fipsmodule/ecdsa_sign_test", "crypto/fipsmodule/ecdsa/ecdsa_sign_tests.txt"],
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
// Copyright (c) 2017, Google Inc.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
// embed_test_data generates a C++ source file which exports a function,
|
||||
// GetTestData, which looks up the specified data files.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
func quote(in []byte) string {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteByte('"')
|
||||
for _, b := range in {
|
||||
switch b {
|
||||
case '\a':
|
||||
buf.WriteString(`\a`)
|
||||
case '\b':
|
||||
buf.WriteString(`\b`)
|
||||
case '\f':
|
||||
buf.WriteString(`\f`)
|
||||
case '\n':
|
||||
buf.WriteString(`\n`)
|
||||
case '\r':
|
||||
buf.WriteString(`\r`)
|
||||
case '\t':
|
||||
buf.WriteString(`\t`)
|
||||
case '\v':
|
||||
buf.WriteString(`\v`)
|
||||
case '"':
|
||||
buf.WriteString(`\"`)
|
||||
default:
|
||||
if unicode.IsPrint(rune(b)) {
|
||||
buf.WriteByte(b)
|
||||
} else {
|
||||
fmt.Fprintf(&buf, "\\x%02x", b)
|
||||
}
|
||||
}
|
||||
}
|
||||
buf.WriteByte('"')
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Printf(`/* Copyright (c) 2017, Google Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
/* This file is generated by:
|
||||
`)
|
||||
fmt.Printf(" * go run util/embed_test_data.go")
|
||||
for _, arg := range os.Args[1:] {
|
||||
fmt.Printf(" \\\n * %s", arg)
|
||||
}
|
||||
fmt.Printf(" */\n")
|
||||
|
||||
fmt.Printf(`
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
|
||||
`)
|
||||
|
||||
// MSVC limits the length of string constants, so we emit an array of
|
||||
// them and concatenate at runtime. We could also use a single array
|
||||
// literal, but this is less compact.
|
||||
const chunkSize = 8192
|
||||
|
||||
for i, arg := range os.Args[1:] {
|
||||
data, err := ioutil.ReadFile(arg)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error reading %s: %s.\n", data, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("static const char *kData%d[] = {\n", i)
|
||||
for i := 0; i < len(data); i += chunkSize {
|
||||
chunk := chunkSize
|
||||
if chunk > len(data)-i {
|
||||
chunk = len(data) - i
|
||||
}
|
||||
fmt.Printf(" %s,\n", quote(data[i:i+chunk]))
|
||||
}
|
||||
fmt.Printf("};\n")
|
||||
fmt.Printf("static const size_t kLen%d = %d;\n\n", i, len(data))
|
||||
}
|
||||
|
||||
fmt.Printf(`static std::string AssembleString(const char **data, size_t len) {
|
||||
std::string ret;
|
||||
for (size_t i = 0; i < len; i += %d) {
|
||||
size_t chunk = std::min(static_cast<size_t>(%d), len - i);
|
||||
ret.append(data[i / %d], chunk);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Silence -Wmissing-declarations. */
|
||||
std::string GetTestData(const char *path);
|
||||
|
||||
std::string GetTestData(const char *path) {
|
||||
`, chunkSize, chunkSize, chunkSize)
|
||||
for i, arg := range os.Args[1:] {
|
||||
fmt.Printf(" if (strcmp(path, %s) == 0) {\n", quote([]byte(arg)))
|
||||
fmt.Printf(" return AssembleString(kData%d, kLen%d);\n", i, i)
|
||||
fmt.Printf(" }\n")
|
||||
}
|
||||
fmt.Printf(` fprintf(stderr, "File not embedded: %%s.\n", path);
|
||||
abort();
|
||||
}
|
||||
`)
|
||||
|
||||
}
|
||||
@@ -486,8 +486,8 @@ def NoTestRunnerFiles(path, dent, is_dir):
|
||||
return not is_dir or dent != 'runner'
|
||||
|
||||
|
||||
def NotGTestMain(path, dent, is_dir):
|
||||
return dent != 'gtest_main.cc'
|
||||
def NotGTestSupport(path, dent, is_dir):
|
||||
return 'gtest' not in dent
|
||||
|
||||
|
||||
def SSLHeaderFiles(path, dent, is_dir):
|
||||
@@ -630,12 +630,42 @@ def WriteAsmFiles(perlasms):
|
||||
return asmfiles
|
||||
|
||||
|
||||
def ExtractVariablesFromCMakeFile(cmakefile):
|
||||
"""Parses the contents of the CMakeLists.txt file passed as an argument and
|
||||
returns a dictionary of exported source lists."""
|
||||
variables = {}
|
||||
in_set_command = False
|
||||
set_command = []
|
||||
with open(cmakefile) as f:
|
||||
for line in f:
|
||||
if '#' in line:
|
||||
line = line[:line.index('#')]
|
||||
line = line.strip()
|
||||
|
||||
if not in_set_command:
|
||||
if line.startswith('set('):
|
||||
in_set_command = True
|
||||
set_command = []
|
||||
elif line == ')':
|
||||
in_set_command = False
|
||||
if not set_command:
|
||||
raise ValueError('Empty set command')
|
||||
variables[set_command[0]] = set_command[1:]
|
||||
else:
|
||||
set_command.extend([c for c in line.split(' ') if c])
|
||||
|
||||
if in_set_command:
|
||||
raise ValueError('Unfinished set command')
|
||||
return variables
|
||||
|
||||
|
||||
def IsGTest(path):
|
||||
with open(path) as f:
|
||||
return "#include <gtest/gtest.h>" in f.read()
|
||||
|
||||
|
||||
def main(platforms):
|
||||
cmake = ExtractVariablesFromCMakeFile(os.path.join('src', 'sources.cmake'))
|
||||
crypto_c_files = FindCFiles(os.path.join('src', 'crypto'), NoTestsNorFIPSFragments)
|
||||
fips_fragments = FindCFiles(os.path.join('src', 'crypto', 'fipsmodule'), OnlyFIPSFragments)
|
||||
ssl_source_files = FindCFiles(os.path.join('src', 'ssl'), NoTests)
|
||||
@@ -650,13 +680,24 @@ def main(platforms):
|
||||
crypto_c_files.append('err_data.c')
|
||||
|
||||
test_support_c_files = FindCFiles(os.path.join('src', 'crypto', 'test'),
|
||||
NotGTestMain)
|
||||
NotGTestSupport)
|
||||
test_support_h_files = (
|
||||
FindHeaderFiles(os.path.join('src', 'crypto', 'test'), AllFiles) +
|
||||
FindHeaderFiles(os.path.join('src', 'ssl', 'test'), NoTestRunnerFiles))
|
||||
|
||||
# Generate crypto_test_data.cc
|
||||
with open('crypto_test_data.cc', 'w+') as out:
|
||||
subprocess.check_call(
|
||||
['go', 'run', 'util/embed_test_data.go'] + cmake['CRYPTO_TEST_DATA'],
|
||||
cwd='src',
|
||||
stdout=out)
|
||||
|
||||
test_c_files = []
|
||||
crypto_test_files = ['src/crypto/test/gtest_main.cc']
|
||||
crypto_test_files = [
|
||||
'crypto_test_data.cc',
|
||||
'src/crypto/test/file_test_gtest.cc',
|
||||
'src/crypto/test/gtest_main.cc',
|
||||
]
|
||||
# TODO(davidben): Remove this loop once all tests are converted.
|
||||
for path in FindCFiles(os.path.join('src', 'crypto'), OnlyTests):
|
||||
if IsGTest(path):
|
||||
|
||||
Reference in New Issue
Block a user