diff --git a/cmake/tests.cmake b/cmake/tests.cmake index bcdbeaf2..5241d78b 100644 --- a/cmake/tests.cmake +++ b/cmake/tests.cmake @@ -36,6 +36,7 @@ set(LIBLOOT_SRC_TESTS_INTERNALS_CPP_FILES "${CMAKE_SOURCE_DIR}/src/tests/api/internals/main.cpp") set(LIBLOOT_SRC_TESTS_INTERNALS_H_FILES + "${CMAKE_SOURCE_DIR}/src/tests/api/internals/bsa_test.h" "${CMAKE_SOURCE_DIR}/src/tests/api/internals/game/game_test.h" "${CMAKE_SOURCE_DIR}/src/tests/api/internals/game/game_cache_test.h" "${CMAKE_SOURCE_DIR}/src/tests/api/internals/game/load_order_handler_test.h" diff --git a/src/api/bsa.cpp b/src/api/bsa.cpp index 75aed9e6..dab45365 100644 --- a/src/api/bsa.cpp +++ b/src/api/bsa.cpp @@ -217,8 +217,9 @@ std::map> GetAssetsInBA2(std::istream& in, throw std::runtime_error("BA2 file header type ID is invalid"); } - // The header version is 1 for Fallout 4 and 2 or 3 for Starfield. - if (header.version != 1 && header.version != 2 && header.version != 3) { + // The header version is 1, 7 or 8 for Fallout 4 and 2 or 3 for Starfield. + if (header.version != 1 && header.version != 2 && header.version != 3 && + header.version != 7 && header.version != 8) { throw std::runtime_error("BA2 file header version is invalid"); } diff --git a/src/tests/api/internals/bsa_test.h b/src/tests/api/internals/bsa_test.h index 9514beef..6f9eb119 100644 --- a/src/tests/api/internals/bsa_test.h +++ b/src/tests/api/internals/bsa_test.h @@ -27,6 +27,10 @@ along with LOOT. If not, see #include +#include +#include +#include + #include "api/bsa.h" namespace loot::test { @@ -133,6 +137,48 @@ TEST(GetAssetsInBethesdaArchive, shouldSupportTextureBA2s) { EXPECT_EQ(1, assets.find(folderHash)->second.count(fileHash)); } +class GetAssetsInBethesdaArchive_BA2Version + : public ::testing::TestWithParam { +protected: + GetAssetsInBethesdaArchive_BA2Version() : path(GetArchivePath()) { + const auto sourcePath = + std::filesystem::u8path("./Fallout 4/Data/Blank - Main.ba2"); + std::filesystem::copy(sourcePath, path); + + std::fstream stream( + path, std::ios_base::binary | std::ios_base::in | std::ios_base::out); + stream.seekp(4); + stream.put(GetParam()); + stream.close(); + } + + void TearDown() override { std::filesystem::remove(path); } + + const std::filesystem::path path; + +private: + std::filesystem::path GetArchivePath() { + const auto tempFilename = + "LOOT-test-" + + boost::lexical_cast((boost::uuids::random_generator())()) + + ".ba2"; + + return std::filesystem::temp_directory_path() / tempFilename; + } +}; + +// Pass an empty first argument, as it's a prefix for the test instantation, +// but we only have the one so no prefix is necessary. +INSTANTIATE_TEST_SUITE_P(, + GetAssetsInBethesdaArchive_BA2Version, + ::testing::Values(1, 2, 3, 7, 8)); + +TEST_P(GetAssetsInBethesdaArchive_BA2Version, shouldSupportBA2Version) { + const auto assets = GetAssetsInBethesdaArchive(path); + + EXPECT_FALSE(assets.empty()); +} + TEST(GetAssetsInBethesdaArchives, shouldSkipFilesThatCannotBeRead) { std::vector paths( {std::filesystem::u8path("invalid.bsa"),