diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c041dc4..00e2b31 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -249,3 +249,57 @@ jobs:
--openrpc /workspace/docs/openrpc/the-spec/firebolt-open-rpc.json \
--app-openrpc /workspace/docs/openrpc/the-spec/firebolt-app-open-rpc.json \
--test-exe /workspace/build/test/FireboltClientComponentTests
+
+ cpp_demo_tests:
+ permissions:
+ contents: read
+ packages: read
+ needs: [build_docker]
+ runs-on: ubuntu-latest
+ steps:
+ - name: Log in to the Container registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Checkout Code
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Get version
+ run: |
+ VERSION=$(git describe --tags --dirty --match "v[0-9]*")
+ echo "VERSION=$VERSION" >> $GITHUB_ENV
+ echo "version: $VERSION"
+
+ - name: Configure Project with Demo
+ run: |
+ docker run --rm --user "$(id -u):$(id -g)" -v ${{ github.workspace }}:/workspace ${{ needs.build_docker.outputs.image_tag }} \
+ bash -c " \
+ set -e \
+ && cmake -B build -S . \
+ -DCMAKE_BUILD_TYPE=Debug \
+ -DENABLE_DEMO_APP=ON \
+ "
+
+ - name: Build Project with cpp_test
+ run: |
+ docker run --rm --user "$(id -u):$(id -g)" -v ${{ github.workspace }}:/workspace ${{ needs.build_docker.outputs.image_tag }} \
+ bash -c " \
+ set -e \
+ && cmake --build build --parallel \
+ "
+
+ - name: Run cpp_test executable
+ run: |
+ chmod +x ${{ github.workspace }}/build/test/cpp_test/cpp_test
+ docker run --rm --user "$(id -u):$(id -g)" -v ${{ github.workspace }}:/workspace ${{ needs.build_docker.outputs.image_tag }} \
+ bash -c " \
+ set -e \
+ && cd /workspace/build/test/cpp_test \
+ && ./cpp_test \
+ "
+
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 14008c9..8b9589f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -91,8 +91,10 @@ add_subdirectory(src)
if (ENABLE_DEMO_APP)
add_subdirectory(demo)
+ add_subdirectory(test/cpp_test) #for now
endif()
if (ENABLE_TESTS)
add_subdirectory(test)
endif()
+
diff --git a/test/cpp_test/CMakeLists.txt b/test/cpp_test/CMakeLists.txt
new file mode 100644
index 0000000..3a5a408
--- /dev/null
+++ b/test/cpp_test/CMakeLists.txt
@@ -0,0 +1,54 @@
+cmake_minimum_required(VERSION 3.10)
+project(cpp_test)
+
+set(CMAKE_CXX_STANDARD 17)
+
+add_executable(cpp_test
+ main.cpp
+ cpp/advertisingDemo.cpp
+ cpp/accessibilityDemo.cpp
+ cpp/chooseInterface.cpp
+ cpp/deviceDemo.cpp
+ cpp/displayDemo.cpp
+ cpp/fireboltdemo.cpp
+ cpp/lifecycleDemo.cpp
+ cpp/localizationDemo.cpp
+ cpp/presentationDemo.cpp
+ cpp/statsDemo.cpp
+ cpp/utils.cpp
+)
+
+list(APPEND CMAKE_PREFIX_PATH ${SYSROOT_PATH})
+
+find_package(FireboltTransport)
+find_package(nlohmann_json REQUIRED)
+find_package(nlohmann_json_schema_validator REQUIRED)
+find_package(CURL REQUIRED)
+
+# Generate header file with embedded JSON content
+file(READ "../../docs/openrpc/the-spec/firebolt-open-rpc.json" JSON_CONTENT)
+configure_file(
+ cpp/firebolt-open-rpc.json.in
+ "${CMAKE_BINARY_DIR}/generated/firebolt-open-rpc_json.h"
+ @ONLY
+)
+
+# Make sure your target can find the generated header
+target_include_directories(cpp_test PRIVATE ${CMAKE_BINARY_DIR}/generated)
+
+target_include_directories(cpp_test PRIVATE
+ $
+ $
+ $
+ $
+)
+
+add_compile_definitions(UT_OPEN_RPC_FILE="firebolt-open-rpc.json")
+
+target_link_libraries(cpp_test
+ FireboltClient
+ FireboltTransport::FireboltTransport
+ nlohmann_json::nlohmann_json
+ nlohmann_json_schema_validator::validator
+ CURL::libcurl
+)
\ No newline at end of file
diff --git a/test/cpp_test/cpp/accessibilityDemo.cpp b/test/cpp_test/cpp/accessibilityDemo.cpp
new file mode 100644
index 0000000..5792e01
--- /dev/null
+++ b/test/cpp_test/cpp/accessibilityDemo.cpp
@@ -0,0 +1,84 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "accessibilityDemo.h"
+#include
+#include
+#include
+
+#include "json_types/jsondata_device_types.h"
+
+#include "outputstream.h"
+extern OutputStream gOutput;
+
+using namespace Firebolt;
+using namespace Firebolt::Accessibility;
+
+AccessibilityDemo::AccessibilityDemo()
+ : IFireboltDemo()
+{
+ methodsFromRpc("Accessibility");
+}
+
+void AccessibilityDemo::runOption(const int index)
+{
+ std::string key = names_[index];
+
+ outStream_ << "Running Accessibility method: " << key << std::endl;
+
+ if (key == "Accessibility.closedCaptionsSettings")
+ {
+ Result r =
+ Firebolt::IFireboltAccessor::Instance().AccessibilityInterface().closedCaptionsSettings();
+ if (validateResult(r))
+ {
+ ClosedCaptionsSettings settings = r.value();
+ gOutput << "Closed Captions Settings - Enabled: " << (settings.enabled ? "true" : "false") << std::endl;
+ }
+ }
+ else if (key == "Accessibility.audioDescription")
+ {
+ Result r = Firebolt::IFireboltAccessor::Instance().AccessibilityInterface().audioDescription();
+ if (validateResult(r))
+ {
+ bool enabled = r.value();
+ gOutput << "Audio Description Enabled: " << (enabled ? "true" : "false") << std::endl;
+ }
+ }
+ else if (key == "Accessibility.highContrastUI")
+ {
+ Result r = Firebolt::IFireboltAccessor::Instance().AccessibilityInterface().highContrastUI();
+ if (validateResult(r))
+ {
+ bool enabled = r.value();
+
+ gOutput << "High Contrast UI Enabled: " << (enabled ? "true" : "false") << std::endl;
+ }
+ }
+ else if (key == "Accessibility.voiceGuidanceSettings")
+ {
+ Result r =
+ Firebolt::IFireboltAccessor::Instance().AccessibilityInterface().voiceGuidanceSettings();
+ if (validateResult(r))
+ {
+ VoiceGuidanceSettings settings = r.value();
+ gOutput << "Voice Guidance Settings - Enabled: " << (settings.enabled ? "true" : "false")
+ << ", Rate: " << settings.rate << std::endl;
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/cpp_test/cpp/accessibilityDemo.h b/test/cpp_test/cpp/accessibilityDemo.h
new file mode 100644
index 0000000..a0394bf
--- /dev/null
+++ b/test/cpp_test/cpp/accessibilityDemo.h
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#include
+#include
+#include "fireboltdemo.h"
+
+class AccessibilityDemo : public IFireboltDemo
+{
+public:
+ AccessibilityDemo();
+ ~AccessibilityDemo() = default;
+ void runOption(const int index);
+};
diff --git a/test/cpp_test/cpp/advertisingDemo.cpp b/test/cpp_test/cpp/advertisingDemo.cpp
new file mode 100644
index 0000000..cec1570
--- /dev/null
+++ b/test/cpp_test/cpp/advertisingDemo.cpp
@@ -0,0 +1,54 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+
+#include "advertisingDemo.h"
+#include
+#include
+#include
+
+#include "outputstream.h"
+extern OutputStream gOutput;
+
+// #include "json_types/jsondata_device_types.h"
+
+using namespace Firebolt;
+using namespace Firebolt::Advertising;
+
+AdvertisingDemo::AdvertisingDemo()
+ : IFireboltDemo()
+{
+ methodsFromRpc("Advertising");
+}
+
+void AdvertisingDemo::runOption(const int index)
+{
+ std::string key = names_[index];
+
+ if (key == "Advertising.advertisingId")
+ {
+ Result result = Firebolt::IFireboltAccessor::Instance().AdvertisingInterface().advertisingId();
+ if (validateResult(result))
+ {
+ Ifa ifa = result.value();
+ gOutput << "IFA: " << ifa.ifa << std::endl;
+ gOutput << "IFA Type: " << ifa.ifa_type << std::endl;
+ gOutput << "LMT: " << ifa.lmt << std::endl;
+ }
+ }
+}
diff --git a/test/cpp_test/cpp/advertisingDemo.h b/test/cpp_test/cpp/advertisingDemo.h
new file mode 100644
index 0000000..009e57a
--- /dev/null
+++ b/test/cpp_test/cpp/advertisingDemo.h
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#include
+#include
+#include "fireboltdemo.h"
+
+class AdvertisingDemo : public IFireboltDemo
+{
+public:
+ AdvertisingDemo();
+ ~AdvertisingDemo() = default;
+ void runOption(const int index);
+};
diff --git a/test/cpp_test/cpp/chooseInterface.cpp b/test/cpp_test/cpp/chooseInterface.cpp
new file mode 100644
index 0000000..1295c5d
--- /dev/null
+++ b/test/cpp_test/cpp/chooseInterface.cpp
@@ -0,0 +1,97 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "chooseInterface.h"
+#include "fireboltdemo.h"
+
+#include "accessibilityDemo.h"
+#include "advertisingDemo.h"
+#include "deviceDemo.h"
+#include "displayDemo.h"
+#include "lifecycleDemo.h"
+#include "localizationDemo.h"
+#include "presentationDemo.h"
+#include "statsDemo.h"
+
+#include
+
+#include "outputstream.h"
+extern OutputStream gOutput;
+
+ChooseInterface::ChooseInterface()
+ : IFireboltDemo()
+{
+ for (auto& [key, value] : json_["info"]["x-module-descriptions"].items())
+ {
+ std::cout << key << ": " << value << std::endl;
+ if (key != "Internal")
+ {
+ names_.push_back(key);
+ descriptions_.push_back(value.get());
+ }
+ }
+
+ interfaces = {new AccessibilityDemo(), new AdvertisingDemo(), new DeviceDemo(), new DisplayDemo(),
+ new LifecycleDemo(), new LocalizationDemo(), new PresentationDemo(), new StatsDemo()};
+}
+
+ChooseInterface::~ChooseInterface()
+{
+ for (auto interfacePtr : interfaces)
+ {
+ delete interfacePtr;
+ }
+}
+
+void ChooseInterface::runOption(const int index)
+{
+ IFireboltDemo* selectedInterface = interfaces[index];
+ gOutput << "Running interface: " << names_[index] << std::endl;
+
+ for (;;)
+ {
+ int methodIndex = selectedInterface->chooseOption();
+
+ if (methodIndex == -1)
+ {
+ break; // Go back to interface selection
+ }
+
+ selectedInterface->runOption(methodIndex);
+ }
+}
+
+void ChooseInterface::autoRun()
+{
+ for (int i = 0; i < (int)interfaces.size(); ++i)
+ {
+ IFireboltDemo* selectedInterface = interfaces[i];
+ if (selectedInterface == nullptr)
+ {
+ continue; // Skip unimplemented interfaces
+ }
+ gOutput << "Auto-running interface: " << names_[i] << std::endl;
+
+ // Assuming each interface has a predefined set of methods to run
+ for (int j = 0; j < selectedInterface->listSize(); ++j)
+ {
+ gOutput << "Auto-running method: " << selectedInterface->methods()[j] << std::endl;
+ selectedInterface->runOption(j);
+ }
+ }
+}
diff --git a/test/cpp_test/cpp/chooseInterface.h b/test/cpp_test/cpp/chooseInterface.h
new file mode 100644
index 0000000..a639412
--- /dev/null
+++ b/test/cpp_test/cpp/chooseInterface.h
@@ -0,0 +1,35 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#include "fireboltdemo.h"
+
+class ChooseInterface : public IFireboltDemo
+{
+public:
+ ChooseInterface();
+ ~ChooseInterface();
+ std::vector methods() const { return names_; }
+
+ void runOption(const int index);
+ void autoRun();
+
+private:
+ std::vector interfaces;
+};
diff --git a/test/cpp_test/cpp/deviceDemo.cpp b/test/cpp_test/cpp/deviceDemo.cpp
new file mode 100644
index 0000000..470264f
--- /dev/null
+++ b/test/cpp_test/cpp/deviceDemo.cpp
@@ -0,0 +1,86 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+
+#include "deviceDemo.h"
+#include
+#include
+#include
+
+#include "json_types/jsondata_device_types.h"
+
+#include "outputstream.h"
+extern OutputStream gOutput;
+
+using namespace Firebolt;
+using namespace Firebolt::Device;
+
+DeviceDemo::DeviceDemo()
+ : IFireboltDemo()
+{
+ methodsFromRpc("Device");
+}
+
+void DeviceDemo::runOption(const int index)
+{
+ std::string key = names_[index];
+
+ outStream_ << "Running Device method: " << key << std::endl;
+
+ if (key == "Device.class")
+ {
+ Result r = Firebolt::IFireboltAccessor::Instance().DeviceInterface().deviceClass();
+ if (validateResult(r))
+ {
+ gOutput << "Device Class: " << stringFromEnum(Firebolt::Device::JsonData::DeviceClassEnum, r.value())
+ << std::endl;
+ }
+ }
+ else if (key == "Device.uptime")
+ {
+ Result r = Firebolt::IFireboltAccessor::Instance().DeviceInterface().uptime();
+ if (validateResult(r))
+ {
+ gOutput << "Device Uptime (seconds): " << r.value() << std::endl;
+ }
+ }
+ else if (key == "Device.timeInActiveState")
+ {
+ Result r = Firebolt::IFireboltAccessor::Instance().DeviceInterface().timeInActiveState();
+ if (validateResult(r))
+ {
+ gOutput << "Device Time In Active State (seconds): " << r.value() << std::endl;
+ }
+ }
+ else if (key == "Device.chipsetId")
+ {
+ Result r = Firebolt::IFireboltAccessor::Instance().DeviceInterface().chipsetId();
+ if (validateResult(r))
+ {
+ gOutput << "Device Chipset ID: " << r.value() << std::endl;
+ }
+ }
+ else if (key == "Device.uid")
+ {
+ Result r = Firebolt::IFireboltAccessor::Instance().DeviceInterface().uid();
+ if (validateResult(r))
+ {
+ gOutput << "Device UID: " << r.value() << std::endl;
+ }
+ }
+}
diff --git a/test/cpp_test/cpp/deviceDemo.h b/test/cpp_test/cpp/deviceDemo.h
new file mode 100644
index 0000000..e035dd1
--- /dev/null
+++ b/test/cpp_test/cpp/deviceDemo.h
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#include
+#include
+#include "fireboltdemo.h"
+
+class DeviceDemo : public IFireboltDemo
+{
+public:
+ DeviceDemo();
+ ~DeviceDemo() = default;
+ void runOption(const int index);
+};
diff --git a/test/cpp_test/cpp/displayDemo.cpp b/test/cpp_test/cpp/displayDemo.cpp
new file mode 100644
index 0000000..f16d5af
--- /dev/null
+++ b/test/cpp_test/cpp/displayDemo.cpp
@@ -0,0 +1,61 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "displayDemo.h"
+#include
+#include
+#include
+
+#include "json_types/jsondata_device_types.h"
+
+#include "outputstream.h"
+extern OutputStream gOutput;
+
+using namespace Firebolt;
+using namespace Firebolt::Display;
+
+DisplayDemo::DisplayDemo()
+ : IFireboltDemo()
+{
+ methodsFromRpc("Display");
+}
+
+void DisplayDemo::runOption(const int index)
+{
+ std::string key = names_[index];
+
+ outStream_ << "Running Display method: " << key << std::endl;
+ if (key == "Display.maxResolution")
+ {
+ Result r = Firebolt::IFireboltAccessor::Instance().DisplayInterface().maxResolution();
+ if (validateResult(r))
+ {
+ DisplaySize res = r.value();
+ gOutput << "Max Resolution - Width: " << res.width << ", Height: " << res.height << std::endl;
+ }
+ }
+ else if (key == "Display.size")
+ {
+ Result r = Firebolt::IFireboltAccessor::Instance().DisplayInterface().size();
+ if (validateResult(r))
+ {
+ DisplaySize size = r.value();
+ gOutput << "Display Size - Width: " << size.width << ", Height: " << size.height << std::endl;
+ }
+ }
+}
diff --git a/test/cpp_test/cpp/displayDemo.h b/test/cpp_test/cpp/displayDemo.h
new file mode 100644
index 0000000..7139bc1
--- /dev/null
+++ b/test/cpp_test/cpp/displayDemo.h
@@ -0,0 +1,30 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#pragma once
+
+#include
+#include
+#include "fireboltdemo.h"
+
+class DisplayDemo : public IFireboltDemo
+{
+public:
+ DisplayDemo();
+ ~DisplayDemo() = default;
+ void runOption(const int index);
+};
diff --git a/test/cpp_test/cpp/firebolt-open-rpc.json.in b/test/cpp_test/cpp/firebolt-open-rpc.json.in
new file mode 100644
index 0000000..8aad328
--- /dev/null
+++ b/test/cpp_test/cpp/firebolt-open-rpc.json.in
@@ -0,0 +1,4 @@
+#pragma once
+#include
+
+constexpr std::string_view JSON_DATA = R"(@JSON_CONTENT@)";
\ No newline at end of file
diff --git a/test/cpp_test/cpp/fireboltdemo.cpp b/test/cpp_test/cpp/fireboltdemo.cpp
new file mode 100644
index 0000000..e188e52
--- /dev/null
+++ b/test/cpp_test/cpp/fireboltdemo.cpp
@@ -0,0 +1,138 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+
+#include "fireboltdemo.h"
+#include "firebolt-open-rpc_json.h"
+#include "utils.h"
+#include
+#include
+#include
+#include
+
+#include "outputstream.h"
+extern OutputStream gOutput;
+
+nlohmann::json IFireboltDemo::json_;
+
+#ifndef UT_OPEN_RPC_FILE
+#define UT_OPEN_RPC_FILE "firebolt-open-rpc.json"
+#endif
+
+IFireboltDemo::IFireboltDemo()
+{
+ loadRpc();
+}
+
+void IFireboltDemo::paramFromConsole(const std::string& name, const std::string& def, std::string& value)
+{
+ gOutput << "Enter " << name << " (default: " << def << "): ";
+ std::string input;
+ std::getline(std::cin, input);
+ if (input.empty())
+ {
+ value = def;
+ }
+ else
+ {
+ value = input;
+ }
+}
+
+int getOption(int n)
+{
+ std::string input;
+
+ while (true)
+ {
+ std::cout << "Select option or 'q' to go back: ";
+ std::cin >> input;
+
+ // Check if user wants to quit
+ if (input.length() == 1 && std::tolower(input[0]) == 'q')
+ {
+ return -1;
+ }
+
+ // Try to convert to integer
+ try
+ {
+ int num = std::stoi(input);
+
+ // Check if number is in valid range
+ if (num >= 0 && num <= n)
+ {
+ return num;
+ }
+ else
+ {
+ gOutput << "Please enter a number between 0 and " << n << "." << std::endl;
+ }
+ }
+ catch (const std::invalid_argument&)
+ {
+ std::cout << "Invalid input. Please enter a number or 'q'." << std::endl;
+ }
+ catch (const std::out_of_range&)
+ {
+ std::cout << "Number too large. Please enter a number between 0 and " << n << "." << std::endl;
+ }
+ }
+}
+
+int IFireboltDemo::chooseFromList(const std::vector& options, const std::string& prompt)
+{
+ std::cout << prompt << std::endl;
+ for (size_t i = 0; i < options.size(); ++i)
+ {
+ std::cout << i << ": " << options[i] << std::endl;
+ }
+
+ int choice = getOption(static_cast(options.size() - 1));
+
+ return choice;
+}
+
+int IFireboltDemo::chooseOption()
+{
+ return chooseFromList(names_, "Choose a method to run:");
+}
+
+void IFireboltDemo::loadRpc()
+{
+ json_ = nlohmann::json::parse(JSON_DATA);
+}
+
+std::vector IFireboltDemo::methodsFromRpc(const std::string& interfaceName)
+{
+ std::vector methodNames;
+
+ std::string interfaceStr = interfaceName + ".";
+ for (const auto& method : json_["methods"])
+ {
+ if (method.contains("name") && method["name"].get().rfind(interfaceStr, 0) == 0)
+ {
+
+ names_.push_back(method["name"]);
+ descriptions_.push_back(method["summary"]);
+ gOutput << "Found method: " << names_.back() << ":" << descriptions_.back() << std::endl;
+ }
+ }
+
+ return methodNames;
+}
diff --git a/test/cpp_test/cpp/fireboltdemo.h b/test/cpp_test/cpp/fireboltdemo.h
new file mode 100644
index 0000000..61969fe
--- /dev/null
+++ b/test/cpp_test/cpp/fireboltdemo.h
@@ -0,0 +1,98 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#include "firebolt/firebolt.h"
+#include "outputstream.h"
+#include
+#include
+#include
+#include
+
+class IFireboltDemo
+{
+public:
+ IFireboltDemo();
+ virtual ~IFireboltDemo() = default;
+
+ int chooseOption();
+ virtual void runOption(const int index) = 0;
+ int listSize() const { return static_cast(names_.size()); }
+ std::vector methods() const { return names_; }
+
+protected:
+ void paramFromConsole(const std::string& name, const std::string& def, std::string& value);
+ int chooseFromList(const std::vector& options, const std::string& prompt);
+
+ void loadRpc();
+
+ template bool validateResult(const Firebolt::Result& result) const
+ {
+ return doValidateResult(result.error());
+ }
+
+ bool validateResult(const Firebolt::Result& result) const { return doValidateResult(result.error()); }
+
+ template T chooseEnumFromList(const Firebolt::JSON::EnumType& enumType, const std::string& prompt)
+ {
+ std::vector options;
+ for (const auto& pair : enumType)
+ {
+ options.push_back(pair.first);
+ std::cout << "Option: " << pair.first << std::endl;
+ }
+
+ int choice = chooseFromList(options, prompt);
+
+ return enumType.at(options[choice]);
+ }
+
+ template std::string stringFromEnum(Firebolt::JSON::EnumType enumType, T value)
+ {
+ for (const auto& pair : enumType)
+ {
+ if (pair.second == value)
+ {
+ return pair.first;
+ }
+ }
+ return {};
+ }
+
+ std::vector methodsFromRpc(const std::string& interfaceName);
+
+ static nlohmann::json json_;
+
+ std::vector names_;
+ std::vector descriptions_;
+
+ OutputStream outStream_;
+
+private:
+ bool doValidateResult(Firebolt::Error error) const
+ {
+ if (error != Firebolt::Error::None)
+ {
+ std::cout << "Operation failed with error: " << static_cast(error) << std::endl;
+ return false;
+ }
+ std::cout << "Operation succeeded." << std::endl;
+ return true;
+ }
+};
diff --git a/test/cpp_test/cpp/lifecycleDemo.cpp b/test/cpp_test/cpp/lifecycleDemo.cpp
new file mode 100644
index 0000000..edfb05b
--- /dev/null
+++ b/test/cpp_test/cpp/lifecycleDemo.cpp
@@ -0,0 +1,136 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "lifecycleDemo.h"
+#include "json_types/jsondata_lifecycle_types.h"
+#include "utils.h"
+#include
+#include
+#include
+
+using namespace Firebolt;
+using namespace Firebolt::Lifecycle;
+
+#include "outputstream.h"
+extern OutputStream gOutput;
+extern bool gAutoRun;
+
+LifecycleDemo::LifecycleDemo()
+ : IFireboltDemo()
+{
+ methodsFromRpc("Lifecycle2");
+ names_.push_back("Trigger lifecycle state change");
+ descriptions_.push_back("Simulate a lifecycle state change event from the platform.");
+ currentState_ = LifecycleState::INITIALIZING;
+}
+
+void LifecycleDemo::runOption(const int index)
+{
+ std::string key = names_[index];
+
+ if (key == "Lifecycle2.close")
+ {
+ CloseType type = CloseType::DEACTIVATE;
+ if (gAutoRun)
+ {
+ gOutput << "Auto-selecting 'deactivate' for Close Type." << std::endl;
+ }
+ else
+ {
+ type = chooseEnumFromList(Firebolt::Lifecycle::JsonData::CloseReasonEnum, "Choose Close Type!!:");
+ }
+
+ Result r = Firebolt::IFireboltAccessor::Instance().LifecycleInterface().close(type);
+ validateResult(r);
+ }
+ else if (key == "Lifecycle2.state")
+ {
+ Result r = Firebolt::IFireboltAccessor::Instance().LifecycleInterface().state();
+ if (validateResult(r))
+ {
+ currentState_ = r.value();
+ printCurrentState();
+ }
+ }
+ else if (key == "Lifecycle2.onStateChanged")
+ {
+ auto callback = [&](const std::vector& changes)
+ {
+ gOutput << "Lifecycle State Changes received:" << std::endl;
+ for (const auto& change : changes)
+ {
+ gOutput << " From "
+ << Firebolt::JSON::toString(Firebolt::Lifecycle::JsonData::LifecycleStateEnum, change.oldState)
+ << " to "
+ << Firebolt::JSON::toString(Firebolt::Lifecycle::JsonData::LifecycleStateEnum, change.newState)
+ << std::endl;
+ currentState_ = change.newState;
+ }
+ };
+ Result r =
+ Firebolt::IFireboltAccessor::Instance().LifecycleInterface().subscribeOnStateChanged(std::move(callback));
+ if (validateResult(r))
+ {
+ gOutput << "Subscribed to Lifecycle state changes with Subscription ID: " << r.value() << std::endl;
+ }
+ }
+ else if (key == "Trigger lifecycle state change")
+ {
+ triggerLifecycleStateChange();
+ }
+ else if (key == "Lifecycle2.unsubscribe")
+ {
+ std::string idStr;
+ paramFromConsole("Subscription ID to unsubscribe", "0", idStr);
+ SubscriptionId id = static_cast(std::stoul(idStr));
+ Result r = Firebolt::IFireboltAccessor::Instance().LifecycleInterface().unsubscribe(id);
+ validateResult(r);
+ }
+ else if (key == "Lifecycle2.unsubscribeAll")
+ {
+ Firebolt::IFireboltAccessor::Instance().LifecycleInterface().unsubscribeAll();
+ gOutput << "Unsubscribed from all Lifecycle subscriptions." << std::endl;
+ }
+}
+
+void LifecycleDemo::triggerLifecycleStateChange()
+{
+ LifecycleState newState = LifecycleState::ACTIVE;
+ if (gAutoRun)
+ {
+ gOutput << "Auto-selecting 'active' for new Lifecycle State." << std::endl;
+ }
+ else
+ {
+ newState = chooseEnumFromList(Firebolt::Lifecycle::JsonData::LifecycleStateEnum,
+ "Choose new Lifecycle State to simulate:");
+ }
+
+ nlohmann::json params;
+ params["value"] = nlohmann::json::array();
+ params["value"].push_back(
+ {{"newState", Firebolt::JSON::toString(Firebolt::Lifecycle::JsonData::LifecycleStateEnum, newState)},
+ {"oldState", Firebolt::JSON::toString(Firebolt::Lifecycle::JsonData::LifecycleStateEnum, currentState_)}});
+ triggerEvent("Lifecycle2.onStateChanged", params.dump());
+}
+
+void LifecycleDemo::printCurrentState()
+{
+ gOutput << "Current Lifecycle State: "
+ << stringFromEnum(Firebolt::Lifecycle::JsonData::LifecycleStateEnum, currentState_) << std::endl;
+}
\ No newline at end of file
diff --git a/test/cpp_test/cpp/lifecycleDemo.h b/test/cpp_test/cpp/lifecycleDemo.h
new file mode 100644
index 0000000..9f970e2
--- /dev/null
+++ b/test/cpp_test/cpp/lifecycleDemo.h
@@ -0,0 +1,36 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#include
+#include
+#include "fireboltdemo.h"
+
+class LifecycleDemo : public IFireboltDemo
+{
+public:
+ LifecycleDemo();
+ ~LifecycleDemo() = default;
+ void runOption(const int index);
+
+private:
+ void triggerLifecycleStateChange();
+ void printCurrentState();
+ Firebolt::Lifecycle::LifecycleState currentState_;
+};
diff --git a/test/cpp_test/cpp/localizationDemo.cpp b/test/cpp_test/cpp/localizationDemo.cpp
new file mode 100644
index 0000000..f896237
--- /dev/null
+++ b/test/cpp_test/cpp/localizationDemo.cpp
@@ -0,0 +1,71 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "localizationDemo.h"
+#include
+#include
+#include
+
+#include "outputstream.h"
+extern OutputStream gOutput;
+
+using namespace Firebolt;
+using namespace Firebolt::Localization;
+
+LocalizationDemo::LocalizationDemo()
+ : IFireboltDemo()
+{
+ methodsFromRpc("Localization");
+}
+
+void LocalizationDemo::runOption(const int index)
+{
+ std::string key = names_[index];
+
+ if (key == "Localization.country")
+ {
+ Result result = Firebolt::IFireboltAccessor::Instance().LocalizationInterface().country();
+ if (validateResult(result))
+ {
+ gOutput << "Country: " << result.value() << std::endl;
+ }
+ }
+ else if (key == "Localization.preferredAudioLanguages")
+ {
+ Result> result =
+ Firebolt::IFireboltAccessor::Instance().LocalizationInterface().preferredAudioLanguages();
+ if (validateResult(result))
+ {
+ gOutput << "Preferred Audio Languages: ";
+ for (const auto& lang : result.value())
+ {
+ gOutput << lang << " ";
+ }
+ gOutput << std::endl;
+ }
+ }
+ else if (key == "Localization.presentationLanguage")
+ {
+ Result result =
+ Firebolt::IFireboltAccessor::Instance().LocalizationInterface().presentationLanguage();
+ if (validateResult(result))
+ {
+ gOutput << "Presentation Language: " << result.value() << std::endl;
+ }
+ }
+}
diff --git a/test/cpp_test/cpp/localizationDemo.h b/test/cpp_test/cpp/localizationDemo.h
new file mode 100644
index 0000000..bdcde26
--- /dev/null
+++ b/test/cpp_test/cpp/localizationDemo.h
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#include
+#include
+#include "fireboltdemo.h"
+
+class LocalizationDemo : public IFireboltDemo
+{
+public:
+ LocalizationDemo();
+ ~LocalizationDemo() = default;
+ void runOption(const int index);
+};
diff --git a/test/cpp_test/cpp/outputstream.h b/test/cpp_test/cpp/outputstream.h
new file mode 100644
index 0000000..791bbe0
--- /dev/null
+++ b/test/cpp_test/cpp/outputstream.h
@@ -0,0 +1,62 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#include
+#include
+#include
+#include
+
+class OutputStream
+{
+ std::unique_ptr file_;
+ std::ostream* out_;
+
+public:
+ OutputStream()
+ : out_(&std::cout)
+ {
+ }
+ OutputStream(const std::string& filename)
+ : file_(std::make_unique(filename)),
+ out_(file_.get())
+ {
+ }
+
+ // Delete copy operations since we have a unique_ptr member
+ OutputStream(const OutputStream&) = delete;
+ OutputStream& operator=(const OutputStream&) = delete;
+
+ // Allow move operations (optional, but good practice)
+ OutputStream(OutputStream&&) = default;
+ OutputStream& operator=(OutputStream&&) = default;
+
+ template OutputStream& operator<<(const T& value)
+ {
+ (*out_) << value;
+ return *this;
+ }
+
+ // Support for std::endl and other manipulators
+ OutputStream& operator<<(std::ostream& (*manip)(std::ostream&))
+ {
+ (*out_) << manip;
+ return *this;
+ }
+};
\ No newline at end of file
diff --git a/test/cpp_test/cpp/presentationDemo.cpp b/test/cpp_test/cpp/presentationDemo.cpp
new file mode 100644
index 0000000..3d39508
--- /dev/null
+++ b/test/cpp_test/cpp/presentationDemo.cpp
@@ -0,0 +1,71 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "presentationDemo.h"
+#include
+#include
+#include
+
+#include "utils.h"
+
+#include "outputstream.h"
+extern OutputStream gOutput;
+
+using namespace Firebolt;
+using namespace Firebolt::Presentation;
+
+PresentationDemo::PresentationDemo()
+ : IFireboltDemo()
+{
+ methodsFromRpc("Presentation");
+ names_.push_back("Trigger presentation state change");
+ descriptions_.push_back("Simulate a presentation state change event from the platform.");
+}
+
+void PresentationDemo::runOption(const int index)
+{
+ std::string key = names_[index];
+
+ if (key == "Presentation.focused")
+ {
+ Result r = Firebolt::IFireboltAccessor::Instance().PresentationInterface().focused();
+ if (validateResult(r))
+ {
+ gOutput << "Presentation focused: " << (r.value() ? "true" : "false") << std::endl;
+ }
+ }
+ else if (key == "Presentation.onFocusedChanged")
+ {
+ auto subscriptionResult =
+ Firebolt::IFireboltAccessor::Instance().PresentationInterface().subscribeOnFocusedChanged(
+ [&](bool focused)
+ { gOutput << "Presentation focus changed: " << (focused ? "true" : "false") << std::endl; });
+ if (validateResult(subscriptionResult))
+ {
+ SubscriptionId subId = subscriptionResult.value();
+ gOutput << "Subscribed to Presentation.onFocusedChanged with SubscriptionId: " << subId << std::endl;
+ }
+ }
+}
+
+/*
+void PresentationDemo::triggerPresentationStateChange()
+{
+ triggerEvent("Presentation.onFocusedChanged", R"({"focused": true})");
+}
+*/
\ No newline at end of file
diff --git a/test/cpp_test/cpp/presentationDemo.h b/test/cpp_test/cpp/presentationDemo.h
new file mode 100644
index 0000000..c9e5b82
--- /dev/null
+++ b/test/cpp_test/cpp/presentationDemo.h
@@ -0,0 +1,34 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#include
+#include
+#include "fireboltdemo.h"
+
+class PresentationDemo : public IFireboltDemo
+{
+public:
+ PresentationDemo();
+ ~PresentationDemo() = default;
+ void runOption(const int index);
+
+private:
+ // void triggerPresentationStateChange();
+};
diff --git a/test/cpp_test/cpp/statsDemo.cpp b/test/cpp_test/cpp/statsDemo.cpp
new file mode 100644
index 0000000..f0f1b75
--- /dev/null
+++ b/test/cpp_test/cpp/statsDemo.cpp
@@ -0,0 +1,53 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "statsDemo.h"
+#include
+#include
+#include
+
+#include "json_types/jsondata_device_types.h"
+
+#include "outputstream.h"
+extern OutputStream gOutput;
+
+using namespace Firebolt;
+using namespace Firebolt::Stats;
+
+StatsDemo::StatsDemo()
+ : IFireboltDemo()
+{
+ methodsFromRpc("Stats");
+}
+
+void StatsDemo::runOption(const int index)
+{
+ std::string key = names_[index];
+
+ outStream_ << "Running Stats method: " << key << std::endl;
+ if (key == "Stats.memoryUsage")
+ {
+ Result r = Firebolt::IFireboltAccessor::Instance().StatsInterface().memoryUsage();
+ if (validateResult(r))
+ {
+ MemoryInfo memInfo = r.value();
+ gOutput << "User Memory Used: " << memInfo.userMemoryUsed << " / " << memInfo.userMemoryLimit << std::endl;
+ gOutput << "GPU Memory Used: " << memInfo.gpuMemoryUsed << " / " << memInfo.gpuMemoryLimit << std::endl;
+ }
+ }
+}
diff --git a/test/cpp_test/cpp/statsDemo.h b/test/cpp_test/cpp/statsDemo.h
new file mode 100644
index 0000000..feb4147
--- /dev/null
+++ b/test/cpp_test/cpp/statsDemo.h
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#include
+#include
+#include "fireboltdemo.h"
+
+class StatsDemo : public IFireboltDemo
+{
+public:
+ StatsDemo();
+ ~StatsDemo() = default;
+ void runOption(const int index);
+};
diff --git a/test/cpp_test/cpp/utils.cpp b/test/cpp_test/cpp/utils.cpp
new file mode 100644
index 0000000..d3a13a0
--- /dev/null
+++ b/test/cpp_test/cpp/utils.cpp
@@ -0,0 +1,139 @@
+/*
+ * If not stated otherwise in this file or this component's LICENSE file the
+ * following copyright and licenses apply:
+ *
+ * Copyright 2025 Sky UK
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utils.h"
+
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+
+#define FAIL() std::cout
+
+// curl http get helper function using
+std::string httpGet(const std::string& url)
+{
+ CURL* curl = curl_easy_init();
+ if (!curl)
+ return "";
+ curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
+
+ struct curl_slist* headers = nullptr;
+ headers = curl_slist_append(headers, "Content-Type: application/json");
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+
+ std::string response;
+ curl_easy_setopt(
+ curl, CURLOPT_WRITEFUNCTION,
+ +[](char* ptr, size_t size, size_t nmemb, std::string* data)
+ {
+ data->append(ptr, size * nmemb);
+ return size * nmemb;
+ });
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
+
+ CURLcode res = curl_easy_perform(curl);
+ curl_easy_cleanup(curl);
+
+ return (res == CURLE_OK) ? response : "";
+}
+
+// curl http post helper function using
+std::string httpPost(const std::string& url, const std::string& postData)
+{
+ CURL* curl = curl_easy_init();
+ if (!curl)
+ return "";
+ curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
+ curl_easy_setopt(curl, CURLOPT_POST, 1L);
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData.c_str());
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, postData.size());
+
+ struct curl_slist* headers = nullptr;
+ headers = curl_slist_append(headers, "Content-Type: application/json");
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+
+ std::string response;
+ curl_easy_setopt(
+ curl, CURLOPT_WRITEFUNCTION,
+ +[](char* ptr, size_t size, size_t nmemb, std::string* data)
+ {
+ data->append(ptr, size * nmemb);
+ return size * nmemb;
+ });
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
+
+ CURLcode res = curl_easy_perform(curl);
+ curl_easy_cleanup(curl);
+
+ return (res == CURLE_OK) ? response : "";
+}
+
+void triggerRaw(const std::string& payload)
+{
+ httpPost("http://localhost:3333/api/v1/raw", payload);
+}
+
+void triggerEvent(const std::string& method, const std::string& params)
+{
+ nlohmann::json eventMessage;
+ eventMessage["method"] = method;
+ eventMessage["result"] = nlohmann::json::parse(params);
+
+ httpPost("http://localhost:3333/api/v1/event", eventMessage.dump());
+}
+
+void verifyEventSubscription(const Firebolt::Result& id)
+{
+ if (id)
+ {
+ std::cout << "Event Subscription is successful." << std::endl;
+ }
+ else
+ {
+ FAIL() << "Event Subscription failed. " + toError(id);
+ }
+}
+void verifyUnsubscribeResult(const Firebolt::Result& result)
+{
+
+ if (result.error() == Firebolt::Error::None)
+ {
+ std::cout << "Unsubscribe success" << std::endl;
+ }
+ else
+ {
+ FAIL() << "Unsubscribe failed." + toError(result);
+ }
+}
+void verifyEventReceived(std::mutex& mtx, std::condition_variable& cv, bool& eventReceived)
+{
+
+ // Wait for the event to be received or timeout after 5 seconds
+ std::unique_lock lock(mtx);
+ if (!cv.wait_for(lock, std::chrono::seconds(5), [&] { return eventReceived; }))
+ {
+ FAIL() << "Did not receive event within timeout";
+ }
+}
diff --git a/test/cpp_test/cpp/utils.h b/test/cpp_test/cpp/utils.h
new file mode 100644
index 0000000..0586900
--- /dev/null
+++ b/test/cpp_test/cpp/utils.h
@@ -0,0 +1,45 @@
+/*
+ * If not stated otherwise in this file or this component's LICENSE file the
+ * following copyright and licenses apply:
+ *
+ * Copyright 2025 Sky UK
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+
+std::string httpGet(const std::string& url);
+std::string httpPost(const std::string& url, const std::string& postData);
+
+void triggerEvent(const std::string& method, const std::string& params);
+void triggerRaw(const std::string& payload);
+
+void verifyEventSubscription(const Firebolt::Result& id);
+void verifyUnsubscribeResult(const Firebolt::Result& result);
+void verifyEventReceived(std::mutex& mtx, std::condition_variable& cv, bool& eventReceived);
+
+template inline std::string toError(const Firebolt::Result& result)
+{
+ if (result)
+ {
+ return "";
+ }
+ return "Error: " + std::to_string(static_cast(result.error()));
+}
diff --git a/test/cpp_test/main.cpp b/test/cpp_test/main.cpp
new file mode 100644
index 0000000..c7f5221
--- /dev/null
+++ b/test/cpp_test/main.cpp
@@ -0,0 +1,129 @@
+/**
+ * Copyright 2025 Comcast Cable Communications Management, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "cpp/chooseInterface.h"
+
+#include "cpp/outputstream.h"
+
+OutputStream gOutput;
+
+bool gConnected = false;
+bool gAutoRun = false;
+
+void connectionChanged(const bool connected, const Firebolt::Error error)
+{
+ std::cout << "Change in connection: connected: " << connected << " error: " << static_cast(error) << std::endl;
+ gConnected = connected;
+}
+
+void createFireboltInstance(const std::string& url)
+{
+ Firebolt::Config config;
+ config.wsUrl = url;
+ config.waitTime_ms = 1000;
+ config.log.level = Firebolt::LogLevel::Debug;
+
+ gConnected = false;
+ Firebolt::IFireboltAccessor::Instance().Connect(config, connectionChanged);
+}
+
+void destroyFireboltInstance()
+{
+ Firebolt::IFireboltAccessor::Instance().Disconnect();
+}
+
+bool waitOnConnectionReady()
+{
+ uint32_t waiting = 10000;
+ static constexpr uint32_t SLEEPSLOT_TIME = 100;
+
+ // Right, a wait till connection is closed is requested..
+ while ((waiting > 0) && (gConnected == false))
+ {
+
+ uint32_t sleepSlot = (waiting > SLEEPSLOT_TIME ? SLEEPSLOT_TIME : waiting);
+ // Right, lets sleep in slices of 100 ms
+ std::this_thread::sleep_for(std::chrono::milliseconds(sleepSlot));
+ waiting -= sleepSlot;
+ }
+ return gConnected;
+}
+
+int main(int argc, char** argv)
+{
+ gOutput = OutputStream("firebolt_test_output.txt");
+
+ gOutput << "Logging to file instead of console" << std::endl;
+
+ // check args for -auto option
+ for (int i = 1; i < argc; ++i)
+ {
+ std::cout << "Arg: " << argv[i] << std::endl;
+ if (std::string(argv[i]) == "-auto")
+ {
+ gAutoRun = true;
+ break;
+ }
+ }
+
+ std::string url = "ws://127.0.0.1:9998";
+ createFireboltInstance(url);
+
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+
+ // ::testing::InitGoogleTest(&argc, argv);
+ if (!waitOnConnectionReady())
+ {
+ std::cout << "Test not able to connect with server..." << std::endl;
+ return -1;
+ }
+
+ if (gAutoRun)
+ {
+ gOutput = OutputStream("firebolt_test_output.txt");
+ ChooseInterface chooseInterface;
+ chooseInterface.autoRun();
+ return 0;
+ }
+
+ gOutput = OutputStream();
+
+ ChooseInterface chooseInterface;
+
+ for (;;)
+ {
+ int interfaceIndex = chooseInterface.chooseOption();
+
+ if (interfaceIndex == -1)
+ {
+ break; // Exit the program
+ }
+
+ chooseInterface.runOption(interfaceIndex);
+ }
+
+ destroyFireboltInstance();
+
+ return 0;
+}