|
|
#include "unity/unity.h" |
|
|
#include <libxml/HTMLtree.h> |
|
|
|
|
|
#include <libxml/tree.h> |
|
|
#include <stdio.h> |
|
|
#include <stdlib.h> |
|
|
#include <string.h> |
|
|
|
|
|
|
|
|
void setUp(void) { |
|
|
|
|
|
} |
|
|
|
|
|
void tearDown(void) { |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int create_temp_file(char *outPath, size_t outPathSize, FILE **outF) { |
|
|
if (outPath == NULL || outF == NULL || outPathSize == 0) |
|
|
return 0; |
|
|
|
|
|
|
|
|
char tmpbuf[L_tmpnam]; |
|
|
#if defined(_MSC_VER) |
|
|
if (tmpnam_s(tmpbuf, L_tmpnam) != 0) |
|
|
return 0; |
|
|
#else |
|
|
if (tmpnam(tmpbuf) == NULL) |
|
|
return 0; |
|
|
#endif |
|
|
|
|
|
strncpy(outPath, tmpbuf, outPathSize - 1); |
|
|
outPath[outPathSize - 1] = '\0'; |
|
|
|
|
|
FILE *f = fopen(outPath, "wb"); |
|
|
if (f == NULL) |
|
|
return 0; |
|
|
|
|
|
*outF = f; |
|
|
return 1; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static char *read_file_to_string(const char *path, long *length) { |
|
|
if (path == NULL) |
|
|
return NULL; |
|
|
|
|
|
FILE *f = fopen(path, "rb"); |
|
|
if (f == NULL) |
|
|
return NULL; |
|
|
|
|
|
if (fseek(f, 0, SEEK_END) != 0) { |
|
|
fclose(f); |
|
|
return NULL; |
|
|
} |
|
|
long size = ftell(f); |
|
|
if (size < 0) { |
|
|
fclose(f); |
|
|
return NULL; |
|
|
} |
|
|
rewind(f); |
|
|
|
|
|
char *buf = (char *)malloc((size_t)size + 1); |
|
|
if (buf == NULL) { |
|
|
fclose(f); |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
size_t nread = fread(buf, 1, (size_t)size, f); |
|
|
fclose(f); |
|
|
buf[nread] = '\0'; |
|
|
if (length) |
|
|
*length = (long)nread; |
|
|
return buf; |
|
|
} |
|
|
|
|
|
|
|
|
static xmlDocPtr build_simple_html_doc(void) { |
|
|
xmlDocPtr doc = htmlNewDocNoDtD(NULL, NULL); |
|
|
if (doc == NULL) |
|
|
return NULL; |
|
|
|
|
|
xmlNodePtr root = htmlNewDocNode(doc, NULL, BAD_CAST "html", NULL); |
|
|
if (root == NULL) { |
|
|
xmlFreeDoc(doc); |
|
|
return NULL; |
|
|
} |
|
|
xmlDocSetRootElement(doc, root); |
|
|
|
|
|
xmlNodePtr body = htmlNewDocNode(doc, NULL, BAD_CAST "body", NULL); |
|
|
if (body == NULL) { |
|
|
xmlFreeDoc(doc); |
|
|
return NULL; |
|
|
} |
|
|
xmlAddChild(root, body); |
|
|
|
|
|
xmlNodePtr p = htmlNewDocNode(doc, NULL, BAD_CAST "p", NULL); |
|
|
if (p == NULL) { |
|
|
xmlFreeDoc(doc); |
|
|
return NULL; |
|
|
} |
|
|
xmlAddChild(body, p); |
|
|
|
|
|
xmlNodePtr text = xmlNewText(BAD_CAST "Hello"); |
|
|
if (text == NULL) { |
|
|
xmlFreeDoc(doc); |
|
|
return NULL; |
|
|
} |
|
|
xmlAddChild(p, text); |
|
|
|
|
|
return doc; |
|
|
} |
|
|
|
|
|
|
|
|
static void test_htmlDocDump_null_doc_returns_minus1(void) { |
|
|
char path[256]; |
|
|
FILE *f = NULL; |
|
|
TEST_ASSERT_TRUE_MESSAGE(create_temp_file(path, sizeof(path), &f), "Failed to create temp file"); |
|
|
|
|
|
int ret = htmlDocDump(f, NULL); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(-1, ret, "htmlDocDump should return -1 for NULL doc"); |
|
|
|
|
|
|
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(0, fflush(f), "Flushing file failed"); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(0, fclose(f), "Closing file failed"); |
|
|
|
|
|
|
|
|
long size = 0; |
|
|
char *contents = read_file_to_string(path, &size); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(contents, "Failed to read temp file"); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(0, (int)size, "File should be empty when doc is NULL"); |
|
|
free(contents); |
|
|
remove(path); |
|
|
} |
|
|
|
|
|
|
|
|
static void test_htmlDocDump_null_file_returns_minus1(void) { |
|
|
xmlDocPtr doc = build_simple_html_doc(); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(doc, "Failed to build HTML doc"); |
|
|
|
|
|
int ret = htmlDocDump(NULL, doc); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(-1, ret, "htmlDocDump should return -1 for NULL file"); |
|
|
|
|
|
xmlFreeDoc(doc); |
|
|
} |
|
|
|
|
|
|
|
|
static void test_htmlDocDump_invalid_encoding_returns_minus1_and_no_write(void) { |
|
|
xmlDocPtr doc = build_simple_html_doc(); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(doc, "Failed to build HTML doc"); |
|
|
|
|
|
|
|
|
doc->encoding = xmlStrdup(BAD_CAST "x-unknown-encoding-xyz-1234"); |
|
|
|
|
|
char path[256]; |
|
|
FILE *f = NULL; |
|
|
TEST_ASSERT_TRUE_MESSAGE(create_temp_file(path, sizeof(path), &f), "Failed to create temp file"); |
|
|
|
|
|
int ret = htmlDocDump(f, doc); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(-1, ret, "htmlDocDump should return -1 for unsupported encoding"); |
|
|
|
|
|
|
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(0, fflush(f), "Flushing file failed"); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(0, fclose(f), "Closing file failed"); |
|
|
|
|
|
long size = -1; |
|
|
char *contents = read_file_to_string(path, &size); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(contents, "Failed to read temp file"); |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(0, (int)size, "File should be empty on encoder failure"); |
|
|
free(contents); |
|
|
remove(path); |
|
|
|
|
|
xmlFreeDoc(doc); |
|
|
} |
|
|
|
|
|
|
|
|
static void test_htmlDocDump_writes_content_with_default_encoding(void) { |
|
|
xmlDocPtr doc = build_simple_html_doc(); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(doc, "Failed to build HTML doc"); |
|
|
|
|
|
|
|
|
doc->encoding = NULL; |
|
|
|
|
|
char path[256]; |
|
|
FILE *f = NULL; |
|
|
TEST_ASSERT_TRUE_MESSAGE(create_temp_file(path, sizeof(path), &f), "Failed to create temp file"); |
|
|
|
|
|
int ret = htmlDocDump(f, doc); |
|
|
TEST_ASSERT_MESSAGE(ret >= 0, "htmlDocDump should succeed (ret >= 0) with default encoding"); |
|
|
|
|
|
|
|
|
|
|
|
long size = -1; |
|
|
char *contents = read_file_to_string(path, &size); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(contents, "Failed to read dumped file"); |
|
|
TEST_ASSERT_MESSAGE(size > 0, "Dumped file should contain data"); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(strstr(contents, "Hello"), "Dumped HTML should contain text 'Hello'"); |
|
|
|
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(strstr(contents, "<html"), "Dumped HTML should contain <html> element"); |
|
|
|
|
|
free(contents); |
|
|
remove(path); |
|
|
xmlFreeDoc(doc); |
|
|
} |
|
|
|
|
|
|
|
|
static void test_htmlDocDump_writes_content_with_utf8_encoding(void) { |
|
|
xmlDocPtr doc = build_simple_html_doc(); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(doc, "Failed to build HTML doc"); |
|
|
|
|
|
|
|
|
doc->encoding = xmlStrdup(BAD_CAST "UTF-8"); |
|
|
|
|
|
char path[256]; |
|
|
FILE *f = NULL; |
|
|
TEST_ASSERT_TRUE_MESSAGE(create_temp_file(path, sizeof(path), &f), "Failed to create temp file"); |
|
|
|
|
|
int ret = htmlDocDump(f, doc); |
|
|
TEST_ASSERT_MESSAGE(ret >= 0, "htmlDocDump should succeed (ret >= 0) with UTF-8 encoding"); |
|
|
|
|
|
long size = -1; |
|
|
char *contents = read_file_to_string(path, &size); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(contents, "Failed to read dumped file"); |
|
|
TEST_ASSERT_MESSAGE(size > 0, "Dumped file should contain data"); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(strstr(contents, "Hello"), "Dumped HTML should contain text 'Hello'"); |
|
|
|
|
|
free(contents); |
|
|
remove(path); |
|
|
xmlFreeDoc(doc); |
|
|
} |
|
|
|
|
|
|
|
|
int main(void) { |
|
|
UNITY_BEGIN(); |
|
|
RUN_TEST(test_htmlDocDump_null_doc_returns_minus1); |
|
|
RUN_TEST(test_htmlDocDump_null_file_returns_minus1); |
|
|
RUN_TEST(test_htmlDocDump_invalid_encoding_returns_minus1_and_no_write); |
|
|
RUN_TEST(test_htmlDocDump_writes_content_with_default_encoding); |
|
|
RUN_TEST(test_htmlDocDump_writes_content_with_utf8_encoding); |
|
|
return UNITY_END(); |
|
|
} |