Skip to content

Commit aeb3727

Browse files
committed
[#30]:svarga:backend, PB fixture tests with golden baselines
1 parent 27f0181 commit aeb3727

14 files changed

Lines changed: 323 additions & 0 deletions

tests/CMakeLists.txt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,35 @@ function(add_h5cpp_fixture_test name)
3030
)
3131
endfunction()
3232

33+
function(add_h5cpp_backend_fixture_test name backend)
34+
set(golden "${GOLDEN_DIR}/${name}.${backend}.expected")
35+
add_test(
36+
NAME h5cpp.${name}
37+
COMMAND
38+
${CMAKE_COMMAND}
39+
"-DH5CPP_BIN=$<TARGET_FILE:h5cpp>"
40+
"-DFIXTURE=${CMAKE_CURRENT_SOURCE_DIR}/fixtures/${name}.cpp"
41+
"-DSTUB_DIR=${STUB_DIR}"
42+
"-DGOLDEN=${golden}"
43+
"-DBACKEND_FORMAT=${backend}"
44+
"-DOUTPUT_DIR=${CMAKE_CURRENT_BINARY_DIR}"
45+
-P "${RUN_FIXTURE}"
46+
)
47+
endfunction()
48+
3349
foreach(fixture IN LISTS FIXTURES)
3450
add_h5cpp_fixture_test(${fixture})
3551
endforeach()
52+
53+
set(PB_FIXTURES
54+
pb_primitives
55+
pb_strings_enums
56+
pb_composites
57+
pb_variant
58+
pb_wire_specs
59+
pb_chrono
60+
)
61+
62+
foreach(fixture IN LISTS PB_FIXTURES)
63+
add_h5cpp_backend_fixture_test(${fixture} protobuf)
64+
endforeach()

tests/fixtures/pb_chrono.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include "pb_stub.hpp"
2+
3+
#include <chrono>
4+
#include <cstdint>
5+
6+
// Tier-4 fixture (stage 6): chrono adapter annotation. A user struct with
7+
// std::chrono::system_clock::time_point + std::chrono::nanoseconds members
8+
// gets pb::adapter_field<N, Ptr, pb::Timestamp_adapter> / Duration_adapter
9+
// entries in the emitted descriptor. The library bridges the C++ types
10+
// to proto3 google.protobuf.Timestamp / Duration wire messages.
11+
namespace sn::pb_test {
12+
13+
struct event_t {
14+
[[clang::annotate("pb::field=1")]]
15+
std::int64_t id;
16+
17+
[[clang::annotate("pb::field=2")]]
18+
[[clang::annotate("pb::adapter=Timestamp")]]
19+
std::chrono::system_clock::time_point when;
20+
21+
[[clang::annotate("pb::field=3")]]
22+
[[clang::annotate("pb::adapter=Duration")]]
23+
std::chrono::nanoseconds ttl;
24+
};
25+
26+
} // namespace sn::pb_test
27+
28+
void use() {
29+
sn::pb_test::event_t e{};
30+
auto buf = pb::encode(e);
31+
(void)buf;
32+
}

tests/fixtures/pb_composites.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include "pb_stub.hpp"
2+
3+
#include <cstdint>
4+
#include <optional>
5+
#include <string>
6+
#include <vector>
7+
8+
// Tier-3 fixture (stage 3): composite shapes — std::vector (repeated),
9+
// std::optional (proto3 optional explicit presence). The compiler emits the
10+
// same pb::field<N, &T::m>{} entries; pb.hpp's trait dispatch handles the
11+
// shape at compile time via is_pb_repeated_v and is_pb_optional_v.
12+
//
13+
// stdlib types are NOT walked into for descriptor emission (only the outer
14+
// user record gets a descriptor_t<>).
15+
namespace sn::pb_test {
16+
17+
struct profile_t {
18+
[[clang::annotate("pb::field=1")]] std::string name;
19+
[[clang::annotate("pb::field=2")]] std::vector<std::int32_t> scores;
20+
[[clang::annotate("pb::field=3")]] std::optional<std::string> nickname;
21+
[[clang::annotate("pb::field=4")]] std::vector<std::string> aliases;
22+
[[clang::annotate("pb::field=5")]] std::optional<std::int64_t> user_id;
23+
};
24+
25+
} // namespace sn::pb_test
26+
27+
void use() {
28+
sn::pb_test::profile_t p{};
29+
auto buf = pb::encode(p);
30+
(void)buf;
31+
}

