Coverage for core\test_leoserver.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

91 statements  

1#@+leo-ver=5-thin 

2#@+node:ekr.20210820203000.1: * @file ../unittests/core/test_leoserver.py 

3"""Unit tests for leo/core/leoserver.py""" 

4 

5import json 

6import os 

7import leo.core.leoserver as leoserver 

8from leo.core.leoTest2 import LeoUnitTest 

9 

10# Globals. 

11g = None 

12g_leoserver = None 

13g_server = None 

14 

15#@+others 

16#@+node:ekr.20210901070918.1: ** class TestLeoServer(LeoUnitTest) 

17class TestLeoServer(LeoUnitTest): 

18 """Tests of LeoServer class.""" 

19 request_number = 0 

20 #@+others 

21 #@+node:felix.20210621233316.99: *3* TestLeoServer: Setup and TearDown 

22 @classmethod 

23 def setUpClass(cls): 

24 # Assume we are running in the leo-editor directory. 

25 # pylint: disable=import-self 

26 global g, g_leoserver, g_server 

27 g_leoserver = leoserver 

28 g_server = leoserver.LeoServer(testing=True) 

29 g = g_server.g 

30 assert g 

31 

32 @classmethod 

33 def tearDownClass(cls): 

34 global g_leoserver, g_server 

35 try: 

36 g_server.shut_down({}) 

37 print('===== server did not terminate properly ====') # pragma:no cover 

38 except g_leoserver.TerminateServer: 

39 pass 

40 except leoserver.ServerError: # pragma:no cover 

41 pass 

42 

43 def setUp(self): 

44 global g_server 

45 self.server = g_server 

46 g.unitTesting = True 

47 

48 def tearDown(self): 

49 g.unitTesting = False 

50 

51 #@+node:felix.20210621233316.100: *3* TestLeoServer._request 

52 def _request(self, action, param=None): 

53 server = self.server 

54 self.request_number += 1 

55 log_flag = param.get("log") 

56 # Direct server commands require an exclamation mark '!' prefix 

57 # to distinguish them from Leo's commander's own methods. 

58 d = { 

59 "action": action, 

60 "id": self.request_number 

61 } 

62 if param: 

63 d["param"] = param 

64 response = server._do_message(d) 

65 # _make_response calls json_dumps. Undo it with json.loads. 

66 answer = json.loads(response) 

67 if log_flag: 

68 g.printObj(answer, tag=f"response to {action!r}") # pragma: no cover 

69 return answer 

70 #@+node:felix.20210621233316.102: *3* TestLeoServer.test_most_public_server_methods 

71 def test_most_public_server_methods(self): 

72 server = self.server 

73 tag = 'test_most_public_server_methods' 

74 assert isinstance(server, g_leoserver.LeoServer), self.server 

75 test_dot_leo = g.os_path_finalize_join(g.app.loadDir, '..', 'test', 'test.leo') 

76 assert os.path.exists(test_dot_leo), repr(test_dot_leo) 

77 methods = server._get_all_server_commands() 

78 # Ensure that some methods happen at the end. 

79 for z in ('toggle_mark', 'undo', 'redo'): 

80 methods.remove(z) 

81 for z in ('toggle_mark', 'toggle_mark', 'undo', 'redo'): 

82 methods.append(z) 

83 # g.printObj(methods, tag=methods) 

84 exclude = [ 

85 # Find methods... 

86 'change_all', 'change_then_find', 

87 'clone_find_all', 'clone_find_all_flattened', 'clone_find_tag', 

88 'find_all', 'find_def', 'find_next', 'find_previous', 'find_var', 

89 'goto_script', 

90 'tag_children', 

91 # Other methods 

92 'delete_node', 'cut_node', # dangerous. 

93 'click_button', 'get_buttons', 'remove_button', # Require plugins. 

94 'paste_node', 'paste_as_clone_node', # New exclusion. 

95 'save_file', # way too dangerous! 

96 # 'set_selection', # Not ready yet. 

97 'open_file', 'close_file', # Done by hand. 

98 'import_any_file', 

99 'insert_child_named_node', 

100 'insert_named_node', 

101 'set_ask_result', 

102 'set_opened_file', 

103 'set_search_settings', 

104 'shut_down', # Don't shut down the server. 

105 ] 

106 expected = ['error'] 

