#include "node_builtins.h"
#include "node_threadsafe_cow-inl.h"
#include "gtest/gtest.h"
#include "node_test_fixture.h"
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
using node::builtins::BuiltinCodeCacheData;
using node::builtins::BuiltinLoader;
using node::builtins::BuiltinSourceMap;
using node::builtins::CodeCacheInfo;
class PerProcessTest : public ::testing::Test {
protected:
static const BuiltinSourceMap get_sources_for_test() {
return *BuiltinLoader().source_.read();
}
// id -> first byte of the cached data, after feeding `batches` in order.
static std::vector<std::pair<std::string, uint8_t>> RefreshCodeCacheWith(
const std::vector<std::vector<CodeCacheInfo>>& batches) {
BuiltinLoader loader;
for (const auto& batch : batches) loader.RefreshCodeCache(batch);
std::vector<std::pair<std::string, uint8_t>> out;
node::RwLock::ScopedReadLock lock(loader.code_cache_->mutex);
EXPECT_TRUE(loader.code_cache_->has_code_cache);
for (const auto& [id, data] : loader.code_cache_->map) {
out.emplace_back(id, data.data[0]);
}
std::sort(out.begin(), out.end());
return out;
}
};
CodeCacheInfo MakeCodeCacheInfo(const std::string& id, uint8_t marker) {
auto* bytes = new uint8_t[4]{marker, marker, marker, marker};
auto cached_data = std::make_shared<v8::ScriptCompiler::CachedData>(
bytes, 4, v8::ScriptCompiler::CachedData::BufferOwned);
return CodeCacheInfo{id, BuiltinCodeCacheData(std::move(cached_data))};
}
namespace {
TEST_F(PerProcessTest, EmbeddedSources) {
const auto& sources = PerProcessTest::get_sources_for_test();
ASSERT_TRUE(std::any_of(sources.cbegin(), sources.cend(), [](auto p) {
return p.second.source.is_one_byte();
})) << "BuiltinLoader::source_ should have some 8bit items";
ASSERT_TRUE(std::any_of(sources.cbegin(), sources.cend(), [](auto p) {
return !p.second.source.is_one_byte();
})) << "BuiltinLoader::source_ should have some 16bit items";
}
// RefreshCodeCache() merges: it can be fed the snapshot's code cache and then
// an embedder's, and the entry supplied last wins for a shared id.
TEST_F(PerProcessTest, RefreshCodeCacheMerges) {
const auto merged = PerProcessTest::RefreshCodeCacheWith({
{MakeCodeCacheInfo("internal/a", 1), MakeCodeCacheInfo("internal/b", 1)},
{MakeCodeCacheInfo("internal/b", 2), MakeCodeCacheInfo("embedder/c", 2)},
});
const std::vector<std::pair<std::string, uint8_t>> expected = {
{"embedder/c", 2}, {"internal/a", 1}, {"internal/b", 2}};
EXPECT_EQ(merged, expected);
// A single call still behaves as before.
const auto single = PerProcessTest::RefreshCodeCacheWith(
{{MakeCodeCacheInfo("internal/a", 7)}});
ASSERT_EQ(single.size(), 1u);
EXPECT_EQ(single[0].second, 7);
}
} // end namespace