#include #include #include #include "../StreamReader.h" #include "../LineParser.h" #include "../IMFHeader.h" #include "../IMFBoundary.h" using namespace coreutils; static int checks = 0; #define CHECK(cond) do { checks++; if(!(cond)) { std::cerr << "FAIL line " << __LINE__ << ": " #cond << std::endl; return 1; } } while(0) void feedStr(StreamReader &r, const char *s) { ZString z((char *)s, strlen(s)); r.feed(z); } // The whole point of StreamReader/Parser: a "line" (or header, or boundary) // can arrive split across any number of socket packets, and parsing must // resume cleanly from wherever it left off once more data shows up. int test_lineparser_split_across_feeds() { StreamReader reader; feedStr(reader, "partial li"); LineParser lp(reader); CHECK(lp.doParse() == Parser::Status::INCOMPLETE); feedStr(reader, "ne\r\n"); CHECK(lp.doParse() == Parser::Status::COMPLETE); ZString line = lp.getLine(); CHECK(line.getLength() == 12); CHECK(strncmp(line.getData(), "partial line", 12) == 0); return 0; } int test_imfheader_folding_and_split_feeds() { StreamReader reader; IMFHeader header(reader); feedStr(reader, "Subject: line one\r\n "); CHECK(header.doParse() == Parser::Status::INCOMPLETE); feedStr(reader, "line two\r\n\r\n"); CHECK(header.doParse() == Parser::Status::COMPLETE); auto &fields = header.getHeaders(); CHECK(fields.size() == 1); MString subj = fields[MString("Subject")]; CHECK(subj.getLength() == 17); CHECK(strncmp(subj.getData(), "line one line two", subj.getLength()) == 0); return 0; } int test_imfboundary_split_across_feeds() { ZString b((char *)"XYZ", 3); StreamReader reader; IMFBoundary bound(reader, b); feedStr(reader, "\r\n--X"); CHECK(bound.doParse() == Parser::Status::INCOMPLETE); feedStr(reader, "YZ--"); CHECK(bound.doParse() == Parser::Status::COMPLETE); CHECK(bound.isLast() == true); return 0; } int main() { int rc = 0; rc |= test_lineparser_split_across_feeds(); rc |= test_imfheader_folding_and_split_feeds(); rc |= test_imfboundary_split_across_feeds(); if (rc == 0) std::cout << "ALL " << checks << " CHECKS PASSED" << std::endl; else std::cout << "SOME CHECKS FAILED (see above)" << std::endl; return rc; }