#include "assets/brush_package.h" #include "test_harness.h" #include #include #include #include namespace { std::array ppbr_header(std::uint16_t major, std::uint16_t minor) { return { std::byte { 'P' }, std::byte { 'P' }, std::byte { 'B' }, std::byte { 'R' }, static_cast(major & 0xffU), static_cast((major >> 8U) & 0xffU), static_cast(minor & 0xffU), static_cast((minor >> 8U) & 0xffU), }; } void parses_ppbr_header_and_legacy_version_tolerance(pp::tests::Harness& harness) { const auto canonical_bytes = ppbr_header(0, 1); const auto canonical = pp::assets::parse_ppbr_header(canonical_bytes); PP_EXPECT(harness, canonical); PP_EXPECT(harness, canonical.value().major == 0U); PP_EXPECT(harness, canonical.value().minor == 1U); const auto minor_tolerated_bytes = ppbr_header(0, 2); const auto major_tolerated_bytes = ppbr_header(1, 1); const auto rejected_bytes = ppbr_header(1, 2); const auto legacy_minor_tolerated = pp::assets::parse_ppbr_header(minor_tolerated_bytes); const auto legacy_major_tolerated = pp::assets::parse_ppbr_header(major_tolerated_bytes); const auto rejected = pp::assets::parse_ppbr_header(rejected_bytes); PP_EXPECT(harness, legacy_minor_tolerated); PP_EXPECT(harness, legacy_major_tolerated); PP_EXPECT(harness, !rejected); } void rejects_truncated_and_bad_magic_headers(pp::tests::Harness& harness) { const std::array truncated { std::byte { 'P' }, std::byte { 'P' }, std::byte { 'B' }, std::byte { 'R' }, }; auto bad_magic = ppbr_header(0, 1); bad_magic[2] = std::byte { 'X' }; const auto truncated_result = pp::assets::parse_ppbr_header(truncated); const auto magic_result = pp::assets::parse_ppbr_header(bad_magic); PP_EXPECT(harness, !truncated_result); PP_EXPECT(harness, truncated_result.status().code == pp::foundation::StatusCode::out_of_range); PP_EXPECT(harness, !magic_result); PP_EXPECT(harness, magic_result.status().code == pp::foundation::StatusCode::invalid_argument); } void plans_export_package_and_data_paths(pp::tests::Harness& harness) { const auto regular = pp::assets::plan_ppbr_export_paths( "D:/Paint/clouds", "", true, pp::assets::PpbrDataDirectoryPolicy::next_to_package); PP_EXPECT(harness, regular); if (regular) { PP_EXPECT(harness, regular.value().package_path == "D:/Paint/clouds.ppbr"); PP_EXPECT(harness, regular.value().directory == "D:/Paint"); PP_EXPECT(harness, regular.value().stem == "clouds"); PP_EXPECT(harness, regular.value().extension == "ppbr"); PP_EXPECT(harness, regular.value().data_directory == "D:/Paint/clouds_data"); PP_EXPECT(harness, regular.value().data_directory_enabled); } const auto override = pp::assets::plan_ppbr_export_paths( "/brushes/clouds.ppbr", "/Users/artist/Exports", true, pp::assets::PpbrDataDirectoryPolicy::override_directory); PP_EXPECT(harness, override); if (override) { PP_EXPECT(harness, override.value().data_directory == "/Users/artist/Exports/clouds_data"); PP_EXPECT(harness, override.value().data_directory_enabled); } const auto no_data = pp::assets::plan_ppbr_export_paths( "D:/Paint/clouds.ppbr", "", false, pp::assets::PpbrDataDirectoryPolicy::next_to_package); PP_EXPECT(harness, no_data); if (no_data) { PP_EXPECT(harness, !no_data.value().data_directory_enabled); } } void preserves_legacy_extension_containment_rule(pp::tests::Harness& harness) { const auto path = pp::assets::normalize_ppbr_export_path("D:/Paint/clouds.ppbr.tmp"); PP_EXPECT(harness, path); PP_EXPECT(harness, path.value() == "D:/Paint/clouds.ppbr.tmp"); } void rejects_export_paths_that_legacy_regex_could_not_match(pp::tests::Harness& harness) { PP_EXPECT( harness, !pp::assets::plan_ppbr_export_paths( "", "", true, pp::assets::PpbrDataDirectoryPolicy::next_to_package)); PP_EXPECT( harness, !pp::assets::plan_ppbr_export_paths( "clouds", "", true, pp::assets::PpbrDataDirectoryPolicy::next_to_package)); PP_EXPECT( harness, !pp::assets::plan_ppbr_export_paths( "D:/Paint/.ppbr", "", true, pp::assets::PpbrDataDirectoryPolicy::next_to_package)); PP_EXPECT( harness, !pp::assets::plan_ppbr_export_paths( "D:/Paint/clouds.ppbr!", "", true, pp::assets::PpbrDataDirectoryPolicy::next_to_package)); } void plans_imported_brush_image_targets(pp::tests::Harness& harness) { const auto brush = pp::assets::plan_brush_package_image_target_paths( "D:/Paint/data", pp::assets::BrushPackageImageKind::brush_tip, "cloud", "png"); PP_EXPECT(harness, brush); if (brush) { PP_EXPECT(harness, brush.value().image_path == "D:/Paint/data/brushes/cloud.png"); PP_EXPECT(harness, brush.value().thumbnail_path == "D:/Paint/data/brushes/thumbs/cloud.png"); } const auto pattern = pp::assets::plan_brush_package_image_target_paths( "D:/Paint/data", pp::assets::BrushPackageImageKind::pattern, "paper", "jpg"); PP_EXPECT(harness, pattern); if (pattern) { PP_EXPECT(harness, pattern.value().image_path == "D:/Paint/data/patterns/paper.jpg"); PP_EXPECT(harness, pattern.value().thumbnail_path == "D:/Paint/data/patterns/thumbs/paper.jpg"); } } void rejects_invalid_imported_brush_image_targets(pp::tests::Harness& harness) { PP_EXPECT( harness, !pp::assets::plan_brush_package_image_target_paths( "", pp::assets::BrushPackageImageKind::brush_tip, "cloud", "png")); PP_EXPECT( harness, !pp::assets::plan_brush_package_image_target_paths( "D:/Paint/data", pp::assets::BrushPackageImageKind::brush_tip, "", "png")); PP_EXPECT( harness, !pp::assets::plan_brush_package_image_target_paths( "D:/Paint/data", pp::assets::BrushPackageImageKind::pattern, "paper", "png!")); } } // namespace int main() { pp::tests::Harness harness; harness.run("parses PPBR header and legacy version tolerance", parses_ppbr_header_and_legacy_version_tolerance); harness.run("rejects truncated and bad magic headers", rejects_truncated_and_bad_magic_headers); harness.run("plans export package and data paths", plans_export_package_and_data_paths); harness.run("preserves legacy extension containment rule", preserves_legacy_extension_containment_rule); harness.run("rejects export paths that legacy regex could not match", rejects_export_paths_that_legacy_regex_could_not_match); harness.run("plans imported brush image targets", plans_imported_brush_image_targets); harness.run("rejects invalid imported brush image targets", rejects_invalid_imported_brush_image_targets); return harness.finish(); }