tests/fixtures/pb_primitives.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include "pb_stub.hpp"
2+
3+
#include <cstdint>
4+
5+
// Tier-1 fixture: numeric scalars only. Every member carries
6+
// [[clang::annotate("pb::field=N")]]; the compiler emits a
7+
// pb::meta::descriptor_t<T> specialization with one pb::field<N,&T::m>{}
8+
// entry per member, in source-declaration order.
9+
namespace sn::pb_test {
10+
struct primitives_t {
11+
[[clang::annotate("pb::field=1")]] bool _bool;
12+
[[clang::annotate("pb::field=2")]] std::int32_t _i32;
13+
[[clang::annotate("pb::field=3")]] std::int64_t _i64;
14+
[[clang::annotate("pb::field=4")]] std::uint32_t _u32;
15+
[[clang::annotate("pb::field=5")]] std::uint64_t _u64;
16+
[[clang::annotate("pb::field=6")]] float _f;
17+
[[clang::annotate("pb::field=7")]] double _d;
18+
};
19+
} // namespace sn::pb_test
20+
21+
void use() {
22+
sn::pb_test::primitives_t p{};
23+
auto buf = pb::encode(p);
24+
(void)buf;
25+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include "pb_stub.hpp"
2+
3+
#include <cstdint>
4+
#include <string>
5+
6+
// Tier-1 fixture (stage 2): non-POD members — std::string is the canonical
7+
// length-delimited scalar; enum class is the canonical proto3 enum mapping.
8+
// The compiler emits a single descriptor_t<log_entry_t> with one pb::field
9+
// entry per member; std::string is NOT walked into (it's a stdlib leaf).
10+
namespace sn::pb_test {
11+
12+
enum class severity_e : std::int32_t {
13+
UNSPECIFIED = 0,
14+
INFO = 1,
15+
WARN = 2,
16+
ERROR = 3,
17+
};
18+
19+
struct log_entry_t {
20+
[[clang::annotate("pb::field=1")]] std::int64_t timestamp_ns;
21+
[[clang::annotate("pb::field=2")]] std::string message;
22+
[[clang::annotate("pb::field=3")]] severity_e level;
23+
[[clang::annotate("pb::field=4")]] double elapsed_ms;
24+
};
25+
26+
} // namespace sn::pb_test
27+
28+
void use() {
29+
sn::pb_test::log_entry_t e{};
30+
auto buf = pb::encode(e);
31+
(void)buf;
32+
}

tests/fixtures/pb_variant.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include "pb_stub.hpp"
2+
3+
#include <cstdint>
4+
#include <string>
5+
#include <variant>
6+
7+
// Tier-3 fixture (stage 4): std::variant as proto3 oneof. The variant must
8+
// start with std::monostate (the "absent" state); each subsequent alternative
9+
// gets a field number from the [[clang::annotate("pb::oneof_tags=N1,N2,…")]]
10+
// list on the variant member. Compiler emits a pb::oneof<&T::v,
11+
// pb::alt<T1, N1>, ...>{} entry in the descriptor.
12+
namespace sn::pb_test {
13+
14+
struct event_t {
15+
[[clang::annotate("pb::field=1")]] std::int64_t timestamp_ns;
16+
[[clang::annotate("pb::oneof_tags=5,6,7")]]
17+
std::variant<std::monostate, std::string, std::int64_t, double> payload;
18+
};
19+
20+
} // namespace sn::pb_test
21+
22+
void use() {
23+
sn::pb_test::event_t e{};
24+
auto buf = pb::encode(e);
25+
(void)buf;
26+
}

tests/fixtures/pb_wire_specs.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include "pb_stub.hpp"
2+
3+
#include <cstdint>
4+
5+
// Tier-2 fixture (stage 5): pb::wire=spec annotation. C++ int32_t maps to
6+
// any of int32/sint32/fixed32/sfixed32 on the wire depending on the
7+
// annotation. The compiler emits the WireSpec template arg on pb::field<>.
8+
namespace sn::pb_test {
9+
10+
struct deltas_t {
11+
// Default (no pb::wire) → natural mapping (int32, varint with sign extension).
12+
[[clang::annotate("pb::field=1")]]
13+
std::int32_t natural;
14+
15+
// sint32: zigzag varint — better for centered-around-zero distributions.
16+
[[clang::annotate("pb::field=2")]]
17+
[[clang::annotate("pb::wire=sint32")]]
18+
std::int32_t zigzag;
19+
20+
// fixed32: always 4 bytes LE (for uint32_t).
21+
[[clang::annotate("pb::field=3")]]
22+
[[clang::annotate("pb::wire=fixed32")]]
23+
std::uint32_t lo32;
24+
25+
// sfixed64: always 8 bytes LE signed.
26+
[[clang::annotate("pb::field=4")]]
27+
[[clang::annotate("pb::wire=sfixed64")]]
28+
std::int64_t big_signed;
29+
};
30+
31+
} // namespace sn::pb_test
32+
33+
void use() {
34+
sn::pb_test::deltas_t d{};
35+
auto buf = pb::encode(d);
36+
(void)buf;
37+
}

tests/golden/pb_chrono.expected

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/* Generated by h5cpp-compiler --protocol-buffers. Do not edit. */
2+
#pragma once
3+
4+
#include <pb.hpp>
5+
6+
template<> struct pb::meta::descriptor_t<sn::pb_test::event_t> {
7+
static constexpr auto fields = std::tuple{
8+
pb::field<1, &sn::pb_test::event_t::id>{},
9+
pb::adapter_field<2, &sn::pb_test::event_t::when, pb::Timestamp_adapter>{},
10+
pb::adapter_field<3, &sn::pb_test::event_t::ttl, pb::Duration_adapter>{}
11+
};
12+
};
13+
14+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/* Generated by h5cpp-compiler --protocol-buffers. Do not edit. */
2+
#pragma once
3+
4+
#include <pb.hpp>
5+
6+
template<> struct pb::meta::descriptor_t<sn::pb_test::profile_t> {
7+
static constexpr auto fields = std::tuple{
8+
pb::field<1, &sn::pb_test::profile_t::name>{},
9+
pb::field<2, &sn::pb_test::profile_t::scores>{},
10+
pb::field<3, &sn::pb_test::profile_t::nickname>{},
11+
pb::field<4, &sn::pb_test::profile_t::aliases>{},
12+
pb::field<5, &sn::pb_test::profile_t::user_id>{}
13+
};
14+
};
15+
16+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/* Generated by h5cpp-compiler --protocol-buffers. Do not edit. */
2+
#pragma once
3+
4+
#include <pb.hpp>
5+
6+
template<> struct pb::meta::descriptor_t<sn::pb_test::primitives_t> {
7+
static constexpr auto fields = std::tuple{
8+
pb::field<1, &sn::pb_test::primitives_t::_bool>{},
9+
pb::field<2, &sn::pb_test::primitives_t::_i32>{},
10+
pb::field<3, &sn::pb_test::primitives_t::_i64>{},
11+
pb::field<4, &sn::pb_test::primitives_t::_u32>{},
12+
pb::field<5, &sn::pb_test::primitives_t::_u64>{},
13+
pb::field<6, &sn::pb_test::primitives_t::_f>{},
14+
pb::field<7, &sn::pb_test::primitives_t::_d>{}
15+
};
16+
};
17+
18+

0 commit comments

Comments
 (0)