feature/SysfsReaderClass #2
11
.clang-format
Normal file
11
.clang-format
Normal file
@ -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
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,6 @@
|
|||||||
# ---> C++
|
# ---> C++
|
||||||
|
# build artifacts
|
||||||
|
build/
|
||||||
# Prerequisites
|
# Prerequisites
|
||||||
*.d
|
*.d
|
||||||
|
|
||||||
|
|||||||
20
CMakeLists.txt
Normal file
20
CMakeLists.txt
Normal file
@ -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)
|
||||||
22
README.md
22
README.md
@ -1,3 +1,23 @@
|
|||||||
# azkoyen_technical_test
|
# azkoyen_technical_test
|
||||||
|
|
||||||
Azkoyen technical test implementation. Implemented (mostly) on standard c++ 17 framework, but with Qt wherever was necessary
|
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
|
||||||
|
|
||||||
|
`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.
|
||||||
|
|||||||
44
include/SysfsRead.hpp
Normal file
44
include/SysfsRead.hpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// SysfsRead.hpp
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier GPL-3.0-or-later
|
||||||
|
// Author: Unai Blazquez Gomez <unaibg2000@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
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:
|
||||||
|
/// @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.
|
||||||
|
};
|
||||||
56
src/core/SysfsRead.cxx
Normal file
56
src/core/SysfsRead.cxx
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// SysfsRead.cxx
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Author: Unai Blazquez <unaibg2000@gmail.com>
|
||||||
|
|
||||||
|
#include "SysfsRead.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
15
tests/CMakeLists.txt
Normal file
15
tests/CMakeLists.txt
Normal file
@ -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)
|
||||||
|
|
||||||
77
tests/test_sysfs_read.cxx
Normal file
77
tests/test_sysfs_read.cxx
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user