// Copyright (C) 2020-2023 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // // This program is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the Free // Software Foundation; either version 3 of the License, or (at your option) // any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with // this program; if not, write to the Free Software Foundation, Inc., 51 // Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "../src/Config.hpp" #include "../src/Context.hpp" #include "../src/Hash.hpp" #include "../src/InodeCache.hpp" #include "../src/Util.hpp" #include "TestUtil.hpp" #include #include #include "third_party/doctest.h" #include #include #include using TestUtil::TestContext; namespace { bool inode_cache_available() { Fd fd(open(Util::get_actual_cwd().c_str(), O_RDONLY)); return fd && InodeCache::available(*fd); } void init(Config& config) { config.set_debug(true); config.set_inode_cache(true); config.set_temporary_dir(Util::get_actual_cwd()); } bool put(InodeCache& inode_cache, const std::string& filename, const std::string& str, HashSourceCodeResult return_value) { return inode_cache.put(filename, InodeCache::ContentType::checked_for_temporal_macros, Hash().hash(str).digest(), return_value); } } // namespace TEST_SUITE_BEGIN("InodeCache" * doctest::skip(!inode_cache_available())); TEST_CASE("Test disabled") { TestContext test_context; Config config; init(config); config.set_inode_cache(false); InodeCache inode_cache(config, util::Duration(0)); Digest digest; CHECK(!inode_cache.get( "a", InodeCache::ContentType::checked_for_temporal_macros, digest)); CHECK(!inode_cache.put("a", InodeCache::ContentType::checked_for_temporal_macros, digest, HashSourceCodeResult())); CHECK(inode_cache.get_hits() == -1); CHECK(inode_cache.get_misses() == -1); CHECK(inode_cache.get_errors() == -1); } TEST_CASE("Test lookup nonexistent") { TestContext test_context; Config config; init(config); InodeCache inode_cache(config, util::Duration(0)); util::write_file("a", ""); Digest digest; CHECK(!inode_cache.get( "a", InodeCache::ContentType::checked_for_temporal_macros, digest)); CHECK(inode_cache.get_hits() == 0); CHECK(inode_cache.get_misses() == 1); CHECK(inode_cache.get_errors() == 0); } TEST_CASE("Test put and lookup") { TestContext test_context; Config config; init(config); InodeCache inode_cache(config, util::Duration(0)); util::write_file("a", "a text"); HashSourceCodeResult result; result.insert(HashSourceCode::found_date); CHECK(put(inode_cache, "a", "a text", result)); Digest digest; auto return_value = inode_cache.get( "a", InodeCache::ContentType::checked_for_temporal_macros, digest); REQUIRE(return_value); CHECK(digest == Hash().hash("a text").digest()); CHECK(return_value->to_bitmask() == static_cast(HashSourceCode::found_date)); CHECK(inode_cache.get_hits() == 1); CHECK(inode_cache.get_misses() == 0); CHECK(inode_cache.get_errors() == 0); util::write_file("a", "something else"); CHECK(!inode_cache.get( "a", InodeCache::ContentType::checked_for_temporal_macros, digest)); CHECK(inode_cache.get_hits() == 1); CHECK(inode_cache.get_misses() == 1); CHECK(inode_cache.get_errors() == 0); CHECK(put(inode_cache, "a", "something else", HashSourceCodeResult(HashSourceCode::found_time))); return_value = inode_cache.get( "a", InodeCache::ContentType::checked_for_temporal_macros, digest); REQUIRE(return_value); CHECK(digest == Hash().hash("something else").digest()); CHECK(return_value->to_bitmask() == static_cast(HashSourceCode::found_time)); CHECK(inode_cache.get_hits() == 2); CHECK(inode_cache.get_misses() == 1); CHECK(inode_cache.get_errors() == 0); } TEST_CASE("Drop file") { TestContext test_context; Config config; init(config); InodeCache inode_cache(config, util::Duration(0)); Digest digest; inode_cache.get("a", InodeCache::ContentType::raw, digest); CHECK(Stat::stat(inode_cache.get_file())); CHECK(inode_cache.drop()); CHECK(!Stat::stat(inode_cache.get_file())); CHECK(inode_cache.drop()); } TEST_CASE("Test content type") { TestContext test_context; Config config; init(config); InodeCache inode_cache(config, util::Duration(0)); util::write_file("a", "a text"); Digest binary_digest = Hash().hash("binary").digest(); Digest code_digest = Hash().hash("code").digest(); CHECK(inode_cache.put("a", InodeCache::ContentType::raw, binary_digest, HashSourceCodeResult(HashSourceCode::found_date))); CHECK(inode_cache.put("a", InodeCache::ContentType::checked_for_temporal_macros, code_digest, HashSourceCodeResult(HashSourceCode::found_time))); Digest digest; auto return_value = inode_cache.get("a", InodeCache::ContentType::raw, digest); REQUIRE(return_value); CHECK(digest == binary_digest); CHECK(return_value->to_bitmask() == static_cast(HashSourceCode::found_date)); return_value = inode_cache.get( "a", InodeCache::ContentType::checked_for_temporal_macros, digest); REQUIRE(return_value); CHECK(digest == code_digest); CHECK(return_value->to_bitmask() == static_cast(HashSourceCode::found_time)); } TEST_SUITE_END();