107 param_d = { 

108 "remove_tag": {"tag": "testTag"}, 

109 "tag_node": {"tag": "testTag"}, 

110 # "apply_config": {"config": {"whatever": True}}, 

111 "get_focus": {"log": False}, 

112 "set_body": {"body": "new body\n", 'gnx': "ekr.20061008140603"}, 

113 "set_headline": {"name": "new headline"}, 

114 "get_all_server_commands": {"log": False}, 

115 "get_all_leo_commands": {"log": False}, 

116 # "paste_node": {"name", "paste-node-name"}, 

117 # "paste_as_clone_node": {"name", "paste-node-name"}, 

118 } 

119 # First open a test file & performa all tests. 

120 server.open_file({"filename": test_dot_leo}) # A real file. 

121 try: 

122 id_ = 0 

123 for method_name in methods: 

124 id_ += 1 

125 if method_name not in exclude: 

126 assert getattr(server, method_name), method_name 

127 param = param_d.get(method_name, {}) 

128 message = { 

129 "id": id_, 

130 "action": "!" + method_name, 

131 "param": param, 

132 } 

133 try: 

134 # Don't call the method directly. 

135 # That would disable trace/verbose logic, checking, etc. 

136 server._do_message(message) 

137 except Exception as e: 

138 if method_name not in expected: 

139 print(f"Exception in {tag}: {method_name!r} {e}") # pragma:no cover 

140 finally: 

141 server.close_file({"forced": True}) 

142 #@+node:felix.20210621233316.103: *3* TestLeoServer.test_open_and_close 

143 def test_open_and_close(self): 

144 # server = self.server 

145 test_dot_leo = g.os_path_finalize_join(g.app.loadDir, '..', 'test', 'test.leo') 

146 assert os.path.exists(test_dot_leo), repr(test_dot_leo) 

147 log = False 

148 table = [ 

149 # Open file. 

150 ("!open_file", {"log": log, "filename": "xyzzy.leo"}), # Does not exist. 

151 # Switch to the second file. 

152 ("!open_file", {"log": log, "filename": test_dot_leo}), # Does exist. 

153 # Open again. This should be valid. 

154 ("!open_file", {"log": False, "filename": test_dot_leo}), 

155 # Better test of _ap_to_p. 

156 ("!set_current_position", { 

157 "ap": { 

158 "gnx": "ekr.20180311131424.1", # Recent 

159 "childIndex": 1, 

160 "stack": [], 

161 } 

162 }), 

163 ("!get_ua", {"log": log}), 

164 # Close the second file. 

165 ("!close_file", {"log": log, "forced": True}), 

166 # Close the first file. 

167 ("!close_file", {"log": log, "forced": True}), 

168 ] 

169 for action, package in table: 

170 self._request(action, package) 

171 #@+node:felix.20210621233316.104: *3* TestLeoServer.test_find_commands 

172 def test_find_commands(self): 

173 

174 tag = 'test_find_commands' 

175 test_dot_leo = g.os_path_finalize_join(g.app.loadDir, '..', 'test', 'test.leo') 

176 assert os.path.exists(test_dot_leo), repr(test_dot_leo) 

177 log = False 

178 # Open the file & create the StringFindTabManager. 

179 self._request("!open_file", {"log": False, "filename": test_dot_leo}) 

180 # 

181 # Batch find commands: The answer is a count of found nodes. 

182 for method in ('!find_all', '!clone_find_all', '!clone_find_all_flattened'): 

183 answer = self._request(method, {"log": log, "find_text": "def"}) 

184 if log: 

185 g.printObj(answer, tag=f"{tag}:{method}: answer") # pragma: no cover 

186 # 

187 # Find commands that may select text: The answer is (p, pos, newpos). 

188 for method in ('!find_next', '!find_previous', '!find_def', '!find_var'): 

189 answer = self._request(method, {"log": log, "find_text": "def"}) 

190 if log: 

191 g.printObj(answer, tag=f"{tag}:{method}: answer") # pragma: no cover 

192 # 

193 # Change commands: The answer is a count of changed nodes. 

194 for method in ('!replace_all', '!replace_then_find'): 

195 answer = self._request(method, {"log": log, "find_text": "def", "change_text": "DEF"}) 

196 if log: 

197 g.printObj(answer, tag=f"{tag}:{method}: answer") # pragma: no cover 

198 # 

199 # Tag commands. Why they are in leoFind.py?? 

200 for method in ('!clone_find_tag', '!tag_children'): 

201 answer = self._request(method, {"log": log, "tag": "my-tag"}) 

202 if log: 

203 g.printObj(answer, tag=f"{tag}:{method}: answer") # pragma: no cover 

204 

205 #@-others 

206#@-others 

207 

208#@-leo