import pytest from lesson_service import _parse_flashcards def test_mcq_multiline_prompt_code_fence_and_paragraph(): md_text = """### Perhatikan program berikut ```c int x = 2; printf("%d", x * 3); ``` Berapakah keluarannya? - [] 2 - [] 3 - [x] 6 - [] Error > `x * 3` menghasilkan `6`. """ quiz = _parse_flashcards(md_text) assert len(quiz) == 1 q = quiz[0] assert q['type'] == 'mcq' # Code fence dirender di question, bukan hilang assert '
6'
assert q['options'][2]['is_correct'] is True
def test_mcq_table_and_math_rendered_in_question():
md_text = """### Dari tabel berikut, berapa totalnya?
| A | B |
|---|---|
| 1 | 2 |
| 3 | 4 |
$$x^2 + y = 10$$
- [x] 10
- [] 9
- [] 11
"""
quiz = _parse_flashcards(md_text)
assert len(quiz) == 1
q = quiz[0]
assert ' Penjelasan: Operasi `5 + 5` dihitung dulu menjadi `10`.
"""
quiz = _parse_flashcards(md_text)
assert len(quiz) == 1
q = quiz[0]
assert q['explanation'] != ''
assert 'Penjelasan' in q['explanation']
assert 'Penjelasan' not in q['question']
for opt in q['options']:
assert 'Penjelasan' not in opt['text']
def test_flashcard_simple_compat():
md_text = """### Apa fungsi dari `return 0;` di dalam fungsi `main()`?
Menandakan bahwa program telah selesai berjalan dengan sukses.
"""
quiz = _parse_flashcards(md_text)
assert len(quiz) == 1
q = quiz[0]
assert q['type'] == 'flashcard'
assert 'return' in q['front']
assert 'Menandakan bahwa program' in q['back']
assert q['options'] is None or q['options'] == []
def test_flashcard_with_explanation_back_clean():
md_text = """### Bagaimana cara menulis komentar satu baris di bahasa C?
Cukup gunakan dua garis miring di awal baris.
> Penjelasan: Komentar diabaikan oleh compiler.
"""
quiz = _parse_flashcards(md_text)
assert len(quiz) == 1
q = quiz[0]
assert q['type'] == 'flashcard'
assert 'Penjelasan' in q['explanation']
assert 'Penjelasan' not in q['back']
assert 'dua garis miring' in q['back']
def test_stable_ids_questions_and_options():
md_text = """### Soal pertama?
- [x] A
- [] B
### Soal kedua?
- [] C
- [x] D
"""
quiz = _parse_flashcards(md_text)
assert [q['id'] for q in quiz] == ['q-0', 'q-1']
assert [o['id'] for o in quiz[0]['options']] == ['q-0-o-0', 'q-0-o-1']
assert [o['id'] for o in quiz[1]['options']] == ['q-1-o-0', 'q-1-o-1']
def test_mcq_zero_correct_raises_valueerror():
md_text = """### Soal tanpa jawaban benar?
- [] A
- [] B
- [] C
"""
with pytest.raises(ValueError):
_parse_flashcards(md_text)
def test_mcq_two_correct_raises_valueerror():
md_text = """### Soal dengan dua jawaban benar?
- [x] A
- [] B
- [x] C
"""
with pytest.raises(ValueError):
_parse_flashcards(md_text)
def test_options_inside_code_fence_ignored():
md_text = """### Mana yang benar?
```markdown
- [x] ini bukan opsi, ini contoh di dalam code fence
- [] juga bukan
```
- [x] Opsi asli 1
- [] Opsi asli 2
"""
quiz = _parse_flashcards(md_text)
assert len(quiz) == 1
q = quiz[0]
assert len(q['options']) == 2
# Isi code fence tetap ada di question
assert 'ini bukan opsi' in q['question']
assert 'Opsi asli 1' not in q['question']
def test_image_markdown_in_question_heading():
md_text = """### Pilih gambar yang melambangkan bahasa C:

- [x] Benar
- [] Salah
"""
quiz = _parse_flashcards(md_text)
assert len(quiz) == 1
q = quiz[0]
assert q['image'] == 'https://upload.wikimedia.org/wikipedia/commons/1/18/C_Programming_Language.svg'
def test_empty_and_blank_text_returns_empty_list():
assert _parse_flashcards("") == []
assert _parse_flashcards(" \n ") == []
def test_old_flat_format_still_parses_with_ids():
md_text = """### Bahasa C adalah bahasa tingkat rendah.
- [] Benar
- [x] Salah
"""
quiz = _parse_flashcards(md_text)
assert len(quiz) == 1
assert quiz[0]['id'] == 'q-0'
assert quiz[0]['type'] == 'mcq'
assert len(quiz[0]['options']) == 2
assert quiz[0]['options'][1]['is_correct'] is True