Start UI core layout value tests

This commit is contained in:
2026-06-01 00:07:55 +02:00
parent 31322bbd83
commit a67e7fc9bb
9 changed files with 171 additions and 8 deletions

View File

@@ -114,6 +114,18 @@ target_link_libraries(pp_renderer_api
PRIVATE PRIVATE
pp_project_warnings) pp_project_warnings)
add_library(pp_ui_core STATIC
src/ui_core/layout_value.cpp)
target_include_directories(pp_ui_core
PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/src")
target_link_libraries(pp_ui_core
PUBLIC
pp_foundation
pp_project_options
PRIVATE
pp_project_warnings)
if(PP_BUILD_TOOLS) if(PP_BUILD_TOOLS)
add_subdirectory(tools/pano_cli) add_subdirectory(tools/pano_cli)
endif() endif()

View File

@@ -75,8 +75,8 @@ Known local toolchain state:
- Android NDK: `C:\Users\omara\AppData\Local\Android\Sdk\ndk\29.0.14206865` - Android NDK: `C:\Users\omara\AppData\Local\Android\Sdk\ndk\29.0.14206865`
- Android arm64 headless configure/build passes through root CMake and the - Android arm64 headless configure/build passes through root CMake and the
`platform-build` automation wrapper for `pp_foundation`, `pp_assets`, `platform-build` automation wrapper for `pp_foundation`, `pp_assets`,
`pp_paint`, `pp_document`, `pp_renderer_api`, `pano_cli`, and their current `pp_paint`, `pp_document`, `pp_renderer_api`, `pp_ui_core`, `pano_cli`, and
headless test binaries. their current headless test binaries.
- `vcpkg` is not on PATH yet; see DEBT-0007. - `vcpkg` is not on PATH yet; see DEBT-0007.
Known warnings after the current CMake app build: Known warnings after the current CMake app build:

View File

@@ -307,9 +307,10 @@ PNG/JPEG signature detection and corrupt/truncated/unsupported tests.
`pp_paint` has started with CPU reference math for the five current shader `pp_paint` has started with CPU reference math for the five current shader
blend modes. `pp_document` has started with a pure canvas/layer model and blend modes. `pp_document` has started with a pure canvas/layer model and
layer invariant tests. `pp_renderer_api` has started with renderer-neutral layer invariant tests. `pp_renderer_api` has started with renderer-neutral
texture/readback descriptors and validation tests. Continue expanding document texture/readback descriptors and validation tests. `pp_ui_core` has started
behavior toward legacy Canvas parity and then port OpenGL classes behind the with XML-layout-facing length parsing and invalid input tests. Continue
renderer boundary. expanding document behavior toward legacy Canvas parity and then port OpenGL
classes behind the renderer boundary.
Implementation tasks: Implementation tasks:
@@ -513,7 +514,7 @@ Last verified on 2026-05-31:
```powershell ```powershell
cmake --preset windows-msvc-default cmake --preset windows-msvc-default
cmake --build --preset windows-msvc-default --config Debug --target pp_foundation_binary_stream_tests pp_foundation_parse_tests pp_foundation_trace_tests pp_assets_image_format_tests pp_paint_blend_tests pp_document_tests pp_renderer_api_tests pano_cli PanoPainter cmake --build --preset windows-msvc-default --config Debug --target pp_foundation_binary_stream_tests pp_foundation_parse_tests pp_foundation_trace_tests pp_assets_image_format_tests pp_paint_blend_tests pp_document_tests pp_renderer_api_tests pp_ui_core_layout_value_tests pano_cli PanoPainter
ctest --preset desktop-fast --build-config Debug ctest --preset desktop-fast --build-config Debug
powershell -ExecutionPolicy Bypass -File scripts\automation\test.ps1 -Preset desktop-fast -Configuration Debug powershell -ExecutionPolicy Bypass -File scripts\automation\test.ps1 -Preset desktop-fast -Configuration Debug
powershell -ExecutionPolicy Bypass -File scripts\automation\build.ps1 -Preset windows-msvc-default -Configuration Debug -Target pano_cli powershell -ExecutionPolicy Bypass -File scripts\automation\build.ps1 -Preset windows-msvc-default -Configuration Debug -Target pano_cli
@@ -530,6 +531,7 @@ Results:
- `pp_paint_blend_tests` passed. - `pp_paint_blend_tests` passed.
- `pp_document_tests` passed. - `pp_document_tests` passed.
- `pp_renderer_api_tests` passed. - `pp_renderer_api_tests` passed.
- `pp_ui_core_layout_value_tests` passed.
- `pano_cli_create_document_smoke` passed. - `pano_cli_create_document_smoke` passed.
- `pano_cli_inspect_image_rejects_unsupported` passed as an expected failure - `pano_cli_inspect_image_rejects_unsupported` passed as an expected failure
test. test.

View File

@@ -1,7 +1,7 @@
[CmdletBinding()] [CmdletBinding()]
param( param(
[string[]]$Presets = @("android-arm64"), [string[]]$Presets = @("android-arm64"),
[string[]]$Targets = @("pp_foundation", "pp_assets", "pp_paint", "pp_document", "pp_renderer_api", "pano_cli", "pp_foundation_binary_stream_tests", "pp_foundation_parse_tests", "pp_foundation_trace_tests", "pp_assets_image_format_tests", "pp_paint_blend_tests", "pp_document_tests", "pp_renderer_api_tests") [string[]]$Targets = @("pp_foundation", "pp_assets", "pp_paint", "pp_document", "pp_renderer_api", "pp_ui_core", "pano_cli", "pp_foundation_binary_stream_tests", "pp_foundation_parse_tests", "pp_foundation_trace_tests", "pp_assets_image_format_tests", "pp_paint_blend_tests", "pp_document_tests", "pp_renderer_api_tests", "pp_ui_core_layout_value_tests")
) )
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"

View File

@@ -3,7 +3,7 @@ set -u
preset="${1:-android-arm64}" preset="${1:-android-arm64}"
shift || true shift || true
targets="${*:-pp_foundation pp_assets pp_paint pp_document pp_renderer_api pano_cli pp_foundation_binary_stream_tests pp_foundation_parse_tests pp_foundation_trace_tests pp_assets_image_format_tests pp_paint_blend_tests pp_document_tests pp_renderer_api_tests}" targets="${*:-pp_foundation pp_assets pp_paint pp_document pp_renderer_api pp_ui_core pano_cli pp_foundation_binary_stream_tests pp_foundation_parse_tests pp_foundation_trace_tests pp_assets_image_format_tests pp_paint_blend_tests pp_document_tests pp_renderer_api_tests pp_ui_core_layout_value_tests}"
start="$(date +%s)" start="$(date +%s)"
cmake --preset "$preset" cmake --preset "$preset"

View File

@@ -0,0 +1,57 @@
#include "ui_core/layout_value.h"
#include "foundation/parse.h"
namespace pp::ui {
pp::foundation::Result<LayoutLength> parse_layout_length(std::string_view text) noexcept
{
if (text == "auto") {
return pp::foundation::Result<LayoutLength>::success(
LayoutLength { .kind = LayoutLengthKind::auto_value, .value = 0 });
}
if (text.empty()) {
return pp::foundation::Result<LayoutLength>::failure(
pp::foundation::Status::invalid_argument("layout length must not be empty"));
}
if (text.back() == '%') {
const auto number = pp::foundation::parse_u32(text.substr(0, text.size() - 1U));
if (!number) {
return pp::foundation::Result<LayoutLength>::failure(number.status());
}
if (number.value() > 100U) {
return pp::foundation::Result<LayoutLength>::failure(
pp::foundation::Status::out_of_range("layout percent must be between 0 and 100"));
}
return pp::foundation::Result<LayoutLength>::success(
LayoutLength { .kind = LayoutLengthKind::percent, .value = number.value() });
}
const auto pixels = pp::foundation::parse_u32(text);
if (!pixels) {
return pp::foundation::Result<LayoutLength>::failure(pixels.status());
}
return pp::foundation::Result<LayoutLength>::success(
LayoutLength { .kind = LayoutLengthKind::pixels, .value = pixels.value() });
}
const char* layout_length_kind_name(LayoutLengthKind kind) noexcept
{
switch (kind) {
case LayoutLengthKind::auto_value:
return "auto";
case LayoutLengthKind::pixels:
return "pixels";
case LayoutLengthKind::percent:
return "percent";
}
return "unknown";
}
}

View File

@@ -0,0 +1,24 @@
#pragma once
#include "foundation/result.h"
#include <cstdint>
#include <string_view>
namespace pp::ui {
enum class LayoutLengthKind : std::uint8_t {
auto_value,
pixels,
percent,
};
struct LayoutLength {
LayoutLengthKind kind = LayoutLengthKind::auto_value;
std::uint32_t value = 0;
};
[[nodiscard]] pp::foundation::Result<LayoutLength> parse_layout_length(std::string_view text) noexcept;
[[nodiscard]] const char* layout_length_kind_name(LayoutLengthKind kind) noexcept;
}

View File

@@ -76,6 +76,16 @@ add_test(NAME pp_renderer_api_tests COMMAND pp_renderer_api_tests)
set_tests_properties(pp_renderer_api_tests PROPERTIES set_tests_properties(pp_renderer_api_tests PROPERTIES
LABELS "renderer;desktop-fast") LABELS "renderer;desktop-fast")
add_executable(pp_ui_core_layout_value_tests
ui_core/layout_value_tests.cpp)
target_link_libraries(pp_ui_core_layout_value_tests PRIVATE
pp_ui_core
pp_test_harness)
add_test(NAME pp_ui_core_layout_value_tests COMMAND pp_ui_core_layout_value_tests)
set_tests_properties(pp_ui_core_layout_value_tests PROPERTIES
LABELS "ui;desktop-fast")
if(TARGET pano_cli) if(TARGET pano_cli)
add_test(NAME pano_cli_create_document_smoke add_test(NAME pano_cli_create_document_smoke
COMMAND pano_cli create-document --width 64 --height 32 --layers 2) COMMAND pano_cli create-document --width 64 --height 32 --layers 2)

View File

@@ -0,0 +1,58 @@
#include "ui_core/layout_value.h"
#include "test_harness.h"
#include <string_view>
using pp::foundation::StatusCode;
using pp::ui::LayoutLengthKind;
using pp::ui::layout_length_kind_name;
using pp::ui::parse_layout_length;
namespace {
void parses_auto_pixels_and_percent(pp::tests::Harness& h)
{
const auto auto_value = parse_layout_length("auto");
const auto pixels = parse_layout_length("28");
const auto percent = parse_layout_length("100%");
PP_EXPECT(h, auto_value.ok());
PP_EXPECT(h, auto_value.value().kind == LayoutLengthKind::auto_value);
PP_EXPECT(h, pixels.ok());
PP_EXPECT(h, pixels.value().kind == LayoutLengthKind::pixels);
PP_EXPECT(h, pixels.value().value == 28U);
PP_EXPECT(h, percent.ok());
PP_EXPECT(h, percent.value().kind == LayoutLengthKind::percent);
PP_EXPECT(h, percent.value().value == 100U);
PP_EXPECT(h, layout_length_kind_name(LayoutLengthKind::percent) == std::string_view("percent"));
}
void rejects_invalid_layout_lengths(pp::tests::Harness& h)
{
const auto empty = parse_layout_length("");
const auto negative = parse_layout_length("-1");
const auto trailing = parse_layout_length("28px");
const auto too_large_percent = parse_layout_length("101%");
const auto bare_percent = parse_layout_length("%");
PP_EXPECT(h, !empty.ok());
PP_EXPECT(h, empty.status().code == StatusCode::invalid_argument);
PP_EXPECT(h, !negative.ok());
PP_EXPECT(h, negative.status().code == StatusCode::invalid_argument);
PP_EXPECT(h, !trailing.ok());
PP_EXPECT(h, trailing.status().code == StatusCode::invalid_argument);
PP_EXPECT(h, !too_large_percent.ok());
PP_EXPECT(h, too_large_percent.status().code == StatusCode::out_of_range);
PP_EXPECT(h, !bare_percent.ok());
PP_EXPECT(h, bare_percent.status().code == StatusCode::invalid_argument);
}
}
int main()
{
pp::tests::Harness harness;
harness.run("parses_auto_pixels_and_percent", parses_auto_pixels_and_percent);
harness.run("rejects_invalid_layout_lengths", rejects_invalid_layout_lengths);
return harness.finish();
}