1# Copyright 2017 The TensorFlow Authors. All Rights Reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# ============================================================================== 15"""Unit tests for curses-based CLI widgets.""" 16from __future__ import absolute_import 17from __future__ import division 18from __future__ import print_function 19 20from tensorflow.python.debug.cli import curses_widgets 21from tensorflow.python.debug.cli import debugger_cli_common 22from tensorflow.python.framework import test_util 23from tensorflow.python.platform import googletest 24 25RTL = debugger_cli_common.RichTextLines 26CNH = curses_widgets.CursesNavigationHistory 27 28 29class CNHTest(test_util.TensorFlowTestCase): 30 31 def testConstructorWorks(self): 32 CNH(10) 33 34 def testConstructorWithInvalidCapacityErrors(self): 35 with self.assertRaises(ValueError): 36 CNH(0) 37 with self.assertRaises(ValueError): 38 CNH(-1) 39 40 def testInitialStateIsCorrect(self): 41 nav_history = CNH(10) 42 self.assertEqual(0, nav_history.size()) 43 self.assertFalse(nav_history.can_go_forward()) 44 self.assertFalse(nav_history.can_go_back()) 45 46 with self.assertRaisesRegex(ValueError, "Empty navigation history"): 47 nav_history.go_back() 48 with self.assertRaisesRegex(ValueError, "Empty navigation history"): 49 nav_history.go_forward() 50 with self.assertRaisesRegex(ValueError, "Empty navigation history"): 51 nav_history.update_scroll_position(3) 52 53 def testAddOneItemWorks(self): 54 nav_history = CNH(10) 55 nav_history.add_item("foo", RTL(["bar"]), 0) 56 57 self.assertEqual(1, nav_history.size()) 58 self.assertEqual(0, nav_history.pointer()) 59 60 self.assertFalse(nav_history.can_go_forward()) 61 self.assertFalse(nav_history.can_go_back()) 62 63 output = nav_history.go_back() 64 self.assertEqual("foo", output.command) 65 self.assertEqual(["bar"], output.screen_output.lines) 66 self.assertEqual(0, output.scroll_position) 67 68 def testAddItemsBeyondCapacityWorks(self): 69 nav_history = CNH(2) 70 nav_history.add_item("foo", RTL(["foo_output"]), 0) 71 nav_history.add_item("bar", RTL(["bar_output"]), 0) 72 73 self.assertEqual(2, nav_history.size()) 74 self.assertEqual(1, nav_history.pointer()) 75 self.assertTrue(nav_history.can_go_back()) 76 self.assertFalse(nav_history.can_go_forward()) 77 78 nav_history.add_item("baz", RTL(["baz_output"]), 0) 79 80 self.assertEqual(2, nav_history.size()) 81 self.assertEqual(1, nav_history.pointer()) 82 self.assertTrue(nav_history.can_go_back()) 83 self.assertFalse(nav_history.can_go_forward()) 84 85 item = nav_history.go_back() 86 self.assertEqual("bar", item.command) 87 self.assertFalse(nav_history.can_go_back()) 88 self.assertTrue(nav_history.can_go_forward()) 89 90 item = nav_history.go_forward() 91 self.assertEqual("baz", item.command) 92 self.assertTrue(nav_history.can_go_back()) 93 self.assertFalse(nav_history.can_go_forward()) 94 95 def testAddItemFromNonLatestPointerPositionWorks(self): 96 nav_history = CNH(2) 97 nav_history.add_item("foo", RTL(["foo_output"]), 0) 98 nav_history.add_item("bar", RTL(["bar_output"]), 0) 99 100 nav_history.go_back() 101 nav_history.add_item("baz", RTL(["baz_output"]), 0) 102 103 self.assertEqual(2, nav_history.size()) 104 self.assertEqual(1, nav_history.pointer()) 105 self.assertTrue(nav_history.can_go_back()) 106 self.assertFalse(nav_history.can_go_forward()) 107 108 item = nav_history.go_back() 109 self.assertEqual("foo", item.command) 110 item = nav_history.go_forward() 111 self.assertEqual("baz", item.command) 112 113 def testUpdateScrollPositionOnLatestItemWorks(self): 114 nav_history = CNH(2) 115 nav_history.add_item("foo", RTL(["foo_out", "more_foo_out"]), 0) 116 nav_history.add_item("bar", RTL(["bar_out", "more_bar_out"]), 0) 117 118 nav_history.update_scroll_position(1) 119 nav_history.go_back() 120 item = nav_history.go_forward() 121 self.assertEqual("bar", item.command) 122 self.assertEqual(1, item.scroll_position) 123 124 def testUpdateScrollPositionOnOldItemWorks(self): 125 nav_history = CNH(2) 126 nav_history.add_item("foo", RTL(["foo_out", "more_foo_out"]), 0) 127 nav_history.add_item("bar", RTL(["bar_out", "more_bar_out"]), 0) 128 129 item = nav_history.go_back() 130 self.assertEqual("foo", item.command) 131 self.assertEqual(0, item.scroll_position) 132 133 nav_history.update_scroll_position(1) 134 nav_history.go_forward() 135 item = nav_history.go_back() 136 self.assertEqual("foo", item.command) 137 self.assertEqual(1, item.scroll_position) 138 139 item = nav_history.go_forward() 140 self.assertEqual("bar", item.command) 141 self.assertEqual(0, item.scroll_position) 142 143 def testRenderWithEmptyHistoryWorks(self): 144 nav_history = CNH(2) 145 146 output = nav_history.render(40, "prev", "next") 147 self.assertEqual(1, len(output.lines)) 148 self.assertEqual( 149 "| " + CNH.BACK_ARROW_TEXT + " " + CNH.FORWARD_ARROW_TEXT, 150 output.lines[0]) 151 self.assertEqual({}, output.font_attr_segs) 152 153 def testRenderLatestWithSufficientLengthWorks(self): 154 nav_history = CNH(2) 155 nav_history.add_item("foo", RTL(["foo_out", "more_foo_out"]), 0) 156 nav_history.add_item("bar", RTL(["bar_out", "more_bar_out"]), 0) 157 158 output = nav_history.render( 159 40, 160 "prev", 161 "next", 162 latest_command_attribute="green", 163 old_command_attribute="yellow") 164 self.assertEqual(1, len(output.lines)) 165 self.assertEqual( 166 "| " + CNH.BACK_ARROW_TEXT + " " + CNH.FORWARD_ARROW_TEXT + 167 " | bar", 168 output.lines[0]) 169 self.assertEqual(2, output.font_attr_segs[0][0][0]) 170 self.assertEqual(5, output.font_attr_segs[0][0][1]) 171 self.assertEqual("prev", output.font_attr_segs[0][0][2].content) 172 173 self.assertEqual(12, output.font_attr_segs[0][1][0]) 174 self.assertEqual(15, output.font_attr_segs[0][1][1]) 175 self.assertEqual("green", output.font_attr_segs[0][1][2]) 176 177 def testRenderOldButNotOldestWithSufficientLengthWorks(self): 178 nav_history = CNH(3) 179 nav_history.add_item("foo", RTL(["foo_out", "more_foo_out"]), 0) 180 nav_history.add_item("bar", RTL(["bar_out", "more_bar_out"]), 0) 181 nav_history.add_item("baz", RTL(["baz_out", "more_baz_out"]), 0) 182 183 nav_history.go_back() 184 185 output = nav_history.render( 186 40, 187 "prev", 188 "next", 189 latest_command_attribute="green", 190 old_command_attribute="yellow") 191 self.assertEqual(1, len(output.lines)) 192 self.assertEqual( 193 "| " + CNH.BACK_ARROW_TEXT + " " + CNH.FORWARD_ARROW_TEXT + 194 " | (-1) bar", 195 output.lines[0]) 196 self.assertEqual(2, output.font_attr_segs[0][0][0]) 197 self.assertEqual(5, output.font_attr_segs[0][0][1]) 198 self.assertEqual("prev", output.font_attr_segs[0][0][2].content) 199 200 self.assertEqual(6, output.font_attr_segs[0][1][0]) 201 self.assertEqual(9, output.font_attr_segs[0][1][1]) 202 self.assertEqual("next", output.font_attr_segs[0][1][2].content) 203 204 self.assertEqual(12, output.font_attr_segs[0][2][0]) 205 self.assertEqual(17, output.font_attr_segs[0][2][1]) 206 self.assertEqual("yellow", output.font_attr_segs[0][2][2]) 207 208 self.assertEqual(17, output.font_attr_segs[0][3][0]) 209 self.assertEqual(20, output.font_attr_segs[0][3][1]) 210 self.assertEqual("yellow", output.font_attr_segs[0][3][2]) 211 212 def testRenderOldestWithSufficientLengthWorks(self): 213 nav_history = CNH(3) 214 nav_history.add_item("foo", RTL(["foo_out", "more_foo_out"]), 0) 215 nav_history.add_item("bar", RTL(["bar_out", "more_bar_out"]), 0) 216 nav_history.add_item("baz", RTL(["baz_out", "more_baz_out"]), 0) 217 218 nav_history.go_back() 219 nav_history.go_back() 220 221 output = nav_history.render( 222 40, 223 "prev", 224 "next", 225 latest_command_attribute="green", 226 old_command_attribute="yellow") 227 self.assertEqual(1, len(output.lines)) 228 self.assertEqual( 229 "| " + CNH.BACK_ARROW_TEXT + " " + CNH.FORWARD_ARROW_TEXT + 230 " | (-2) foo", 231 output.lines[0]) 232 self.assertEqual(6, output.font_attr_segs[0][0][0]) 233 self.assertEqual(9, output.font_attr_segs[0][0][1]) 234 self.assertEqual("next", output.font_attr_segs[0][0][2].content) 235 236 self.assertEqual(12, output.font_attr_segs[0][1][0]) 237 self.assertEqual(17, output.font_attr_segs[0][1][1]) 238 self.assertEqual("yellow", output.font_attr_segs[0][1][2]) 239 240 self.assertEqual(17, output.font_attr_segs[0][2][0]) 241 self.assertEqual(20, output.font_attr_segs[0][2][1]) 242 self.assertEqual("yellow", output.font_attr_segs[0][2][2]) 243 244 def testRenderWithInsufficientLengthWorks(self): 245 nav_history = CNH(2) 246 nav_history.add_item("long_command", RTL(["output"]), 0) 247 248 output = nav_history.render( 249 15, 250 "prev", 251 "next", 252 latest_command_attribute="green", 253 old_command_attribute="yellow") 254 self.assertEqual(1, len(output.lines)) 255 self.assertEqual( 256 "| " + CNH.BACK_ARROW_TEXT + " " + CNH.FORWARD_ARROW_TEXT + 257 " | lon", 258 output.lines[0]) 259 260 self.assertEqual(12, output.font_attr_segs[0][0][0]) 261 self.assertEqual(15, output.font_attr_segs[0][0][1]) 262 self.assertEqual("green", output.font_attr_segs[0][0][2]) 263 264 265if __name__ == "__main__": 266 googletest.main() 267