Coverage for tests/test_styles.py: 100%

65 statements  

« prev     ^ index     » next       coverage.py v7.17.0, created at 2026-10-31 22:06 +0000

1"""Tests for styles and exporters.""" 

2 

3from __future__ import annotations 

4 

5import dataclasses 

6import pathlib 

7 

8import pytest 

9 

10import coursebook 

11from coursebook import outline 

12 

13 

14@pytest.mark.parametrize(('name', 'expected'), [ 

15 ('law review', coursebook.LawReview), 

16 ('Law_Review', coursebook.LawReview), 

17 ('book', coursebook.Book), 

18 ('Coursebook', coursebook.Coursebook), 

19 ('textbook', coursebook.Coursebook)]) 

20def test_get_style(name: str, expected: type[coursebook.Style]) -> None: 

21 """Tests choosing styles by name and alias.""" 

22 assert type(coursebook.get_style(name)) is expected 

23 

24 

25def test_unknown_style() -> None: 

26 """Tests that an unknown style lists the known styles.""" 

27 with pytest.raises(ValueError, match = 'law_review'): 

28 coursebook.get_style('memo') 

29 with pytest.raises(ValueError, match = 'unknown style'): 

30 coursebook.get_style('style') 

31 

32 

33def test_style_overrides() -> None: 

34 """Tests that overrides replace defaults and `None` is ignored.""" 

35 style = coursebook.get_style( 

36 'law review', number_headings = False, table_of_contents = None) 

37 assert style.number_headings is False 

38 assert style.table_of_contents is False 

39 

40 

41def test_format_heading() -> None: 

42 """Tests headings with and without labels.""" 

43 entry = outline.OutlineEntry(label = 'IV', title = 'Conclusion') 

44 assert coursebook.LawReview().format_heading(entry) == 'IV. Conclusion' 

45 assert coursebook.Book().format_heading(entry) == 'Conclusion' 

46 preface = outline.OutlineEntry(label = '', title = 'Preface') 

47 assert coursebook.LawReview().format_heading(preface) == 'Preface' 

48 

49 

50def test_custom_style_is_registered() -> None: 

51 """Tests that a subclass of `Style` can be chosen by name.""" 

52 

53 @dataclasses.dataclass 

54 class SeminarPaper(coursebook.Coursebook): 

55 number_headings: bool = True 

56 

57 style = coursebook.get_style('Seminar Paper') 

58 assert isinstance(style, SeminarPaper) 

59 assert style.sections == ('text', 'slides', 'notes') 

60 

61 

62@pytest.mark.parametrize(('name', 'expected'), [ 

63 ('word', coursebook.WordExporter), 

64 ('DOCX', coursebook.WordExporter), 

65 ('PowerPoint', coursebook.PowerPointExporter), 

66 ('pdf', coursebook.PdfExporter), 

67 ('HTML', coursebook.HtmlExporter), 

68 ('word_exporter', coursebook.WordExporter)]) 

69def test_get_exporter(name: str, expected: type[coursebook.Exporter]) -> None: 

70 """Tests choosing exporters by name and alias.""" 

71 assert type(coursebook.get_exporter(name)) is expected 

72 

73 

74def test_unknown_exporter() -> None: 

75 """Tests that an unknown format lists the known formats.""" 

76 with pytest.raises(ValueError, match = 'powerpoint'): 

77 coursebook.get_exporter('epub') 

78 

79 

80def test_exporter_arguments(tmp_path: pathlib.Path) -> None: 

81 """Tests the pandoc arguments for each exporter.""" 

82 options = coursebook.ExportOptions( 

83 template = tmp_path / 'reference.docx', 

84 resource_paths = [tmp_path], 

85 bibliography = [tmp_path / 'refs.bib'], 

86 csl = tmp_path / 'style.csl', 

87 table_of_contents = True) 

88 word = coursebook.WordExporter().get_arguments(options) 

89 assert f'--reference-doc={tmp_path / "reference.docx"}' in word 

90 assert '--citeproc' in word 

91 assert f'--csl={tmp_path / "style.csl"}' in word 

92 assert '--toc' in word 

93 slides = coursebook.PowerPointExporter().get_arguments(options) 

94 assert '--slide-level=2' in slides 

95 assert '--toc' not in slides 

96 

97 

98def test_formatting_metadata() -> None: 

99 """Tests the template variables for PDF and HTML files.""" 

100 options = coursebook.ExportOptions( 

101 metadata = {'title': 'T'}, 

102 formatting = coursebook.LawReview().formatting) 

103 pdf = coursebook.PdfExporter().get_metadata(options) 

104 assert pdf['mainfont'] == 'Times New Roman' 

105 assert pdf['fontsize'] == '12pt' 

106 assert pdf['margin'] == {'x': '1.0in', 'y': '1.0in'} 

107 assert pdf['page-numbering'] == '1' 

108 assert '#show heading.where(level: 1): upper' in pdf['header-includes'] 

109 assert pdf['header-includes'].endswith('```\n') 

110 html = coursebook.HtmlExporter().get_metadata(options) 

111 assert html['mainfont'] == 'Times New Roman, serif' 

112 assert 'text-transform: uppercase' in html['header-includes'] 

113 plain = coursebook.HtmlExporter().get_metadata( 

114 coursebook.ExportOptions(metadata = {'title': 'T'})) 

115 assert plain == {'title': 'T'} 

116 

117 

118def test_exporter_sections() -> None: 

119 """Tests which sections each exporter can export.""" 

120 assert coursebook.PowerPointExporter.sections == ('slides',) 

121 for exporter in ( 

122 coursebook.WordExporter, coursebook.PdfExporter, 

123 coursebook.HtmlExporter): 

124 assert exporter.sections == ('text', 'notes')