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>kris/onging/CECPQ3_patch15
@@ -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; | |||
} | |||
if (plaintext.size() != AES_BLOCK_SIZE || | |||
ciphertext.size() != AES_BLOCK_SIZE) { | |||
t->PrintLine("Plaintext or Ciphertext not a block size."); | |||
return false; | |||
} | |||
ASSERT_TRUE(t->GetBytes(&key, "Key")); | |||
ASSERT_TRUE(t->GetBytes(&plaintext, "Plaintext")); | |||
ASSERT_TRUE(t->GetBytes(&ciphertext, "Ciphertext")); | |||
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; | |||
} | |||
if (AES_set_decrypt_key(key.data(), 8 * key.size(), &aes_key) != 0) { | |||
t->PrintLine("AES_set_decrypt_key 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))); | |||
// 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; | |||
} | |||
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; | |||
EXPECT_EQ(-1, AES_unwrap_key(&aes_key, nullptr /* iv */, buf.get(), | |||
ciphertext.data(), ciphertext.size())); | |||
} | |||
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): | |||