-// Copyright (C) 2010-2025 Joel Rosdahl and other contributors
+// Copyright (C) 2010-2026 Joel Rosdahl and other contributors
//
// See doc/authors.adoc for a complete list of contributors.
//
#include <ccache/hash.hpp>
#include <ccache/hashutil.hpp>
+#include <ccache/util/cpu.hpp>
#include <ccache/util/file.hpp>
#include <ccache/util/format.hpp>
#endif
}
-TEST_SUITE_BEGIN("hashutil");
-
-TEST_CASE("hash_command_output_simple")
-{
- TestContext test_context;
-
- Hash h1;
- Hash h2;
-
- CHECK(hco(h1, "echo", "not used"));
- CHECK(hco(h2, "echo", "not used"));
- CHECK(h1.digest() == h2.digest());
-}
-
-TEST_CASE("hash_command_output_space_removal")
-{
- TestContext test_context;
-
- Hash h1;
- Hash h2;
-
- CHECK(hco(h1, "echo", "not used"));
- CHECK(hco(h2, " echo ", "not used"));
- CHECK(h1.digest() == h2.digest());
-}
+using SourceCodePatternChecker = HashSourceCodeResult (*)(std::string_view);
-TEST_CASE("hash_command_output_hash_inequality")
-{
- TestContext test_context;
-
- Hash h1;
- Hash h2;
-
- CHECK(hco(h1, "echo foo", "not used"));
- CHECK(hco(h2, "echo bar", "not used"));
- CHECK(h1.digest() != h2.digest());
-}
-
-TEST_CASE("hash_command_output_compiler_substitution")
-{
- TestContext test_context;
-
- Hash h1;
- Hash h2;
-
- CHECK(hco(h1, "echo foo", "not used"));
-#ifdef _WIN32
- REQUIRE(util::write_file("command.bat", "@echo off\r\necho foo\r\n"));
- CHECK(hash_command_output(h2, "%compiler%", "command.bat"));
-#else
- CHECK(hash_command_output(h2, "%compiler% foo", "echo"));
-#endif
- CHECK(h1.digest() == h2.digest());
-}
-
-TEST_CASE("hash_command_output_stdout_versus_stderr")
+static void
+check_temporal_macros(SourceCodePatternChecker check)
{
- TestContext test_context;
-
- Hash h1;
- Hash h2;
-
-#ifdef _WIN32
- REQUIRE(util::write_file("stderr.bat", "@echo off\r\necho foo>&2\r\n"));
- CHECK(hco(h1, "echo foo", "not used"));
- CHECK(hco(h2, "stderr.bat", "not used"));
-#else
- CHECK(hco(h1, "echo foo", "not used"));
- CHECK(hco(h2, "echo foo >&2", "not used"));
-#endif
- CHECK(h1.digest() == h2.digest());
-}
-
-TEST_CASE("hash_multicommand_output")
-{
- TestContext test_context;
-
- Hash h1;
- Hash h2;
-
-#ifdef _WIN32
- h2.hash("foo\r\nbar\r\n");
- REQUIRE(util::write_file("foo.bat", "@echo off\r\necho foo\r\n"));
- REQUIRE(util::write_file("bar.bat", "@echo off\r\necho bar\r\n"));
- CHECK(hash_multicommand_output(h1, "foo.bat; bar.bat", "not used"));
-#else
- h2.hash("foo\nbar\n");
- CHECK(hash_multicommand_output(h1, "echo foo; echo bar", "not used"));
- CHECK(h1.digest() == h2.digest());
-#endif
-}
-
-TEST_CASE("hash_multicommand_output_error_handling")
-{
- TestContext test_context;
-
- Hash h1;
- Hash h2;
-
- CHECK(!hash_multicommand_output(h2, "false; true", "not used"));
-}
-
-TEST_CASE("check_for_temporal_macros")
-{
- TestContext test_context;
-
const std::string_view time_start =
"__TIME__\n"
"int a;\n";
"#define alphabet abcdefghijklmnopqrstuvwxyz\n"
"a__DATE__";
- auto check = check_for_temporal_macros;
-
CHECK(check(time_start).contains(HashSourceCode::found_time));
CHECK(check(time_start.substr(1)).empty());
}
}
+TEST_SUITE_BEGIN("hashutil");
+
+TEST_CASE("hash_command_output_simple")
+{
+ TestContext test_context;
+
+ Hash h1;
+ Hash h2;
+
+ CHECK(hco(h1, "echo", "not used"));
+ CHECK(hco(h2, "echo", "not used"));
+ CHECK(h1.digest() == h2.digest());
+}
+
+TEST_CASE("hash_command_output_space_removal")
+{
+ TestContext test_context;
+
+ Hash h1;
+ Hash h2;
+
+ CHECK(hco(h1, "echo", "not used"));
+ CHECK(hco(h2, " echo ", "not used"));
+ CHECK(h1.digest() == h2.digest());
+}
+
+TEST_CASE("hash_command_output_hash_inequality")
+{
+ TestContext test_context;
+
+ Hash h1;
+ Hash h2;
+
+ CHECK(hco(h1, "echo foo", "not used"));
+ CHECK(hco(h2, "echo bar", "not used"));
+ CHECK(h1.digest() != h2.digest());
+}
+
+TEST_CASE("hash_command_output_compiler_substitution")
+{
+ TestContext test_context;
+
+ Hash h1;
+ Hash h2;
+
+ CHECK(hco(h1, "echo foo", "not used"));
+#ifdef _WIN32
+ REQUIRE(util::write_file("command.bat", "@echo off\r\necho foo\r\n"));
+ CHECK(hash_command_output(h2, "%compiler%", "command.bat"));
+#else
+ CHECK(hash_command_output(h2, "%compiler% foo", "echo"));
+#endif
+ CHECK(h1.digest() == h2.digest());
+}
+
+TEST_CASE("hash_command_output_stdout_versus_stderr")
+{
+ TestContext test_context;
+
+ Hash h1;
+ Hash h2;
+
+#ifdef _WIN32
+ REQUIRE(util::write_file("stderr.bat", "@echo off\r\necho foo>&2\r\n"));
+ CHECK(hco(h1, "echo foo", "not used"));
+ CHECK(hco(h2, "stderr.bat", "not used"));
+#else
+ CHECK(hco(h1, "echo foo", "not used"));
+ CHECK(hco(h2, "echo foo >&2", "not used"));
+#endif
+ CHECK(h1.digest() == h2.digest());
+}
+
+TEST_CASE("hash_multicommand_output")
+{
+ TestContext test_context;
+
+ Hash h1;
+ Hash h2;
+
+#ifdef _WIN32
+ h2.hash("foo\r\nbar\r\n");
+ REQUIRE(util::write_file("foo.bat", "@echo off\r\necho foo\r\n"));
+ REQUIRE(util::write_file("bar.bat", "@echo off\r\necho bar\r\n"));
+ CHECK(hash_multicommand_output(h1, "foo.bat; bar.bat", "not used"));
+#else
+ h2.hash("foo\nbar\n");
+ CHECK(hash_multicommand_output(h1, "echo foo; echo bar", "not used"));
+ CHECK(h1.digest() == h2.digest());
+#endif
+}
+
+TEST_CASE("hash_multicommand_output_error_handling")
+{
+ TestContext test_context;
+
+ Hash h1;
+ Hash h2;
+
+ CHECK(!hash_multicommand_output(h2, "false; true", "not used"));
+}
+
+TEST_CASE("check_for_temporal_macros")
+{
+ TestContext test_context;
+
+ SUBCASE("scalar")
+ {
+ check_temporal_macros(check_for_source_code_patterns_scalar);
+ }
+
+#ifdef HAVE_AVX2
+ if (util::cpu_supports_avx2()) {
+ SUBCASE("avx2")
+ {
+ check_temporal_macros(check_for_source_code_patterns_avx2);
+ }
+ }
+#endif
+}
+
TEST_SUITE_END();