File size: 2,910 Bytes
52739ad
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
"""Tests for the upload & parse flow (Session 2).

Covers the happy path (raw text) and, per the acceptance criteria, the
parse-failure paths: non-PDF files, broken PDFs, password-protected PDFs,
empty input, and oversize input.
"""

import io

import pytest
from fastapi.testclient import TestClient
from pypdf import PdfWriter

from app.main import MAX_UPLOAD_BYTES, app

client = TestClient(app)


def _encrypted_pdf_bytes(password: str = "secret") -> bytes:
    """Build a small, password-protected PDF in memory."""
    writer = PdfWriter()
    writer.add_blank_page(width=200, height=200)
    # RC4 avoids a hard dependency on the `cryptography` package in CI.
    writer.encrypt(user_password=password, algorithm="RC4-128")
    buffer = io.BytesIO()
    writer.write(buffer)
    return buffer.getvalue()


def test_create_document_from_text():
    body = "DocuAsk turns a document into a searchable index. " * 40
    response = client.post("/documents", data={"text": body})
    assert response.status_code == 201
    payload = response.json()
    assert payload["status"] == "ready"
    assert payload["num_chunks"] >= 1
    assert payload["num_chars"] == len(body)
    assert payload["filename"] is None

    # The returned id resolves to a stored document.
    fetched = client.get(f"/documents/{payload['document_id']}")
    assert fetched.status_code == 200
    assert fetched.json()["document_id"] == payload["document_id"]


def test_empty_text_is_rejected():
    response = client.post("/documents", data={"text": "   "})
    assert response.status_code == 400
    assert "detail" in response.json()


def test_missing_input_is_rejected():
    response = client.post("/documents")
    assert response.status_code == 400


def test_non_pdf_file_is_rejected():
    response = client.post(
        "/documents",
        files={"file": ("notes.png", b"\x89PNG\r\n", "image/png")},
    )
    assert response.status_code == 415
    assert "PDF" in response.json()["detail"]


def test_broken_pdf_is_rejected():
    # A .pdf name but garbage bytes — pypdf cannot read it.
    response = client.post(
        "/documents",
        files={"file": ("broken.pdf", b"this is definitely not a pdf", "application/pdf")},
    )
    assert response.status_code == 400
    assert "PDF" in response.json()["detail"]


def test_encrypted_pdf_is_rejected():
    response = client.post(
        "/documents",
        files={"file": ("secret.pdf", _encrypted_pdf_bytes(), "application/pdf")},
    )
    assert response.status_code == 400
    assert "password" in response.json()["detail"].lower()


def test_oversize_text_is_rejected():
    huge = "a" * (MAX_UPLOAD_BYTES + 1)
    response = client.post("/documents", data={"text": huge})
    assert response.status_code == 413


def test_unknown_document_returns_404():
    response = client.get("/documents/does-not-exist")
    assert response.status_code == 404