File size: 4,067 Bytes
60caae2
 
05c50a2
 
 
ec30e3a
 
 
05c50a2
60caae2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
05c50a2
 
 
 
 
60caae2
 
 
05c50a2
60caae2
 
05c50a2
 
 
 
 
 
 
60caae2
05c50a2
 
 
60caae2
 
05c50a2
 
 
 
 
 
 
 
 
 
 
 
60caae2
 
 
 
05c50a2
60caae2
 
 
 
05c50a2
60caae2
05c50a2
 
 
 
 
60caae2
 
05c50a2
 
 
60caae2
 
05c50a2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
"""Tests for studycraft.validator."""

from studycraft.validator import (
    MIN_EXAMPLES,
    MIN_QUIZ_QUESTIONS,
    REQUIRED_SECTIONS,
    validate_chapter,
    validate_guide,
)

_GOOD_CHAPTER = """\
# πŸ“– Practice Guide β€” Python
## Chapter 1: Variables

## 1. Learning Objectives
- Understand variables

## 2. Core Concepts & Theory
Concepts here.

## 3. Worked Examples

### Example 1 β€” Assigning a variable
**Problem:** Assign x = 5
**Solution:** x = 5

### Example 2 β€” String variable
**Problem:** Create a name
**Solution:** name = "Alice"

### Example 3 β€” Multiple assignment
**Problem:** Assign a, b, c
**Solution:** a, b, c = 1, 2, 3

## 4. Practice Exercises
Do these exercises.

## 5. Mini Project
Build a calculator.

## 6. Chapter Quiz
1. What is a variable?
2. How do you assign a value?
3. What types exist?
4. What is an integer?
5. Given x=5, what is x+1?
6. How do you swap variables?
7. Why use descriptive names?
8. What is the difference between int and float?
9. How would you design a config system?
10. Which naming convention is better and why?

## 7. Reflection
Think about what you learned.

## 8. Tips & Common Mistakes
Avoid common errors.
"""

_BAD_CHAPTER = """\
# Chapter 1: Variables

## 1. Learning Objectives
- [Actionable objective 1]

## 2. Core Concepts & Theory
[Term 1] is important.

## 3. Worked Examples

### Example 1 β€” Basic
**Problem:** [State the problem]
"""


def test_good_chapter_passes():
    result = validate_chapter(_GOOD_CHAPTER, label="Ch 1")
    assert result.passed is True
    assert result.missing_sections == []
    assert result.example_count == MIN_EXAMPLES
    assert result.quiz_count == MIN_QUIZ_QUESTIONS
    assert result.placeholder_count == 0
    assert result.summary() == "All checks passed"


def test_bad_chapter_missing_sections():
    result = validate_chapter(_BAD_CHAPTER, label="Ch 1")
    assert not result.passed
    # Must be missing these specific sections
    for section in ("Practice Exercises", "Mini Project", "Chapter Quiz", "Reflection", "Tips & Common Mistakes"):
        assert section in result.missing_sections, f"Should report {section} as missing"


def test_bad_chapter_has_placeholders():
    result = validate_chapter(_BAD_CHAPTER, label="Ch 1")
    assert result.placeholder_count > 0
    # Verify actual placeholder text is captured
    assert any("[Actionable objective 1]" == p for p in result.placeholders)
    assert any("[Term 1]" == p for p in result.placeholders)


def test_bad_chapter_low_examples():
    result = validate_chapter(_BAD_CHAPTER)
    assert result.example_count == 1
    assert result.example_count < MIN_EXAMPLES


def test_bad_chapter_zero_quiz():
    result = validate_chapter(_BAD_CHAPTER)
    assert result.quiz_count == 0


def test_example_count_exact():
    result = validate_chapter(_GOOD_CHAPTER)
    assert result.example_count == 3


def test_quiz_count_exact():
    result = validate_chapter(_GOOD_CHAPTER)
    assert result.quiz_count == 10


def test_summary_lists_all_failures():
    result = validate_chapter(_BAD_CHAPTER)
    summary = result.summary()
    assert "Missing sections" in summary
    assert "Examples:" in summary
    assert "Quiz questions:" in summary
    assert "Unfilled placeholders:" in summary


def test_validate_guide_splits_and_validates():
    ch2 = _GOOD_CHAPTER.replace("Chapter 1", "Chapter 2").replace("Practice Guide β€” Python", "Practice Guide β€” Java")
    two_chapters = _GOOD_CHAPTER + "\n\n---\n\n" + ch2
    results = validate_guide(two_chapters)
    assert len(results) == 2
    assert all(r.passed for r in results)
    assert results[0].chapter_label != results[1].chapter_label


def test_validate_guide_empty():
    results = validate_guide("")
    assert results == []


def test_label_preserved():
    result = validate_chapter(_GOOD_CHAPTER, label="My Chapter")
    assert result.chapter_label == "My Chapter"


def test_required_sections_count():
    """Ensure REQUIRED_SECTIONS matches the 8 sections in the template."""
    assert len(REQUIRED_SECTIONS) == 8