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++
|
||||
# build artifacts
|
||||
build/
|
||||
# Prerequisites
|
||||
*.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 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