import unittest from textbook.extract_exercises import extract_exercises, numbered_items FIXTURE = """\ 1.6. Divisibility in the Integers body text Proof. Exercise 1.6.15. n Exercises 1.6 1.6.1. Complete the following sketch. (a) part a text 1.6.2. Prove Proposition 1.6.9. 1.6.3. Suppose that a natural number p > 1 has some property. This is the converse of Proposition 1.6.19. 1.7. Modular Arithmetic next section text """ class ExtractExercisesTests(unittest.TestCase): def test_extract_exercises_slices_between_headings(self): block = extract_exercises(FIXTURE, 'Exercises 1.6', '1.7. Modular Arithmetic') self.assertIn('1.6.1. Complete', block) self.assertNotIn('next section text', block) def test_extract_exercises_missing_heading_raises(self): with self.assertRaises(ValueError): extract_exercises(FIXTURE, 'Exercises 1.6', 'Exercises 9.9') def test_numbered_items_orders_and_dedupes(self): block = extract_exercises(FIXTURE, 'Exercises 1.6', '1.7. Modular Arithmetic') items, _dropped = numbered_items(block, '1.6.') self.assertEqual([i['number'] for i in items], ['1.6.1', '1.6.2', '1.6.3']) def test_numbered_items_drops_wrapped_cross_reference(self): # '1.6.19.' alone on its own line, right after a big jump from 1.6.3, with no # text on the same line, is a wrapped cross-reference ("...Proposition\n1.6.19."), # not a real exercise 16 numbers ahead of the last real one. block = extract_exercises(FIXTURE, 'Exercises 1.6', '1.7. Modular Arithmetic') items, dropped = numbered_items(block, '1.6.', max_gap=3) self.assertNotIn('1.6.19', [i['number'] for i in items]) self.assertEqual([d['number'] for d in dropped], ['1.6.19']) if __name__ == '__main__': unittest.main()