Add PPI dirty-face payload save automation

This commit is contained in:
2026-06-02 10:18:35 +02:00
parent 4f4ac380ac
commit a8faa82b70
9 changed files with 280 additions and 35 deletions

View File

@@ -5,6 +5,7 @@
#include <bit>
#include <cstddef>
#include <cstdint>
#include <span>
#include <string_view>
#include <vector>
@@ -392,6 +393,7 @@ void creates_minimal_project_for_roundtrip_load(pp::tests::Harness& h)
.height = 128,
.layer_name = "Roundtrip",
.frame_duration_ms = 333,
.dirty_faces = {},
});
PP_EXPECT(h, project.ok());
@@ -409,25 +411,90 @@ void creates_minimal_project_for_roundtrip_load(pp::tests::Harness& h)
PP_EXPECT(h, index.value().body.layers[0].frames[0].duration_ms == 333U);
}
void creates_minimal_project_with_dirty_face_payload(pp::tests::Harness& h)
{
const auto png_payload = transparent_png_1x1();
const pp::assets::PpiDirtyFacePayloadConfig dirty_faces[] {
{
.face_index = 2,
.x = 4,
.y = 5,
.width = 1,
.height = 1,
.png_rgba8 = std::span<const std::byte>(png_payload.data(), png_payload.size()),
},
};
const auto project = create_minimal_ppi_project(pp::assets::PpiMinimalProjectConfig {
.width = 256,
.height = 128,
.layer_name = "Payload",
.frame_duration_ms = 333,
.dirty_faces = std::span<const pp::assets::PpiDirtyFacePayloadConfig>(dirty_faces, 1),
});
PP_EXPECT(h, project.ok());
const auto decoded = decode_ppi_project_images(project.value());
PP_EXPECT(h, decoded.ok());
PP_EXPECT(h, decoded.value().project.body.summary.dirty_face_count == 1U);
PP_EXPECT(h, decoded.value().project.body.summary.rgba_face_payload_count == 1U);
PP_EXPECT(h, decoded.value().project.body.summary.compressed_face_bytes == png_payload.size());
PP_EXPECT(h, decoded.value().faces.size() == 1U);
PP_EXPECT(h, decoded.value().faces[0].face_index == 2U);
PP_EXPECT(h, decoded.value().faces[0].descriptor.x0 == 4U);
PP_EXPECT(h, decoded.value().faces[0].descriptor.y0 == 5U);
PP_EXPECT(h, decoded.value().faces[0].image.width == 1U);
PP_EXPECT(h, decoded.value().faces[0].image.height == 1U);
PP_EXPECT(h, decoded.value().faces[0].image.pixels.size() == 4U);
}
void rejects_invalid_minimal_project_writer_inputs(pp::tests::Harness& h)
{
const auto png_payload = transparent_png_1x1();
const pp::assets::PpiDirtyFacePayloadConfig duplicate_faces[] {
{
.face_index = 0,
.x = 0,
.y = 0,
.width = 1,
.height = 1,
.png_rgba8 = std::span<const std::byte>(png_payload.data(), png_payload.size()),
},
{
.face_index = 0,
.x = 1,
.y = 1,
.width = 1,
.height = 1,
.png_rgba8 = std::span<const std::byte>(png_payload.data(), png_payload.size()),
},
};
const auto no_size = create_minimal_ppi_project(pp::assets::PpiMinimalProjectConfig {
.width = 0,
.height = 128,
.layer_name = "Ink",
.frame_duration_ms = 100,
.dirty_faces = {},
});
const auto no_name = create_minimal_ppi_project(pp::assets::PpiMinimalProjectConfig {
.width = 128,
.height = 128,
.layer_name = "",
.frame_duration_ms = 100,
.dirty_faces = {},
});
const auto no_duration = create_minimal_ppi_project(pp::assets::PpiMinimalProjectConfig {
.width = 128,
.height = 128,
.layer_name = "Ink",
.frame_duration_ms = 0,
.dirty_faces = {},
});
const auto duplicate_dirty_face = create_minimal_ppi_project(pp::assets::PpiMinimalProjectConfig {
.width = 128,
.height = 128,
.layer_name = "Ink",
.frame_duration_ms = 100,
.dirty_faces = std::span<const pp::assets::PpiDirtyFacePayloadConfig>(duplicate_faces, 2),
});
PP_EXPECT(h, !no_size.ok());
@@ -436,6 +503,8 @@ void rejects_invalid_minimal_project_writer_inputs(pp::tests::Harness& h)
PP_EXPECT(h, no_name.status().code == StatusCode::invalid_argument);
PP_EXPECT(h, !no_duration.ok());
PP_EXPECT(h, no_duration.status().code == StatusCode::invalid_argument);
PP_EXPECT(h, !duplicate_dirty_face.ok());
PP_EXPECT(h, duplicate_dirty_face.status().code == StatusCode::invalid_argument);
}
}
@@ -456,6 +525,7 @@ int main()
harness.run("rejects_invalid_dirty_face_png_payloads", rejects_invalid_dirty_face_png_payloads);
harness.run("rejects_invalid_project_body_summaries", rejects_invalid_project_body_summaries);
harness.run("creates_minimal_project_for_roundtrip_load", creates_minimal_project_for_roundtrip_load);
harness.run("creates_minimal_project_with_dirty_face_payload", creates_minimal_project_with_dirty_face_payload);
harness.run("rejects_invalid_minimal_project_writer_inputs", rejects_invalid_minimal_project_writer_inputs);
return harness.finish();
}