File size: 2,754 Bytes
efd296e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Question generation: the pure parts — prompt shape, reply parsing, resume."""

import json

from scripts.generate_glosses import existing_urls_of
from scripts.generate_questions import (
    QUESTION_MAX_CHARS,
    QUESTIONS_PER_PAGE,
    batch_prompt,
    parse_questions,
)


def _page(url, title="T", excerpt="Applies a linear transformation."):
    return {"url": url, "title": title, "excerpt": excerpt}


def test_batch_prompt_numbers_pages_and_uses_symbol():
    prompt = batch_prompt(
        [
            _page("https://docs.pytorch.org/docs/stable/generated/torch.nn.Linear.html"),
            _page("https://docs.pytorch.org/docs/stable/amp.html", title="AMP page"),
        ]
    )
    assert "### 0" in prompt and "### 1" in prompt
    assert "torch.nn.Linear" in prompt  # symbol derived from the url
    assert "AMP page" in prompt  # no symbol in the url → the title stands in


def test_parse_questions_plain_json():
    raw = json.dumps(
        [
            {"i": 0, "questions": ["How do I add a fully-connected layer?", "  spaced  "]},
            {"i": 1, "questions": ["What splits a dataset randomly?"]},
        ]
    )
    out = parse_questions(raw, 2)
    assert out[0][0] == "How do I add a fully-connected layer?"
    assert out[0][1] == "spaced"
    assert out[1] == ["What splits a dataset randomly?"]


def test_parse_questions_survives_fences_and_prose():
    raw = 'Sure!\n```json\n[{"i": 0, "questions": ["q1"]}]\n```\nDone.'
    assert parse_questions(raw, 1) == {0: ["q1"]}


def test_parse_questions_drops_malformed_items():
    raw = json.dumps(
        [
            {"i": 5, "questions": ["out of range"]},  # index beyond the batch
            {"i": 0, "questions": []},  # empty list → dropped
            {"i": 1, "questions": ["ok", 7, ""]},  # non-strings/blanks filtered
            "not a dict",
        ]
    )
    assert parse_questions(raw, 2) == {1: ["ok"]}


def test_parse_questions_caps_count_and_length():
    many = [f"question {i}?" for i in range(QUESTIONS_PER_PAGE + 4)]
    long = "x" * (QUESTION_MAX_CHARS + 50)
    out = parse_questions(json.dumps([{"i": 0, "questions": many + [long]}]), 1)
    assert len(out[0]) == QUESTIONS_PER_PAGE
    assert all(len(q) <= QUESTION_MAX_CHARS for q in out[0])


def test_parse_questions_non_json_is_empty():
    assert parse_questions("the pages look great", 1) == {}


def test_existing_urls_of_resumes_from_the_output_file(tmp_path):
    path = tmp_path / "questions.jsonl"
    assert existing_urls_of(path) == set()  # no file yet → nothing covered
    path.write_text(
        '{"url": "https://a", "questions": ["q"]}\n\n{"url": "https://b", "questions": ["q"]}\n'
    )
    assert existing_urls_of(path) == {"https://a", "https://b"}