• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

wirenboard / wb-mqtt-serial / 666

08 Jul 2025 11:10AM UTC coverage: 73.854% (+0.1%) from 73.706%
666

push

github

web-flow
Port handling refactoring (#960)

Pass port by reference when needed instead of storing it in every device

6444 of 9057 branches covered (71.15%)

526 of 700 new or added lines in 56 files covered. (75.14%)

6 existing lines in 5 files now uncovered.

12341 of 16710 relevant lines covered (73.85%)

305.53 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.79
/test/fake_serial_device.cpp
1
#include "fake_serial_device.h"
2
#include "fake_serial_port.h"
3

4
using namespace std;
5

6
namespace // utility
7
{
8
    uint64_t GetValue(uint16_t* src, int width)
312✔
9
    {
10
        uint64_t res = 0;
312✔
11
        for (int i = 0; i < width; ++i) {
804✔
12
            auto bitCount = ((width - i) - 1) * 16;
492✔
13
            res |= uint64_t(src[i]) << bitCount;
492✔
14
        }
15
        return res;
312✔
16
    }
17

18
    void SetValue(uint16_t* dst, int width, uint64_t value)
102✔
19
    {
20
        for (int p = width - 1; p >= 0; --p) {
249✔
21
            dst[p] = value & 0xffff;
147✔
22
            value >>= 16;
147✔
23
        }
24
    }
102✔
25

26
    class TFakeRegisterRange: public TRegisterRange
27
    {
28
    public:
29
        TFakeRegisterRange()
175✔
30
        {}
175✔
31

32
        bool Add(TPort& port, PRegister reg, std::chrono::milliseconds pollLimit) override
387✔
33
        {
34
            if (HasOtherDeviceAndType(reg)) {
387✔
35
                return false;
×
36
            }
37
            RegisterList().push_back(reg);
387✔
38
            return true;
387✔
39
        }
40
    };
41

42
}; // utility
43

44
std::list<TFakeSerialDevice*> TFakeSerialDevice::Devices;
45

46
void TFakeSerialDevice::Register(TSerialDeviceFactory& factory)
141✔
47
{
48
    factory.RegisterProtocol(
141✔
49
        new TUint32SlaveIdProtocol("fake", TRegisterTypes({{TFakeSerialDevice::REG_FAKE, "fake", "text", U16}})),
423✔
50
        new TBasicDeviceFactory<TFakeSerialDevice>("#/definitions/simple_device_with_setup",
51
                                                   "#/definitions/common_channel"));
282✔
52
}
141✔
53

54
TFakeSerialDevice::TFakeSerialDevice(PDeviceConfig config, PProtocol protocol)
147✔
55
    : TSerialDevice(config, protocol),
56
      TUInt32SlaveId(config->SlaveId),
294✔
57
      Connected(true),
58
      SessionLogEnabled(false)
147✔
59
{
60
    Devices.push_back(this);
147✔
61
}
147✔
62

63
TRegisterValue TFakeSerialDevice::ReadRegisterImpl(TPort& port, const TRegisterConfig& reg)
363✔
64
{
65
    CheckFakePort();
363✔
66
    try {
67
        if (!FakePort->IsOpen()) {
363✔
68
            throw TSerialDeviceException("port not open");
×
69
        }
70

71
        if (!Connected) {
363✔
72
            throw TSerialDeviceTransientErrorException("device disconnected");
33✔
73
        }
74

75
        auto addr = GetUint32RegisterAddress(reg.GetAddress());
330✔
76

77
        if (Blockings[addr].first) {
330✔
78
            throw TSerialDeviceTransientErrorException("read blocked");
14✔
79
        }
80

81
        if (addr < 0 || addr > 256) {
316✔
82
            throw runtime_error("invalid register address");
×
83
        }
84

85
        if (reg.Type != REG_FAKE) {
316✔
86
            throw runtime_error("invalid register type");
×
87
        }
88

89
        TRegisterValue value;
632✔
90
        if (reg.IsString()) {
316✔
91
            std::string str;
8✔
92
            for (uint32_t i = 0; i < reg.Get16BitWidth(); ++i) {
132✔
93
                auto ch = static_cast<char>(Registers[addr + i]);
128✔
94
                if (ch != '\0') {
128✔
95
                    str.push_back(ch);
29✔
96
                }
97
            }
98
            value.Set(str);
4✔
99
        } else {
100
            value.Set(GetValue(&Registers[addr], reg.Get16BitWidth()));
312✔
101
        }
102

103
        FakePort->GetFixture().Emit() << "fake_serial_device '" << SlaveId << "': read address '" << reg.GetAddress()
632✔
104
                                      << "' value '" << value << "'";
316✔
105
        return value;
632✔
106
    } catch (const exception& e) {
94✔
107
        FakePort->GetFixture().Emit() << "fake_serial_device '" << SlaveId << "': read address '" << reg.GetAddress()
47✔
108
                                      << "' failed: '" << e.what() << "'";
47✔
109

110
        throw;
47✔
111
    }
112
}
113

114
void TFakeSerialDevice::WriteRegisterImpl(TPort& port, const TRegisterConfig& reg, const TRegisterValue& value)
118✔
115
{
116
    CheckFakePort();
118✔
117
    try {
118
        if (!FakePort->IsOpen()) {
118✔
119
            throw TSerialDeviceException("port not open");
×
120
        }
121

122
        if (!Connected) {
118✔
123
            throw TSerialDeviceTransientErrorException("device disconnected");
5✔
124
        }
125

126
        auto addr = GetUint32RegisterAddress(reg.GetAddress());
113✔
127

128
        if (Blockings[addr].second) {
113✔
129
            throw TSerialDeviceTransientErrorException("write blocked");
10✔
130
        }
131

132
        if (addr < 0 || addr > 256) {
103✔
133
            throw runtime_error("invalid register address");
×
134
        }
135

136
        if (reg.Type != REG_FAKE) {
103✔
137
            throw runtime_error("invalid register type");
×
138
        }
139

140
        if (reg.IsString()) {
103✔
141
            auto str = value.Get<std::string>();
2✔
142
            for (uint32_t i = 0; i < reg.Get16BitWidth(); ++i) {
33✔
143
                Registers[addr + i] = i < str.size() ? str[i] : 0;
32✔
144
            }
145
        } else {
146
            SetValue(&Registers[addr], reg.Get16BitWidth(), value.Get<uint64_t>());
102✔
147
        }
148
        FakePort->GetFixture().Emit() << "fake_serial_device '" << SlaveId << "': write to address '"
206✔
149
                                      << reg.GetAddress() << "' value '" << value << "'";
103✔
150

151
    } catch (const exception& e) {
30✔
152
        FakePort->GetFixture().Emit() << "fake_serial_device '" << SlaveId << "': write address '" << reg.GetAddress()
15✔
153
                                      << "' failed: '" << e.what() << "'";
15✔
154

155
        throw;
15✔
156
    }
157
}
103✔
158

159
void TFakeSerialDevice::SetTransferResult(bool ok)
469✔
160
{
161
    CheckFakePort();
469✔
162
    auto initialConnectionState = GetConnectionState();
469✔
163
    if ((initialConnectionState != TDeviceConnectionState::CONNECTED) && ok) {
469✔
164
        FakePort->GetFixture().Emit() << "fake_serial_device '" << SlaveId << "': transfer OK";
47✔
165
    }
166
    if (!ok) {
469✔
167
        FakePort->GetFixture().Emit() << "fake_serial_device '" << SlaveId << "': transfer FAIL";
70✔
168
    }
169

170
    TSerialDevice::SetTransferResult(ok);
469✔
171

172
    if (initialConnectionState != GetConnectionState()) {
469✔
173
        if (GetConnectionState() == TDeviceConnectionState::CONNECTED) {
57✔
174
            FakePort->GetFixture().Emit() << "fake_serial_device '" << SlaveId << "': reconnected";
47✔
175
        } else {
176
            FakePort->GetFixture().Emit() << "fake_serial_device '" << SlaveId << "': disconnected";
10✔
177
        }
178
    }
179
}
469✔
180

181
void TFakeSerialDevice::BlockReadFor(int addr, bool block)
8✔
182
{
183
    CheckFakePort();
8✔
184
    Blockings[addr].first = block;
8✔
185
    FakePort->GetFixture().Emit() << "fake_serial_device: " << (block ? "block" : "unblock") << " address '" << addr
16✔
186
                                  << "' for reading";
8✔
187
}
8✔
188

189
void TFakeSerialDevice::BlockWriteFor(int addr, bool block)
16✔
190
{
191
    CheckFakePort();
16✔
192
    Blockings[addr].second = block;
16✔
193
    FakePort->GetFixture().Emit() << "fake_serial_device: " << (block ? "block" : "unblock") << " address '" << addr
32✔
194
                                  << "' for writing";
16✔
195
}
16✔
196

197
uint32_t TFakeSerialDevice::Read2Registers(int addr)
9✔
198
{
199
    return (uint32_t(Registers[addr]) << 16) | Registers[addr + 1];
9✔
200
}
201

202
void TFakeSerialDevice::SetIsConnected(bool connected)
12✔
203
{
204
    Connected = connected;
12✔
205
}
12✔
206

207
TFakeSerialDevice::~TFakeSerialDevice()
238✔
208
{
209
    Devices.erase(std::remove(Devices.begin(), Devices.end(), this), Devices.end());
238✔
210
}
211

212
TFakeSerialDevice* TFakeSerialDevice::GetDevice(const std::string& slaveId)
24✔
213
{
214
    for (auto device: Devices) {
72✔
215
        if (device->DeviceConfig()->SlaveId == slaveId) {
72✔
216
            return device;
24✔
217
        }
218
    }
219
    return nullptr;
×
220
}
221

222
void TFakeSerialDevice::ClearDevices()
43✔
223
{
224
    Devices.clear();
43✔
225
}
43✔
226

227
PRegisterRange TFakeSerialDevice::CreateRegisterRange() const
175✔
228
{
229
    return std::make_shared<TFakeRegisterRange>();
175✔
230
}
231

232
void TFakeSerialDevice::SetSessionLogEnabled(bool enabled)
1✔
233
{
234
    SessionLogEnabled = enabled;
1✔
235
}
1✔
236

237
void TFakeSerialDevice::PrepareImpl(TPort& port)
70✔
238
{
239
    CheckFakePort();
70✔
240
    TSerialDevice::PrepareImpl(port);
70✔
241
    if (SessionLogEnabled) {
70✔
242
        FakePort->GetFixture().Emit() << "fake_serial_device '" << SlaveId << "': prepare";
4✔
243
    }
244
}
70✔
245

246
void TFakeSerialDevice::EndSession(TPort& port)
15✔
247
{
248
    CheckFakePort();
15✔
249
    if (SessionLogEnabled) {
15✔
250
        FakePort->GetFixture().Emit() << "fake_serial_device '" << SlaveId << "': end session";
3✔
251
    }
252
}
15✔
253

254
void TFakeSerialDevice::SetFakePort(PFakeSerialPort fakePort)
147✔
255
{
256
    FakePort = fakePort;
147✔
257
}
147✔
258

259
void TFakeSerialDevice::CheckFakePort() const
1,059✔
260
{
261
    if (!FakePort) {
1,059✔
NEW
262
        throw runtime_error("not fake serial port passed to fake serial device");
×
263
    }
264
}
1,059✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc