最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

How to write C++ unit tests for HTTP? (Host OS new line vs rn issue.) - Stack Overflow

programmeradmin1浏览0评论

I'm writing some C++ unit tests with Catch2 for a library which includes a dependency on a HTTP parser. (In this particular case, llhttp.)

As part of my unit tests, I have a directory containing test data. For example, one of the most simple tests contains the following file which specifies an input to the test.

POST /api/example HTTP/1.1
Host: example
Content-Type: application/json

{
  "body": "BODY"
}

This is a set of HTTP headers, and a JSON Content body, which is intended to be used as input to test the parsing logic.

However, the line endings are variable depending on the OS.

I saved the file from a Linux OS. Therefore the line endings are \n. (New line, no carriage return.)

This is incompatiable with HTTP, as the standard requires \r\n. (Carriage return, followed by new line.)

I'm looking for some advice on how best to proceed here.

While I could write a function to convert the data read from file into a std::string containing the correct line ending characters, this has some isses.

  • Firstly I have to write the function, and I can't immediatly think of an elegant implementation. This feels a bit like a code smell, maybe this isn't the best approach.
  • Possibly more importantly, this function is unlikely to be cross platform compatiable. If someone re-saves the same file from a Windows system, the logic will be broken. (Unless I were to implement something more complex which first scans the file to detect the line ending format.)

Something about this doesn't feel quite right. Perhaps someone has some advice on the best way to proceed?


To illustrate why I don't think I have a good solution to this problem, here's the current implementation I am using.

std::ifstream ifile("http_data.txt", std::ios::binary);

std::string line; // input
std::ostringstream oss; // output
while(std::getline(ifile, line)) // line ending agonstic
{
    oss.write(line.c_str(), line.size());
    oss.write("\r\n", 2); // line ending specific
}

In short - I don't think my approach is particuarly good. Is there a smarter way to do this?

I'm writing some C++ unit tests with Catch2 for a library which includes a dependency on a HTTP parser. (In this particular case, llhttp.)

As part of my unit tests, I have a directory containing test data. For example, one of the most simple tests contains the following file which specifies an input to the test.

POST /api/example HTTP/1.1
Host: example
Content-Type: application/json

{
  "body": "BODY"
}

This is a set of HTTP headers, and a JSON Content body, which is intended to be used as input to test the parsing logic.

However, the line endings are variable depending on the OS.

I saved the file from a Linux OS. Therefore the line endings are \n. (New line, no carriage return.)

This is incompatiable with HTTP, as the standard requires \r\n. (Carriage return, followed by new line.)

I'm looking for some advice on how best to proceed here.

While I could write a function to convert the data read from file into a std::string containing the correct line ending characters, this has some isses.

  • Firstly I have to write the function, and I can't immediatly think of an elegant implementation. This feels a bit like a code smell, maybe this isn't the best approach.
  • Possibly more importantly, this function is unlikely to be cross platform compatiable. If someone re-saves the same file from a Windows system, the logic will be broken. (Unless I were to implement something more complex which first scans the file to detect the line ending format.)

Something about this doesn't feel quite right. Perhaps someone has some advice on the best way to proceed?


To illustrate why I don't think I have a good solution to this problem, here's the current implementation I am using.

std::ifstream ifile("http_data.txt", std::ios::binary);

std::string line; // input
std::ostringstream oss; // output
while(std::getline(ifile, line)) // line ending agonstic
{
    oss.write(line.c_str(), line.size());
    oss.write("\r\n", 2); // line ending specific
}

In short - I don't think my approach is particuarly good. Is there a smarter way to do this?

Share asked Mar 3 at 22:23 user2138149user2138149 17.7k30 gold badges150 silver badges296 bronze badges 3
  • 3 On Linux, I'd use Vim and do a :set ff=dos then save the file. That wil use \r\n line endings. – Eljay Commented Mar 3 at 22:38
  • 3 You also have shell commands dos2unix and unix2dos. – edrezen Commented Mar 3 at 22:41
  • excellent tips, thank you both – user2138149 Commented Mar 4 at 21:02
Add a comment  | 

1 Answer 1

Reset to default 0

For such small input files, I would not care about input line ending and performance.

std::ifstream ifile("http_data.txt", std::ios::binary);
std::string data(std::istreambuf_iterator<char>{ifile}, {});
boost::replace_all(data, "\r\n", "\n");
boost::replace_all(data, "\n", "\r\n");
// data = std::regex_replace(data, std::regex("\r\n"), "\n"); // not tested
// data = std::regex_replace(data, std::regex("\n"), "\r\n"); // not tested
// Regex replace can be single: ([^\r])\n with \1\r\n, not tested
发布评论

评论列表(0)

  1. 暂无评论