Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build_linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ jobs:
if: matrix.bazel-config == 'bl-x86_64-linux'
run: |
# Test that baselibs works when consumed as an external module dependency
cd examples/integration && bazel build //... && bazel mod deps --lockfile_mode=update
cd examples/integration && bazel build //... && bazel test //... && bazel mod deps --lockfile_mode=update
- name: Upload test logs on failure
if: failure()
uses: actions/upload-artifact@v7
Expand Down
2 changes: 1 addition & 1 deletion MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ single_version_override(

## Configure the python toolchain

bazel_dep(name = "rules_python", version = "1.8.3", dev_dependency = True)
bazel_dep(name = "rules_python", version = "1.8.3")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@4og
This was found by the black-box testing.
It is necessary for the inject_buffer_version (py_binary) which will only be build for the host environment.

The alternative to just export the python file and expect a python installation on the host, is from my point of view not valid.

Atm i don't have concerns with switching rules_python to non dev, it should behave like the other rules_*.
The consuming module is allowed to override the toolchain (python use_extension).


PYTHON_VERSION = "3.12"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ FlatBuffers Component Architecture
:id: comp__baselibs_flatbuffers
:security: YES
:safety: ASIL_B
:status: invalid
:status: valid
:belongs_to: feat__baselibs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ Buffer Identification and Versioning
:safety: ASIL_B
:derived_from: feat_req__baselibs__flatbuffers_library, feat_req__baselibs__safety
:status: valid
:testcovered: YES
:satisfied_by: comp__baselibs_flatbuffers

The FlatBuffers-Library shall provide a common opt-in buffer identification mechanism consisting
Expand All @@ -175,6 +176,7 @@ Buffer Identification and Versioning
:safety: ASIL_B
:derived_from: feat_req__baselibs__flatbuffers_library, feat_req__baselibs__safety
:status: valid
:testcovered: YES
:satisfied_by: comp__baselibs_flatbuffers

The FlatBuffers-Library shall provide a common opt-in version check mechanism that validates
Expand Down
2 changes: 2 additions & 0 deletions examples/integration/MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ local_path_override(

bazel_dep(name = "rules_cc", version = "0.2.17")

bazel_dep(name = "googletest", version = "1.17.0.bcr.2", dev_dependency = True)

# Upgrade grpc-java to 1.70.0 for compatibility with newer grpc (1.70.1).
# The transitive grpc dependency (via flatbuffers) resolves to grpc 1.70.1, which removed
# the com_envoyproxy_protoc_gen_validate repo that grpc-java@1.66.0 requires.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

load("@rules_cc//cc:defs.bzl", "cc_test")
Comment thread
OliverHeilwagen marked this conversation as resolved.
load("@score_baselibs//score/flatbuffers/bazel:codegen.bzl", "generate_cpp")
load("@score_baselibs//score/flatbuffers/bazel:tools.bzl", "generate_json_schema", "serialize_buffer")
load("@score_baselibs//score/flatbuffers/bazel:tools.bzl", "generate_json_schema", "serialize_buffer", "serialize_versioned_buffer")

# Generate C++ header from FlatBuffer schema
generate_cpp(
Expand All @@ -37,19 +37,52 @@ serialize_buffer(
schema = "demo.fbs",
)

# Demo test: loads demo_config.bin at runtime, verifies and reads the config
# using filesystem and flatbufferscpp library.
# Demo test: loads demo_config.bin at runtime, verifies and reads the config.
cc_test(
name = "demo_app",
name = "demo_config",
size = "small",
srcs = [
"demo_app_test.cpp",
"demo_config_test.cpp",
":demo_component_config",
],
data = [":demo_config_bin"],
deps = [
"@googletest//:gtest_main",
"@score_baselibs//score/filesystem",
"@score_baselibs//score/flatbuffers:flatbufferscpp",
"@score_baselibs//score/flatbuffers:flatbufferutils",
],
)

# Generate C++ header from the versioned FlatBuffer schema, which includes
# buffer_version.fbs and defines version_info at id: 0 in the root table.
generate_cpp(
name = "demo_component_config_versioned",
output = "component_config_versioned.h",
schema = "demo_versioned.fbs",
)

# Generate binary config with injected version (major=1, minor=0) from the
# same JSON data as the unversioned demo.
serialize_versioned_buffer(
name = "demo_config_versioned_bin",
buffer_major_version = 1,
buffer_minor_version = 0,
data = "demo_config.json",
output = "demo_config_versioned.bin",
schema = "demo_versioned.fbs",
)

# Demo versioned test: loads demo_config_versioned.bin, calls VerifyVersion
# before accessing the data, then reads and asserts config values.
cc_test(
name = "demo_config_versioned",
size = "small",
srcs = [
"demo_config_versioned_test.cpp",
":demo_component_config_versioned",
],
data = [":demo_config_versioned_bin"],
deps = [
"@googletest//:gtest_main",
"@score_baselibs//score/flatbuffers:flatbufferutils",
],
)
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,13 @@
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/

/// @file demo_app_test.cpp
/// @brief Demonstrates loading and reading a FlatBuffer binary config
/// using flatbufferscpp (FlatBuffers C++ API)
///
/// Build and run via Bazel:
/// bazel test //demo_config_usecase:demo_app
/// @file demo_config_test.cpp
/// @brief Demonstrates loading of a FlatBuffer binary config and reading the config fields.

#include "score/flatbuffers/load_buffer.hpp"
// Generated C++ accessor header produced by generate_cpp() – depends on flatbufferscpp
#include "score/flatbuffers/examples/config_usecase/component_config.h"
// Generated C++ accessor header produced by generate_cpp() for demo.fbs
#include "flatbuffers/config_usecase/component_config.h"

// FlatBuffers verifier (part of flatbufferscpp / @flatbuffers headers)
#include "flatbuffers/verifier.h"

#include <gtest/gtest.h>
Expand All @@ -35,20 +30,20 @@ TEST(DemoAppTest, LoadsAndVerifiesBuffer)
// -------------------------------------------------------------------------
// Step 1: Load the binary FlatBuffer file from disk (standard file I/O)
// -------------------------------------------------------------------------
const std::string_view bin_path = "score/flatbuffers/examples/config_usecase/demo_config.bin";
const std::string_view bin_path = "flatbuffers/config_usecase/demo_config.bin";
const auto buffer = score::flatbuffers::LoadBuffer(bin_path);
ASSERT_TRUE(buffer.has_value()) << buffer.error().ToString();

// -------------------------------------------------------------------------
// Step 2: Verify buffer integrity (flatbuffercpp / FlatBuffers verifier)
// Step 2: Verify structural integrity of the FlatBuffer
// -------------------------------------------------------------------------
flatbuffers::Verifier verifier(buffer.value().data(), buffer.value().size());

ASSERT_TRUE(my_component::demo::VerifyMyComponentConfigBuffer(verifier))
<< "FlatBuffer verification failed for '" << bin_path << "'";
<< "FlatBuffer structural verification failed for '" << bin_path << "'";

// -------------------------------------------------------------------------
// Step 3: Access config values via the generated flatbuffercpp API
// Step 3: Access config values via the generated APIs
// -------------------------------------------------------------------------
const my_component::demo::MyComponentConfig* config =
my_component::demo::GetMyComponentConfig(buffer.value().data());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/********************************************************************************
* Copyright (c) 2026 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/

/// @file demo_config_versioned_test.cpp
/// @brief Demonstrates loading of a versioned FlatBuffer binary config,
/// verifying its version via score::flatbuffers::VerifyVersion before
/// accessing any data, and then reading the config fields.

#include "score/flatbuffers/buffer_version_info.hpp"
#include "score/flatbuffers/load_buffer.hpp"
#include "score/flatbuffers/version_reader.hpp"
// Generated C++ accessor header produced by generate_cpp() for demo_versioned.fbs
#include "flatbuffers/config_usecase/component_config_versioned.h"

#include "flatbuffers/verifier.h"

#include <gtest/gtest.h>

#include <string_view>

TEST(DemoConfigVersionedTest, VerifiesVersionThenLoadsAndReadsBuffer)
{
// -------------------------------------------------------------------------
// Step 1: Load the binary FlatBuffer file from disk
// -------------------------------------------------------------------------
const std::string_view bin_path = "flatbuffers/config_usecase/demo_config_versioned.bin";
const auto buffer = score::flatbuffers::LoadBuffer(bin_path);
ASSERT_TRUE(buffer.has_value()) << buffer.error().ToString();

// -------------------------------------------------------------------------
// Step 2: Verify buffer version before accessing any data
//
// The expected BufferVersionInfo must match:
// - file_identifier : "DEMO" (set in demo_versioned.fbs)
// - major_version : 1 (set in serialize_versioned_buffer rule)
// - minor_version : 0 (set in serialize_versioned_buffer rule)
// -------------------------------------------------------------------------
const score::flatbuffers::BufferVersionInfo expected{"DEMO", 1U, 0U};
// Free function variant is used for VerifyVersion.
// Use score::flatbuffers::VersionReader (implements IVersionReader) instead
// when the caller needs to inject or mock the reader.
const auto version_result = score::flatbuffers::VerifyVersion(buffer.value(), expected);
ASSERT_TRUE(version_result.has_value()) << version_result.error();

// -------------------------------------------------------------------------
// Step 3: Verify structural integrity of the FlatBuffer
// -------------------------------------------------------------------------
flatbuffers::Verifier verifier(buffer.value().data(), buffer.value().size());
ASSERT_TRUE(my_component::demo::VerifyMyComponentConfigBuffer(verifier))
<< "FlatBuffer structural verification failed for '" << bin_path << "'";

// -------------------------------------------------------------------------
// Step 4: Access config values via the generated APIs
// -------------------------------------------------------------------------
const my_component::demo::MyComponentConfig* config =
my_component::demo::GetMyComponentConfig(buffer.value().data());

ASSERT_NE(config, nullptr);
EXPECT_EQ(config->component_name()->str(), "demo_component");
EXPECT_EQ(config->component_id(), 42U);
EXPECT_EQ(config->thread_pool_size(), 4U);
EXPECT_EQ(config->max_memory_mb(), 64U);

const my_component::demo::AdvancedSettings* adv = config->advanced_settings();
ASSERT_NE(adv, nullptr);
EXPECT_EQ(adv->mode(), my_component::demo::OperationMode::PERIODIC);

ASSERT_NE(adv->allowed_priorities(), nullptr);
EXPECT_EQ(adv->allowed_priorities()->size(), 2U);
EXPECT_EQ(adv->allowed_priorities()->Get(0), 1U);
EXPECT_EQ(adv->allowed_priorities()->Get(1), 2U);

ASSERT_NE(adv->feature_flags(), nullptr);
ASSERT_EQ(adv->feature_flags()->size(), 1U);
const my_component::demo::FeatureFlag* flag = adv->feature_flags()->Get(0);
EXPECT_EQ(flag->name()->str(), "enable_logging");
EXPECT_TRUE(flag->enabled());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/// Versioned variant of the demo component config schema.
///
/// Follows the common buffer identification convention:
/// - includes buffer_version.fbs
/// - declares version_info:score.flatbuffers.BufferVersion as the FIRST field
/// of the root table (vtable slot 0)
///
/// The binary buffer is produced by serialize_versioned_buffer, which injects
/// the major/minor version into the JSON data before calling flatc --binary.
/// At runtime, score::flatbuffers::VerifyVersion() reads the embedded version
/// and compares it against the caller-supplied BufferVersionInfo.
///
/// Explicit field IDs (id: N) are used throughout this schema.
/// Benefits: field order in the .fbs source can be changed freely without
/// breaking binary compatibility with buffers produced by older schema versions,
/// because the vtable slot is determined by the id attribute, not by declaration
/// order. This makes schema evolution safer: new fields can be inserted anywhere
/// and deprecated fields can be removed without affecting existing binaries.

include "buffer_version.fbs";

namespace my_component.demo;

/// Generic enum for component run modes
enum OperationMode:uint8 {
EVENT_DRIVEN = 0,
POLLING = 1,
PERIODIC = 2,
}

/// Union for flexible data types
union DataPayloadUnion {
StringData,
BinaryData
}

table MyComponentConfig {
/// MUST be field 0 – required by the universal buffer identification convention.
version_info:score.flatbuffers.BufferVersion (id: 0);

/// Component identification
component_name:string (required, id: 1);
component_id:uint32 (id: 2); // Implicit default is 0

thread_pool_size:uint8 = 4 (id: 3); // Explicit default value
max_memory_mb:uint16 = 64 (id: 4);

/// Nested table
advanced_settings:AdvancedSettings (required, id: 5);
}

table AdvancedSettings {
/// Enum example: operational mode (defaults to first enum value: EVENT_DRIVEN)
mode:OperationMode (id: 0);

/// Vector examples
allowed_priorities:[uint8] (id: 1); // Vector of primitives
feature_flags:[FeatureFlag] (id: 2); // Vector of tables

/// Union example: flexible data payload
/// Note: unions occupy two consecutive IDs – one for the type discriminator
/// and one for the value offset. data_type takes id: 3, data takes id: 4.
data:DataPayloadUnion (id: 4);
}

/// Table used in vector
table FeatureFlag {
name:string (required, id: 0);
enabled:bool = false (id: 1);
}

table StringData {
value:string (id: 0);
}

table BinaryData {
value:[uint8] (id: 0);
}

// Root configuration object
root_type MyComponentConfig;

// Component specific file identifier – distinct from the unversioned "DEMO"
// so that VerifyVersion can distinguish the two buffer formats.
file_identifier "DEMO";
Loading
Loading