diff options
author | John Ankarström <john@ankarstrom.se> | 2022-08-20 20:16:07 +0200 |
---|---|---|
committer | John Ankarström <john@ankarstrom.se> | 2022-08-20 20:16:07 +0200 |
commit | 3fa33fc6b16e066838f4db3e182776a04c5c7d26 (patch) | |
tree | 109510c47b006c65f9d603c6f030826310981d46 | |
parent | 3add6b2f9e87258e06ecdf0120529a096e9ea8d3 (diff) | |
download | EpisodeBrowser-3fa33fc6b16e066838f4db3e182776a04c5c7d26.tar.gz |
Fix XML test.
-rw-r--r-- | c/test.cpp | 152 |
1 files changed, 89 insertions, 63 deletions
@@ -25,6 +25,56 @@ struct Test #define TEST(id) }; struct id : public Test { id() : Test(#id) #define FAIL(...) do { Sprintf(error, __VA_ARGS__); return; } while (0) +template <typename F> +struct Defer +{ + Defer(F dtor) : dtor(dtor) {} + ~Defer() { dtor(); } + F dtor; +}; + +#define DEFER(x) Defer APPLY(CAT, defer_, __COUNTER__) {[=](){x;}} + +struct InternetFile +{ + InternetFile(const wchar_t* url); + ~InternetFile(); + DWORD Read(void* buf, DWORD cb); + HINTERNET hi; + HINTERNET hiUrl; +}; + +InternetFile::InternetFile(const wchar_t* url) +{ + hi = InternetOpen(L"Episode Browser", + INTERNET_OPEN_TYPE_DIRECT, nullptr, nullptr, + /*INTERNET_FLAG_ASYNC*/0); + if (!hi) + throw Win32Error{}; + + hiUrl = InternetOpenUrl(hi, url, + nullptr, 0, INTERNET_FLAG_NO_UI, 0); + if (!hiUrl) { + InternetCloseHandle(hi); + throw Win32Error{}; + } +} + +InternetFile::~InternetFile() +{ + InternetCloseHandle(hiUrl); + InternetCloseHandle(hi); +} + +DWORD InternetFile::Read(void* buf, DWORD cb) +{ + DWORD cbRead; + if (InternetReadFile(hiUrl, buf, cb, &cbRead)) + return cbRead; + else + throw Win32Error{}; +} + TESTS { TEST(StrcpyWithSmallerDestination) @@ -226,55 +276,42 @@ TESTS g_cfg.cEp = i; } - TEST(Internet) + TEST(XML) { - HINTERNET hi, hiUrl; - static unsigned char buf[8'388'608] = {0}; - DWORD cbRead; - - /* Download HTML. */ - hi = InternetOpen(L"Episode Browser", - INTERNET_OPEN_TYPE_DIRECT, nullptr, nullptr, - /*INTERNET_FLAG_ASYNC*/0); - if (!hi) - goto a; - - hiUrl = InternetOpenUrl(hi, L"https://www.detectiveconanworld.com/wiki/Anime", - nullptr, 0, INTERNET_FLAG_NO_UI, 0); - if (!hiUrl) - goto b; - - cbRead = 1; - while (cbRead) - if (!InternetReadFile(hiUrl, &buf, sizeof(buf), &cbRead)) - goto c; - - //printf("%s\n", buf); - - InternetCloseHandle(hiUrl); - InternetCloseHandle(hi); - - /* Parse HTML. */ LIBXML_TEST_VERSION; - htmlDocPtr doc; - doc = htmlReadMemory(reinterpret_cast<const char*>(buf), sizeof(buf), - "https://www.detectiveconanworld.com/wiki/Anime", nullptr, - HTML_PARSE_RECOVER|HTML_PARSE_NOERROR|HTML_PARSE_NOWARNING); - if (!doc) - goto z; - xmlXPathContextPtr xpathCtx; - xmlXPathObjectPtr xpathObj; + InternetFile inf{L"https://www.detectiveconanworld.com/wiki/Anime"}; + char buf[1024]; + + htmlParserCtxtPtr ctxt = htmlCreatePushParserCtxt(nullptr, nullptr, + buf, sizeof(buf), "https://www.detectiveconanworld.com/wiki/Anime", + XML_CHAR_ENCODING_UTF8); + DEFER(xmlFreeParserCtxt(ctxt)); - xpathCtx = xmlXPathNewContext(doc); + htmlCtxtUseOptions(ctxt, HTML_PARSE_RECOVER|HTML_PARSE_NOERROR|HTML_PARSE_NOWARNING); + + while (DWORD cbRead = inf.Read(&buf, sizeof(buf))) { + if (!htmlParseChunk(ctxt, buf, cbRead, 0)) + FAIL(xmlGetLastError()->message); + } + htmlParseChunk(ctxt, buf, 0, 1); /* Terminate. */ + + htmlDocPtr doc = ctxt->myDoc; + if (!doc) + FAIL(xmlGetLastError()->message); + DEFER(xmlFreeDoc(doc)); /* Needed? */ + + xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc); if (!xpathCtx) - goto y; + FAIL(xmlGetLastError()->message); + DEFER(xmlXPathFreeContext(xpathCtx)); - xpathObj = xmlXPathEvalExpression( - reinterpret_cast<const xmlChar*>("//tr"), + xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression( + reinterpret_cast<const xmlChar*>("//tr/td[@style='background:#f2fde9;']"), xpathCtx); if (!xpathObj) - goto x; + FAIL(xmlGetLastError()->message); + DEFER(xmlXPathFreeObject(xpathObj)); xmlNodeSetPtr nodes; int cNodes; @@ -282,39 +319,28 @@ TESTS cNodes = nodes? nodes->nodeNr: 0; printf("%d nodes\n", cNodes); - for (int i = 0; i < cNodes; i++) { - xmlNodePtr node = nodes->nodeTab[i]; - printf("node \"%s\": type %d\n", node->name, node->type); - } - - xmlXPathFreeObject(xpathObj); - xmlXPathFreeContext(xpathCtx); - xmlFreeDoc(doc); - return; - - x: xmlXPathFreeContext(xpathCtx); - y: xmlFreeDoc(doc); - z: FAIL(xmlGetLastError()->message); - - c: InternetCloseHandle(hiUrl); - b: InternetCloseHandle(hi); - a: FAIL(Win32Error{}.what()); + // for (int i = 0; i < cNodes; i++) { + // xmlNodePtr node = nodes->nodeTab[i]; + // printf("node \"%s\": type %d\n", node->name, node->type); + // } } }; int RunTests() { const Test tests[] = { - StrcpyWithSmallerDestination{}, + //StrcpyWithSmallerDestination{}, //EpisodeDataFromWeb{}, - EpisodeDataFromProlog{}, - IO{}, + //EpisodeDataFromProlog{}, + //IO{}, //MigrateElvDataFromPrologToDisk{}, - SampleConfigurationToDisk{}, + //SampleConfigurationToDisk{}, //MigrateCfg{} //MigrateDlvDataFromPrologToDisk{}, //DownloadData{}, - Internet{}, + XML{}, + //ImportElvData{}, + //ImportDlvData{}, }; printf("Results (%llu tests):\n", sizeof(tests)/sizeof(*tests)); |