Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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 # "apply_config": {"config": {"whatever": True}}, 

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

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

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

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

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

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

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

116 } 

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

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

119 try: 

120 id_ = 0 

121 for method_name in methods: 

122 id_ += 1 

123 if method_name not in exclude: 

124 assert getattr(server, method_name), method_name 

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

126 message = { 

127 "id": id_, 

128 "action": "!" + method_name, 

129 "param": param, 

130 } 

131 try: 

132 # Don't call the method directly. 

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

134 server._do_message(message) 

135 except Exception as e: 

136 if method_name not in expected: 

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

138 finally: 

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

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

141 def test_open_and_close(self): 

142 # server = self.server 

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

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

145 log = False 

146 table = [ 

147 # Open file. 

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

149 # Switch to the second file. 

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

151 # Open again. This should be valid. 

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

153 # Better test of _ap_to_p. 

154 ("!set_current_position", { 

155 "ap": { 

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

157 "childIndex": 1, 

158 "stack": [], 

159 } 

160 }), 

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

162 # Close the second file. 

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

164 # Close the first file. 

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

166 ] 

167 for action, package in table: 

168 self._request(action, package) 

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

170 def test_find_commands(self): 

171 

172 tag = 'test_find_commands' 

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

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

175 log = False 

176 # Open the file & create the StringFindTabManager. 

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

178 # 

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

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

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

182 if log: 

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

184 # 

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

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

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

188 if log: 

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

190 # 

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

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

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

194 if log: 

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

196 # 

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

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

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

200 if log: 

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

202 

203 #@-others 

204#@-others 

205 

206#@-leo