From d7d559f4f7c985ed501896900da404fa4ab1360d Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Mon, 9 Dec 2024 15:20:50 +0100 Subject: [PATCH] test: Add tests for different document types Add tests for unstructured reading for different document types Test COG-685 --- .../documents/UnstructuredDocument_test.py | 62 +++++++++++++++++- cognee/tests/test_data/example.csv | 3 + cognee/tests/test_data/example.docx | Bin 0 -> 5950 bytes cognee/tests/test_data/example.xlsx | Bin 0 -> 9210 bytes 4 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 cognee/tests/test_data/example.csv create mode 100644 cognee/tests/test_data/example.docx create mode 100644 cognee/tests/test_data/example.xlsx diff --git a/cognee/tests/integration/documents/UnstructuredDocument_test.py b/cognee/tests/integration/documents/UnstructuredDocument_test.py index 56c3c827f..7f6e20ba0 100644 --- a/cognee/tests/integration/documents/UnstructuredDocument_test.py +++ b/cognee/tests/integration/documents/UnstructuredDocument_test.py @@ -4,19 +4,77 @@ import uuid from cognee.modules.data.processing.document_types.UnstructuredDocument import UnstructuredDocument def test_UnstructuredDocument(): - docx_file_path = os.path.join( + # Define file paths of test data + pptx_file_path = os.path.join( os.sep, *(os.path.dirname(__file__).split(os.sep)[:-2]), "test_data", "example.pptx", ) + docx_file_path = os.path.join( + os.sep, + *(os.path.dirname(__file__).split(os.sep)[:-2]), + "test_data", + "example.docx", + ) + + csv_file_path = os.path.join( + os.sep, + *(os.path.dirname(__file__).split(os.sep)[:-2]), + "test_data", + "example.csv", + ) + + xlsx_file_path = os.path.join( + os.sep, + *(os.path.dirname(__file__).split(os.sep)[:-2]), + "test_data", + "example.xlsx", + ) + + # Define test documents pptx_document = UnstructuredDocument( - id=uuid.uuid4(), name="example.pptx", raw_data_location=docx_file_path, metadata_id=uuid.uuid4(), + id=uuid.uuid4(), name="example.pptx", raw_data_location=pptx_file_path, metadata_id=uuid.uuid4(), mime_type="application/vnd.openxmlformats-officedocument.presentationml.presentation" ) + docx_document = UnstructuredDocument( + id=uuid.uuid4(), name="example.docx", raw_data_location=docx_file_path, metadata_id=uuid.uuid4(), + mime_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document" + ) + + csv_document = UnstructuredDocument( + id=uuid.uuid4(), name="example.csv", raw_data_location=csv_file_path, metadata_id=uuid.uuid4(), + mime_type="text/csv" + ) + + xlsx_document = UnstructuredDocument( + id=uuid.uuid4(), name="example.xslx", raw_data_location=xlsx_file_path, metadata_id=uuid.uuid4(), + mime_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ) + + # Test PPTX for paragraph_data in pptx_document.read(chunk_size=1024): assert 19 == paragraph_data.word_count, f' 19 != {paragraph_data.word_count = }' assert 104 == len(paragraph_data.text), f' 104 != {len(paragraph_data.text) = }' assert 'sentence_cut' == paragraph_data.cut_type, f' sentence_cut != {paragraph_data.cut_type = }' + + # Test DOCX + for paragraph_data in docx_document.read(chunk_size=1024): + assert 16 == paragraph_data.word_count, f' 16 != {paragraph_data.word_count = }' + assert 145 == len(paragraph_data.text), f' 145 != {len(paragraph_data.text) = }' + assert 'sentence_end' == paragraph_data.cut_type, f' sentence_end != {paragraph_data.cut_type = }' + + # TEST CSV + for paragraph_data in csv_document.read(chunk_size=1024): + assert 15 == paragraph_data.word_count, f' 15 != {paragraph_data.word_count = }' + assert 'A A A A A A A A A,A A A A A A,A A' == paragraph_data.text, \ + f'Read text doesn\'t match expected text: {paragraph_data.text}' + assert 'sentence_cut' == paragraph_data.cut_type, f' sentence_cut != {paragraph_data.cut_type = }' + + # Test XLSX + for paragraph_data in xlsx_document.read(chunk_size=1024): + assert 36 == paragraph_data.word_count, f' 36 != {paragraph_data.word_count = }' + assert 171 == len(paragraph_data.text), f' 171 != {len(paragraph_data.text) = }' + assert 'sentence_cut' == paragraph_data.cut_type, f' sentence_cut != {paragraph_data.cut_type = }' diff --git a/cognee/tests/test_data/example.csv b/cognee/tests/test_data/example.csv new file mode 100644 index 000000000..004bbf122 --- /dev/null +++ b/cognee/tests/test_data/example.csv @@ -0,0 +1,3 @@ +A,A,A,A,A +A,A,A,"A,A",A +A,A,A,"A,A",A diff --git a/cognee/tests/test_data/example.docx b/cognee/tests/test_data/example.docx new file mode 100644 index 0000000000000000000000000000000000000000..81ff7f2d4f7d9ef9950390bc3ec8e00bd01befe9 GIT binary patch literal 5950 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