Coverage for test_doctests.py: 100%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

42 statements  

1# -*- coding: utf-8 -*- 

2#@+leo-ver=5-thin 

3#@+node:ekr.20210926044012.1: * @file ../unittests/test_doctests.py 

4#@@first 

5"""Run all doctests.""" 

6import doctest 

7import glob 

8import os 

9import unittest 

10from leo.core import leoGlobals as g 

11 

12unittest_dir = os.path.dirname(__file__) 

13leo_dir = os.path.abspath(os.path.join(unittest_dir, '..')) 

14 

15#@+others # Define a function containing a doctest. 

16#@+node:ekr.20210926053601.1: ** factorial (test_dectests.py) 

17def factorial(n): 

18 # Modified from https://docs.python.org/3/library/doctest.html 

19 # Must import factorial. See: stackoverflow.com/questions/65066002 

20 """Return the factorial of n, an exact integer >= 0. 

21  

22 >>> from leo.unittests.test_doctests import factorial 

23 

24 >>> [factorial(n) for n in range(6)] 

25 [1, 1, 2, 6, 24, 120] 

26 >>> factorial(30) 

27 265252859812191058636308480000000 

28 >>> factorial(-1) 

29 Traceback (most recent call last): 

30 ... 

31 ValueError: n must be >= 0 

32 

33 Factorials of floats are OK, but the float must be an exact integer: 

34 >>> factorial(30.1) 

35 Traceback (most recent call last): 

36 ... 

37 ValueError: n must be exact integer 

38 >>> factorial(30.0) 

39 265252859812191058636308480000000 

40 

41 It must also not be ridiculously large: 

42 >>> factorial(1e100) 

43 Traceback (most recent call last): 

44 ... 

45 OverflowError: n too large 

46 

47 """ # Blank line above is required. 

48 

49 import math 

50 if not n >= 0: 

51 raise ValueError("n must be >= 0") 

52 if math.floor(n) != n: 

53 raise ValueError("n must be exact integer") 

54 if n + 1 == n: # catch a value like 1e300 

55 raise OverflowError("n too large") 

56 result = 1 

57 factor = 2 

58 while factor <= n: 

59 result *= factor 

60 factor += 1 

61 return result 

62#@-others 

63 

64class TestDocTests(unittest.TestCase): # No need to be a subclass of leoTest2.LeoUnitTest. 

65 

66 def test_all_doctests(self): 

67 fails_list = [] # List of files with failing doctests. 

68 files_list = [] # List of files containing a doctest. 

69 n = 0 # Total doctests found 

70 for module in ('core', 'plugins', 'unittests'): 

71 module_path = os.path.join(leo_dir, module) 

72 self.assertTrue(os.path.exists(module_path), msg=repr(module_path)) 

73 path = os.path.join(module_path, '**', '*.py') 

74 files = glob.glob(path, recursive=True) 

75 files = [z for z in files if not z.endswith('__init__.py')] 

76 for f in files: 

77 # Exclude two problematic files. 

78 if 'dtest.py' in f or 'javascript.py' in f: 

79 continue 

80 fails, count = doctest.testfile(f, False) 

81 n += count 

82 if count: 

83 files_list.append(f) 

84 if fails: # pragma: no cover 

85 fails_list.append(f) 

86 print(f"{fails} failures in {g.shortFileName(f)}") 

87 self.assertEqual(fails_list, []) 

88 if 0: 

89 g.trace(f"{n} doctests found in {len(files_list)} file{g.plural(len(files_list))}") 

90 g.printObj(files_list, tag="files containing any doctest") 

91 g.printObj(fails_list, tag="files containing a failed doctest") 

92#@-leo