Skip to content

Commit 2bcbf68

Browse files
authored
🔀 Merge pull request #17 from NestorDP/feat-improve-tests
Feat improve tests
2 parents a63505b + 89d894a commit 2bcbf68

File tree

3 files changed

+130
-39
lines changed

3 files changed

+130
-39
lines changed

‎include/libserial/serial.hpp‎

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,15 @@ size_t getMaxSafeReadSize() const;
330330
*/
331331
int getBaudRate() const;
332332

333+
/**
334+
* @brief Gets the current data length setting
335+
*
336+
* Retrieves the number of data bits configured for serial communication.
337+
*
338+
* @return The current data length (number of data bits)
339+
*/
340+
DataLength getDataLength() const;
341+
333342
#ifdef BUILD_TESTING_ON
334343
// WARNING: Test helper only! This function bypasses normal initialization
335344
// and may leave the Serial object in an inconsistent state. It is intended
@@ -341,19 +350,43 @@ void setFdForTest(int fd) {
341350
// WARNING: Test helper only! This function allows injection of custom
342351
// system call functions for testing error handling. It should NEVER be
343352
// used in production code.
344-
void setSystemCallFunctions(
345-
std::function<int(struct pollfd*, nfds_t, int)> poll_func,
346-
std::function<ssize_t(int, void*, size_t)> read_func) {
353+
void setPollSystemFunction(
354+
std::function<int(struct pollfd*, nfds_t, int)> poll_func) {
347355
poll_ = [poll_func](struct pollfd* f, nfds_t n, int t) {
348356
return poll_func(f, n, t);
349357
};
358+
}
359+
360+
void setReadSystemFunction(
361+
std::function<ssize_t(int, void*, size_t)> read_func) {
350362
read_ = [read_func](int fd, void* buf, size_t sz) {
351363
return read_func(fd, buf, sz);
352364
};
353365
}
366+
367+
/* *INDENT-OFF* */
368+
void setIoctlSystemFunction(
369+
std::function<int(int, unsigned long, void*)> ioctl_func) { // NOLINT
370+
ioctl_ = [ioctl_func](int fd, unsigned long request, void* arg) { // NOLINT
371+
return ioctl_func(fd, request, arg);
372+
};
373+
}
374+
/* *INDENT-ON* */
354375
#endif
355376

356377
private:
378+
/**
379+
* @brief Ioctl system call function wrapper
380+
*
381+
* Allows injection of custom ioctl function for testing.
382+
*/
383+
/* *INDENT-OFF* */
384+
std::function<int(int, unsigned long, void*)> ioctl_ = // NOLINT
385+
[](int fd, unsigned long request, void* arg) { // NOLINT
386+
return ::ioctl(fd, request, arg);
387+
};
388+
/* *INDENT-ON* */
389+
357390
/**
358391
* @brief Poll system call function wrapper
359392
*
@@ -456,13 +489,6 @@ uint16_t min_number_char_read_{0};
456489
*/
457490
CanonicalMode canonical_mode_{CanonicalMode::ENABLE};
458491

459-
/**
460-
* @brief Data length setting
461-
*
462-
* Specifies the number of data bits per character (default EIGHT).
463-
*/
464-
DataLength data_length_{DataLength::EIGHT};
465-
466492
/**
467493
* @brief Line terminator character
468494
*

‎src/serial.cpp‎

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -189,11 +189,18 @@ size_t Serial::readUntil(std::shared_ptr<std::string> buffer, char terminator) {
189189
}
190190

191191
void Serial::flushInputBuffer() {
192-
if (ioctl(fd_serial_port_, TCFLSH, TCIFLUSH) != 0) {
192+
if (ioctl_(fd_serial_port_, TCFLSH, TCIFLUSH) != 0) {
193193
throw SerialException("Error flushing input buffer: " + std::string(strerror(errno)));
194194
}
195195
}
196196

197+
void Serial::setTermios2() {
198+
ssize_t error = ioctl_(fd_serial_port_, TCSETS2, &options_);
199+
if (error < 0) {
200+
throw SerialException("Error set Termios2: " + std::string(strerror(errno)));
201+
}
202+
}
203+
197204
void Serial::setBaudRate(unsigned int baud_rate) {
198205
this->getTermios2();
199206
options_.c_cflag &= ~CBAUD;
@@ -207,13 +214,6 @@ void Serial::setBaudRate(BaudRate baud_rate) {
207214
this->setBaudRate(static_cast<unsigned int>(baud_rate));
208215
}
209216

210-
void Serial::setTermios2() {
211-
ssize_t error = ioctl(fd_serial_port_, TCSETS2, &options_);
212-
if (error < 0) {
213-
throw SerialException("Error set Termios2: " + std::string(strerror(errno)));
214-
}
215-
}
216-
217217
void Serial::setReadTimeout(std::chrono::milliseconds timeout) {
218218
read_timeout_ms_ = timeout;
219219
}
@@ -223,10 +223,7 @@ void Serial::setWriteTimeout(std::chrono::milliseconds timeout) {
223223
}
224224

225225
void Serial::setDataLength(DataLength nbits) {
226-
data_length_ = nbits;
227-
228226
this->getTermios2();
229-
// Clear bits
230227
options_.c_cflag &= ~CSIZE;
231228
switch (nbits) {
232229
case DataLength::FIVE:
@@ -355,7 +352,7 @@ size_t Serial::getMaxSafeReadSize() const {
355352

356353
int Serial::getAvailableData() const {
357354
int bytes_available;
358-
if (ioctl(fd_serial_port_, FIONREAD, &bytes_available) < 0) {
355+
if (ioctl_(fd_serial_port_, FIONREAD, &bytes_available) < 0) {
359356
throw SerialException("Error getting available data: " + std::string(strerror(errno)));
360357
}
361358
return bytes_available;
@@ -366,8 +363,19 @@ int Serial::getBaudRate() const {
366363
return (static_cast<int>(options_.c_ispeed));
367364
}
368365

366+
DataLength Serial::getDataLength() const {
367+
this->getTermios2();
368+
switch (options_.c_cflag & CSIZE) {
369+
case CS5: return DataLength::FIVE;
370+
case CS6: return DataLength::SIX;
371+
case CS7: return DataLength::SEVEN;
372+
case CS8: return DataLength::EIGHT;
373+
default: return DataLength::EIGHT;
374+
}
375+
}
376+
369377
void Serial::getTermios2() const {
370-
ssize_t error = ioctl(fd_serial_port_, TCGETS2, &options_);
378+
ssize_t error = ioctl_(fd_serial_port_, TCGETS2, &options_);
371379
if (error < 0) {
372380
throw SerialException("Error get Termios2: " + std::string(strerror(errno)));
373381
}

‎test/test_serial_pty.cpp‎

Lines changed: 73 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,31 @@ TEST_F(PseudoTerminalTest, ParameterizedConstructor) {
102102
libserial::Serial serial_port(slave_port_);
103103
}
104104

105+
TEST_F(PseudoTerminalTest, SetTermios2WithFail) {
106+
libserial::Serial serial_port;
107+
108+
serial_port.open(slave_port_);
109+
110+
// Inject failure into ioctl for setTermios2
111+
serial_port.setIoctlSystemFunction(
112+
[](int, unsigned long, void*) -> int { // NOLINT
113+
errno = EIO;
114+
return -1;
115+
});
116+
117+
EXPECT_THROW({
118+
serial_port.setBaudRate(9600);
119+
}, libserial::SerialException);
120+
121+
// Restore ioctl function for cleanup
122+
serial_port.setIoctlSystemFunction(
123+
[](int fd, unsigned long request, void* arg) -> int { // NOLINT
124+
return ::ioctl(fd, request, arg);
125+
});
126+
127+
serial_port.close();
128+
}
129+
105130
TEST_F(PseudoTerminalTest, SetAndGetBaudRate) {
106131
libserial::Serial serial_port;
107132

@@ -125,6 +150,45 @@ TEST_F(PseudoTerminalTest, SetAndGetBaudRate) {
125150
serial_port.close();
126151
}
127152

153+
// TEST_F(PseudoTerminalTest, SetAndGetDataLength) {
154+
// libserial::Serial serial_port;
155+
156+
// serial_port.open(slave_port_);
157+
158+
// // Test multiple data lengths to be more thorough
159+
// std::vector<libserial::DataLength> test_lengths = {
160+
// libserial::DataLength::FIVE,
161+
// libserial::DataLength::SIX,
162+
// libserial::DataLength::SEVEN,
163+
// libserial::DataLength::EIGHT
164+
// };
165+
166+
// for (const auto& expected_length : test_lengths) {
167+
// // Set data length
168+
// EXPECT_NO_THROW({
169+
// serial_port.setDataLength(expected_length);
170+
// });
171+
172+
// // Add a small delay and flush
173+
// std::this_thread::sleep_for(std::chrono::milliseconds(50));
174+
175+
// // Force a re-read of the current settings
176+
// serial_port.close();
177+
// serial_port.open(slave_port_);
178+
179+
// // Get data length and verify
180+
// libserial::DataLength actual_length;
181+
// EXPECT_NO_THROW({
182+
// actual_length = serial_port.getDataLength();
183+
// });
184+
185+
// EXPECT_EQ(actual_length, expected_length)
186+
// << "Failed for data length: " << static_cast<int>(expected_length);
187+
// }
188+
189+
// serial_port.close();
190+
// }
191+
128192
TEST_F(PseudoTerminalTest, SetParity) {
129193
libserial::Serial serial_port;
130194

@@ -309,10 +373,11 @@ TEST_F(PseudoTerminalTest, ReadWithReadFail) {
309373
auto read_buffer = std::make_shared<std::string>();
310374

311375
for (const auto& [error_num, error_msg] : errors_read_) {
312-
serial_port.setSystemCallFunctions(
376+
serial_port.setPollSystemFunction(
313377
[](struct pollfd*, nfds_t, int) -> int {
314378
return 1;
315-
},
379+
});
380+
serial_port.setReadSystemFunction(
316381
[error_num](int, void*, size_t) -> ssize_t {
317382
errno = error_num;
318383
return -1;
@@ -337,13 +402,10 @@ TEST_F(PseudoTerminalTest, ReadWithPollFail) {
337402
auto read_buffer = std::make_shared<std::string>();
338403

339404
for (const auto& [error_num, error_msg] : errors_poll_) {
340-
serial_port.setSystemCallFunctions(
405+
serial_port.setPollSystemFunction(
341406
[error_num](struct pollfd*, nfds_t, int) -> int {
342407
errno = error_num;
343408
return -1;
344-
},
345-
[](int, void*, size_t) -> ssize_t {
346-
return 1;
347409
});
348410

349411
auto expected_what = "Error in poll(): " + error_msg;
@@ -436,10 +498,7 @@ TEST_F(PseudoTerminalTest, ReadBytesWithReadFail) {
436498
auto read_buffer = std::make_shared<std::string>();
437499

438500
for (const auto& [error_num, error_msg] : errors_read_) {
439-
serial_port.setSystemCallFunctions(
440-
[](struct pollfd*, nfds_t, int) -> int {
441-
return 1;
442-
},
501+
serial_port.setReadSystemFunction(
443502
[error_num](int, void*, size_t) -> ssize_t {
444503
errno = error_num;
445504
return -1;
@@ -554,10 +613,11 @@ TEST_F(PseudoTerminalTest, ReadUntilWithReadFail) {
554613
// Skip these as they are handled differently in readUntil
555614
continue;
556615
}
557-
serial_port.setSystemCallFunctions(
616+
serial_port.setPollSystemFunction(
558617
[](struct pollfd*, nfds_t, int) -> int {
559618
return 1;
560-
},
619+
});
620+
serial_port.setReadSystemFunction(
561621
[error_num](int, void*, size_t) -> ssize_t {
562622
errno = error_num;
563623
return -1;
@@ -582,13 +642,10 @@ TEST_F(PseudoTerminalTest, ReadUntilWithPollFail) {
582642
auto read_buffer = std::make_shared<std::string>();
583643

584644
for (const auto& [error_num, error_msg] : errors_poll_) {
585-
serial_port.setSystemCallFunctions(
645+
serial_port.setPollSystemFunction(
586646
[error_num](struct pollfd*, nfds_t, int) -> int {
587647
errno = error_num;
588648
return -1;
589-
},
590-
[](int, void*, size_t) -> ssize_t {
591-
return 1;
592649
});
593650

594651
auto expected_what = "Error in poll(): " + error_msg;

0 commit comments

Comments
 (0)