* add buffered writer * rename
This commit is contained in:
parent
f5cece03e5
commit
605e2590f1
|
@ -0,0 +1,63 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
struct Writer {
|
||||||
|
virtual size_t write(const char* buffer, size_t count) = 0;
|
||||||
|
virtual size_t flush() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <int TBufferSize>
|
||||||
|
class BufferedWriter : public Writer {
|
||||||
|
public:
|
||||||
|
size_t write(const char* buffer, size_t count) override {
|
||||||
|
size_t bytesFlushed = 0;
|
||||||
|
|
||||||
|
while (count) {
|
||||||
|
if (m_bytesUsed == 0 && count >= TBufferSize) {
|
||||||
|
// special case: write-thru, skip the copy
|
||||||
|
bytesFlushed += writeInternal(buffer, count);
|
||||||
|
count = 0;
|
||||||
|
} else if (m_bytesUsed + count < TBufferSize) {
|
||||||
|
// Write that will fit in the buffer, just copy to intermediate buffer
|
||||||
|
memcpy(m_buffer + m_bytesUsed, buffer, count);
|
||||||
|
m_bytesUsed += count;
|
||||||
|
count = 0;
|
||||||
|
} else {
|
||||||
|
// Need to write partial, then flush buffer
|
||||||
|
size_t bytesToWrite = TBufferSize - m_bytesUsed;
|
||||||
|
// Copy this block in to place
|
||||||
|
memcpy(m_buffer + m_bytesUsed, buffer, bytesToWrite);
|
||||||
|
m_bytesUsed += bytesToWrite;
|
||||||
|
|
||||||
|
// Flush to underlying
|
||||||
|
bytesFlushed += flush();
|
||||||
|
// Step the read pointer ahead
|
||||||
|
buffer += bytesToWrite;
|
||||||
|
// Decrement remaining bytes
|
||||||
|
count -= bytesToWrite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesFlushed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush the internal buffer to the underlying interface.
|
||||||
|
size_t flush() override {
|
||||||
|
size_t bytesToWrite = m_bytesUsed;
|
||||||
|
|
||||||
|
if (bytesToWrite > 0) {
|
||||||
|
m_bytesUsed = 0;
|
||||||
|
return writeInternal(m_buffer, bytesToWrite);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual size_t writeInternal(const char* buffer, size_t count) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
char m_buffer[TBufferSize];
|
||||||
|
size_t m_bytesUsed = 0;
|
||||||
|
};
|
|
@ -14,6 +14,7 @@ TESTS_SRC_CPP = \
|
||||||
tests/ignition_injection/test_fuelCut.cpp \
|
tests/ignition_injection/test_fuelCut.cpp \
|
||||||
tests/ignition_injection/test_fuel_computer.cpp \
|
tests/ignition_injection/test_fuel_computer.cpp \
|
||||||
tests/ignition_injection/test_injector_model.cpp \
|
tests/ignition_injection/test_injector_model.cpp \
|
||||||
|
tests/util/test_buffered_writer.cpp \
|
||||||
tests/test_util.cpp \
|
tests/test_util.cpp \
|
||||||
tests/test_hardware_reinit.cpp \
|
tests/test_hardware_reinit.cpp \
|
||||||
tests/test_ion.cpp \
|
tests/test_ion.cpp \
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
#include "buffered_writer.h"
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
|
using ::testing::_;
|
||||||
|
using ::testing::Return;
|
||||||
|
using ::testing::StrictMock;
|
||||||
|
|
||||||
|
template <int TBufferSize>
|
||||||
|
struct MockBufferedWriter : public BufferedWriter<TBufferSize>
|
||||||
|
{
|
||||||
|
MOCK_METHOD(size_t, writeInternal, (const char*, size_t), (override));
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char* testBuffer = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||||
|
|
||||||
|
TEST(BufferedWriter, WriteSmall) {
|
||||||
|
// No calls to dut expected
|
||||||
|
StrictMock<MockBufferedWriter<10>> dut;
|
||||||
|
|
||||||
|
EXPECT_EQ(0, dut.write(testBuffer, 5));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BufferedWriter, WriteSmallFlush) {
|
||||||
|
StrictMock<MockBufferedWriter<10>> dut;
|
||||||
|
EXPECT_CALL(dut, writeInternal(_, 5)).WillOnce(Return(5));
|
||||||
|
|
||||||
|
ASSERT_EQ(0, dut.write(testBuffer, 5));
|
||||||
|
|
||||||
|
EXPECT_EQ(dut.flush(), 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BufferedWriter, WriteMultipleSmall) {
|
||||||
|
StrictMock<MockBufferedWriter<10>> dut;
|
||||||
|
{
|
||||||
|
EXPECT_CALL(dut, writeInternal(_, 10)).WillOnce(Return(10));
|
||||||
|
EXPECT_CALL(dut, writeInternal(_, 2)).WillOnce(Return(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(0, dut.write(testBuffer, 3));
|
||||||
|
EXPECT_EQ(0, dut.write(testBuffer, 3));
|
||||||
|
EXPECT_EQ(0, dut.write(testBuffer, 3));
|
||||||
|
EXPECT_EQ(10, dut.write(testBuffer, 3)); // <- this one should trigger a flush
|
||||||
|
|
||||||
|
// Flush the remainder
|
||||||
|
EXPECT_EQ(dut.flush(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BufferedWriter, WriteSingleFullBufferSize) {
|
||||||
|
StrictMock<MockBufferedWriter<50>> dut;
|
||||||
|
|
||||||
|
EXPECT_CALL(dut, writeInternal(_, 50)).WillOnce(Return(50));
|
||||||
|
|
||||||
|
EXPECT_EQ(50, dut.write(testBuffer, 50));
|
||||||
|
|
||||||
|
// Nothing left to flush!
|
||||||
|
EXPECT_EQ(0, dut.flush());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BufferedWriter, WriteLarge) {
|
||||||
|
StrictMock<MockBufferedWriter<10>> dut;
|
||||||
|
|
||||||
|
{
|
||||||
|
EXPECT_CALL(dut, writeInternal(_, 45)).WillOnce(Return(45));
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(45, dut.write(testBuffer, 45));
|
||||||
|
|
||||||
|
EXPECT_EQ(0, dut.flush());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BufferedWriter, WriteLargeAfterSmall) {
|
||||||
|
StrictMock<MockBufferedWriter<10>> dut;
|
||||||
|
|
||||||
|
{
|
||||||
|
EXPECT_CALL(dut, writeInternal(_, 10)).WillOnce(Return(10));
|
||||||
|
EXPECT_CALL(dut, writeInternal(_, 36)).WillOnce(Return(36));
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(0, dut.write(testBuffer, 1));
|
||||||
|
|
||||||
|
EXPECT_EQ(46, dut.write(testBuffer, 45));
|
||||||
|
|
||||||
|
EXPECT_EQ(0, dut.flush());
|
||||||
|
}
|
Loading…
Reference in New Issue