From d992255125a9a2a85184acc9a73222d694edb15b Mon Sep 17 00:00:00 2001 From: unai_71 Date: Tue, 10 Mar 2026 16:48:18 +0100 Subject: [PATCH 01/10] feat: added clang-format for code format enforcing/cohesion --- .clang-format | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..c039979 --- /dev/null +++ b/.clang-format @@ -0,0 +1,11 @@ +# Google style C++ Code Style settings +# https://clang.llvm.org/docs/ClangFormatStyleOptions.html + +Language: Cpp +BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignOperands: Align +AllowAllArgumentsOnNextLine: true +ColumnLimit: 80 +BreakBeforeBraces: Allman -- 2.49.1 From 409ee7aa359cf614ec5a3d22f6dc912a02851736 Mon Sep 17 00:00:00 2001 From: unai_71 Date: Tue, 10 Mar 2026 16:57:47 +0100 Subject: [PATCH 02/10] feat: added readme to focus development --- README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d1a9c05..017861e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,18 @@ # azkoyen_technical_test -Azkoyen technical test implementation. Implemented (mostly) on standard c++ 17 framework, but with Qt wherever was necessary \ No newline at end of file +Azkoyen technical test implementation. Implemented (mostly) on standard c++ 17 framework, but with Qt wherever was necessary. + +## Development approach + +A Test-Driven Development (TDD) workflow was followed throughout the project. Every component — from the lowest-level file reader to the GUI window — has a corresponding Google Test suite that was written before (or alongside) the production code. This ensures each module behaves correctly in isolation and makes regressions immediately visible. + +## SysfsRead class + +- Will convert the contents of a file and output an enum class +- Reads a sysfs-like file +- If the file is missing, the reader will output Unreachable +- If the file contains only a "1" the reader will output Enabled +- If the file contains "error: temp too high", the reader will output ErrorTempTooHigh +- if the file contains any other value the reader will output UnexpectedValue +- if the file is empty: it will output Empty + -- 2.49.1 From fabcf5a146b6294966c0f3d5c1063946e7c506f3 Mon Sep 17 00:00:00 2001 From: unai_71 Date: Tue, 10 Mar 2026 17:00:50 +0100 Subject: [PATCH 03/10] feat: declared enum class --- include/SysfsRead.hpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 include/SysfsRead.hpp diff --git a/include/SysfsRead.hpp b/include/SysfsRead.hpp new file mode 100644 index 0000000..9dde087 --- /dev/null +++ b/include/SysfsRead.hpp @@ -0,0 +1,20 @@ +// SysfsRead.hpp +// +// SPDX-License-Identifier GPL-3.0-or-later +// Author: Unai Blazquez Gomez + +#pragma once + +enum class SysfsStatus +{ + /// @brief File cannot be opened or does not exist. + Unreachable, + /// @brief File exists but is just empty. + Empty, + /// @brief File content indicates taht production is enabled (e.g. "1") + Enabled, + /// @brief File requests a cooldown ("error: temp too high") + ErrorTempTooHigh, + /// @brief File contains an UnexpectedValue; producer must not send. + UnexpectedValue +}; -- 2.49.1 From 159d55c2a2691f454106bb734a4585fe675fcb72 Mon Sep 17 00:00:00 2001 From: unai_71 Date: Tue, 10 Mar 2026 17:02:34 +0100 Subject: [PATCH 04/10] feat: declared skeleton of sysfsRead.hpp --- include/SysfsRead.hpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/include/SysfsRead.hpp b/include/SysfsRead.hpp index 9dde087..bf910f3 100644 --- a/include/SysfsRead.hpp +++ b/include/SysfsRead.hpp @@ -5,6 +5,8 @@ #pragma once +#include + enum class SysfsStatus { /// @brief File cannot be opened or does not exist. @@ -18,3 +20,21 @@ enum class SysfsStatus /// @brief File contains an UnexpectedValue; producer must not send. UnexpectedValue }; + +class SysfsReader +{ + public: + /// @brief Construct a SysfsReader bound to a specific input file path. + /// @param input_path Path to the sysfs-like input file. + explicit SysfsReader(const std::filesystem::path& input_path); + + /// @brief Read and interpret the current status of the input file. + /// + /// This function never throws on common I/O errors; instead it reports them + /// via the SysfsStatus enum. + /// @return Interpreted status of the input file + SysfsStatus read_status() const; + + private: + std::filesystem::path m_path; // Path to the input file. +}; -- 2.49.1 From cb8cfd6da87eca57ee735a73f5e63dcfba16f919 Mon Sep 17 00:00:00 2001 From: unai_71 Date: Tue, 10 Mar 2026 17:08:09 +0100 Subject: [PATCH 05/10] I forgot about the CMakeFile --- CMakeLists.txt | 20 ++++++++++++++++++++ tests/test_sysfs_read.cxx | 5 +++++ 2 files changed, 25 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 tests/test_sysfs_read.cxx diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..8a55ac0 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,20 @@ +# Root cmake file sketch (might change it later) +# Author: Unai Blazquez +# License: GPL-3-or-later + +cmake_minimum_required(VERSION 3.16) +project(azkoyen_ipc_test LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# Core library +add_library(core + src/core/SysfsRead.cxx +) + +target_include_directories(core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) + +#tests +enable_testing() +add_subdirectory(tests) diff --git a/tests/test_sysfs_read.cxx b/tests/test_sysfs_read.cxx new file mode 100644 index 0000000..0294220 --- /dev/null +++ b/tests/test_sysfs_read.cxx @@ -0,0 +1,5 @@ +#include + +#include + +#include "SysfsRead.hpp" -- 2.49.1 From 80dc5d62ebded8444491ec675c5d70ccb3e7e3fe Mon Sep 17 00:00:00 2001 From: unai_71 Date: Tue, 10 Mar 2026 16:11:50 +0000 Subject: [PATCH 06/10] fix: tests cmake file was missing --- tests/CMakeLists.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/CMakeLists.txt diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..ae62cc1 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,15 @@ +# Author: Unai Blazquez +# License: GPL-3-only + +add_executable(test_sysfs_reader + test_sysfs_read.cxx +) + +target_link_libraries(test_sysfs_reader + PRIVATE + core + gtest + gtest_main +) +add_test(NAME test_sysfs_reader COMMAND test_sysfs_reader) + -- 2.49.1 From 17133281d2bbf7c8b5f21a1f496e1f35d72effc8 Mon Sep 17 00:00:00 2001 From: unai_71 Date: Tue, 10 Mar 2026 16:23:47 +0000 Subject: [PATCH 07/10] fix: added build directory to the gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index bc87d63..f20cad4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ # ---> C++ +# build artifacts +build/ # Prerequisites *.d -- 2.49.1 From f04de7ea347b447dd679d9eae6df8f5e449f2aef Mon Sep 17 00:00:00 2001 From: unai_71 Date: Tue, 10 Mar 2026 16:24:35 +0000 Subject: [PATCH 08/10] feat: added Sysfs reader stub and tests, builds cleanly --- src/core/SysfsRead.cxx | 15 ++++++++ tests/test_sysfs_read.cxx | 72 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 src/core/SysfsRead.cxx diff --git a/src/core/SysfsRead.cxx b/src/core/SysfsRead.cxx new file mode 100644 index 0000000..962dbef --- /dev/null +++ b/src/core/SysfsRead.cxx @@ -0,0 +1,15 @@ +// SysfsRead.cxx + +// SPDX-License-Identifier: GPL-3.0-or-later +// Author: Unai Blazquez + +#include "SysfsRead.hpp" + +SysfsReader::SysfsReader(const std::filesystem::path& input_path) + : m_path(input_path) +{ +} +SysfsStatus SysfsReader::read_status() const +{ + return SysfsStatus::UnexpectedValue; +} diff --git a/tests/test_sysfs_read.cxx b/tests/test_sysfs_read.cxx index 0294220..417c006 100644 --- a/tests/test_sysfs_read.cxx +++ b/tests/test_sysfs_read.cxx @@ -3,3 +3,75 @@ #include #include "SysfsRead.hpp" + +TEST(SysfsReaderTest, ReturnsEnabledWhenFileContainsOne) +{ + // Arrange create the file and write "1\n" into it. + { + std::ofstream out("fake_sysfs_input"); + out << "1\n"; + // out is closed automatically at the end of this scope + } + + // 2) Act: construct the reader and read the status. + SysfsReader reader{"fake_sysfs_input"}; + SysfsStatus status = reader.read_status(); + // 3) Assert: we expect Enabled. + EXPECT_EQ(status, SysfsStatus::Enabled); +} + +TEST(SysfsReaderTest, ReturnsEmptyWhenFileIsEmpty) +{ + // Arrange: create the file and don't write anything + { + std::ofstream out("fake_sysfs_input"); + out << ""; + } + SysfsReader reader{"fake_sysfs_input"}; + SysfsStatus status1 = reader.read_status(); + + { + std::ofstream out("fake_sysfs_input"); + out << " "; + } + SysfsReader reader_2{"fake_sysfs_input"}; + SysfsStatus status2 = reader_2.read_status(); + + // Assert + EXPECT_EQ(status1, SysfsStatus::Empty); + EXPECT_EQ(status2, SysfsStatus::Empty); +} + +TEST(SysfsReaderTest, ReturnsUnexpectedValue) +{ + { + std::ofstream out("fake_sysfs_input"); + out << "tdd development"; + } + SysfsReader reader{"fake_sysfs_input"}; + SysfsStatus status = reader.read_status(); + + // Assert + EXPECT_EQ(status, SysfsStatus::UnexpectedValue); +} + +TEST(SysfsReaderTest, ReturnsErrorTempTooHigh) +{ + { + std::ofstream out("fake_sysfs_input"); + out << "error: temp too high"; + } + SysfsReader reader{"fake_sysfs_input"}; + SysfsStatus status = reader.read_status(); + + // Assert + EXPECT_EQ(status, SysfsStatus::ErrorTempTooHigh); +} + +TEST(SysfsReaderTest, ReturnsUnreachableWhenDoesntExist) +{ + SysfsReader reader{"nonexistent_sysfs_input"}; + SysfsStatus status = reader.read_status(); + // Assert + EXPECT_EQ(status, SysfsStatus::Unreachable); +} -- 2.49.1 From 6e1cdec81f08f92ec106663c51cea4a4d3d826f4 Mon Sep 17 00:00:00 2001 From: unai_71 Date: Tue, 10 Mar 2026 16:30:03 +0000 Subject: [PATCH 09/10] feat: implemented sysfs reader class, added new trim method to clean strings --- include/SysfsRead.hpp | 4 ++++ src/core/SysfsRead.cxx | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/include/SysfsRead.hpp b/include/SysfsRead.hpp index bf910f3..c8c9e34 100644 --- a/include/SysfsRead.hpp +++ b/include/SysfsRead.hpp @@ -36,5 +36,9 @@ class SysfsReader SysfsStatus read_status() const; private: + /// @brief Helper method for trimming trailing whitespaces and + /// newline indicators + /// @param String from the m_path file + static void trim_in_place(std::string& string); std::filesystem::path m_path; // Path to the input file. }; diff --git a/src/core/SysfsRead.cxx b/src/core/SysfsRead.cxx index 962dbef..807bcbf 100644 --- a/src/core/SysfsRead.cxx +++ b/src/core/SysfsRead.cxx @@ -5,11 +5,52 @@ #include "SysfsRead.hpp" +#include +#include + SysfsReader::SysfsReader(const std::filesystem::path& input_path) : m_path(input_path) { } + SysfsStatus SysfsReader::read_status() const { + std::ifstream input_file_stream(m_path); + if (!input_file_stream.is_open()) + { + return SysfsStatus::Unreachable; + } + std::stringstream buffer; + buffer << input_file_stream.rdbuf(); // read entire stream into buffer + std::string contents = buffer.str(); + + trim_in_place(contents); // clean input string + // compare + if (contents.empty()) + { + return SysfsStatus::Empty; + } + if (contents == "1") + { + return SysfsStatus::Enabled; + } + if (contents == "error: temp too high") + { + return SysfsStatus::ErrorTempTooHigh; + } return SysfsStatus::UnexpectedValue; } + +void SysfsReader::trim_in_place(std::string& string) +{ + // left trim + string.erase(string.begin(), + std::find_if(string.begin(), string.end(), [](unsigned char ch) + { return !std::isspace(ch); })); + + // right trim + string.erase(std::find_if(string.rbegin(), string.rend(), + [](unsigned char ch) { return !std::isspace(ch); }) + .base(), + string.end()); +} -- 2.49.1 From f07bec25f89e79c4f0fa976fc96640766ea61801 Mon Sep 17 00:00:00 2001 From: unai_71 Date: Tue, 10 Mar 2026 16:33:08 +0000 Subject: [PATCH 10/10] feat: updated readme --- README.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 017861e..8c289fb 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,16 @@ A Test-Driven Development (TDD) workflow was followed throughout the project. Ev ## SysfsRead class -- Will convert the contents of a file and output an enum class -- Reads a sysfs-like file -- If the file is missing, the reader will output Unreachable -- If the file contains only a "1" the reader will output Enabled -- If the file contains "error: temp too high", the reader will output ErrorTempTooHigh -- if the file contains any other value the reader will output UnexpectedValue -- if the file is empty: it will output Empty +`SysfsReader` ([include/SysfsRead.hpp](include/SysfsRead.hpp), [src/core/SysfsRead.cxx](src/core/SysfsRead.cxx)) is the lowest-level component. It opens a sysfs-like file and translates its raw text content into a `SysfsStatus` enum: +| File content | Status | +|--------------------------|---------------------| +| `"1"` | `Enabled` | +| `"error: temp too high"` | `ErrorTempTooHigh` | +| empty / whitespace-only | `Empty` | +| file missing | `Unreachable` | +| anything else | `UnexpectedValue` | + +The reader never throws on I/O errors; every outcome is expressed through the enum so callers can react without exception handling. A helper `trim_in_place` strips trailing whitespace and newlines before comparison. + +**Tests:** [tests/test_sysfs_read.cxx](tests/test_sysfs_read.cxx) — covers all five status branches by writing controlled content to a temporary file. -- 2.49.1