sup

A curses threads-with-tags style email client

sup.git

git clone https://supmua.dev/git/sup/

test/unit/test_line_cursor_mode.rb (5881B) - raw

      1 require "test_helper"
      2 require "dummy_buffer"
      3 
      4 require "sup"
      5 
      6 class TestLineCursorMode < Minitest::Test
      7   def setup
      8     $config = {
      9       :load_more_threads_hysteresis => 0,
     10       :load_more_threads_when_scrolling => true,
     11       :continuous_scroll => false,
     12     }
     13     Redwood::BufferManager.init
     14     @modes_to_cleanup = []
     15     @lines = []
     16     @load_more = Thread::Queue.new
     17     @buffer_height = 41  # 1 for status line, 40 usable lines
     18   end
     19 
     20   def teardown
     21     @modes_to_cleanup.each { |mode| mode.cleanup }
     22     Redwood::BufferManager.deinstantiate!
     23     $config = nil
     24   end
     25 
     26   def make_mode
     27     mode = Redwood::LineCursorMode.new
     28     @modes_to_cleanup << mode
     29     lines = @lines
     30     mode.define_singleton_method(:lines) { lines.length }
     31     mode.define_singleton_method(:[]) { |i| lines[i] }
     32     mode.send(:to_load_more) { |n| @load_more << n }
     33     mode.buffer = Redwood::DummyBuffer.new 100, @buffer_height
     34     mode.spawned
     35     mode.draw
     36     mode
     37   end
     38 
     39   def expect_load_more n
     40     begin
     41       requested = @load_more.pop :timeout => 0.1
     42     rescue ThreadError
     43       ## Ruby < 3.2 does not obey the timeout for Queue#pop
     44       sleep 0.1
     45       requested = @load_more.pop true
     46     end
     47     refute_nil requested, "Expected load_more callbacks to fire"
     48     assert_equal n, requested
     49     (0...n).map { |i| @lines << "line #{i}" }
     50   end
     51 
     52   def test_cursor_down
     53     mode = make_mode
     54     expect_load_more 41
     55     mode.draw  # curpos gets messed up without this call, why?
     56 
     57     21.times do
     58       mode.handle_input Ncurses::CharCode.character('j')
     59     end
     60     assert_equal 21, mode.curpos
     61     assert_equal 0, mode.topline
     62 
     63     ## Two past halfway, load_more callbacks are triggered.
     64     mode.handle_input Ncurses::CharCode.character('j')
     65     assert_equal 22, mode.curpos
     66     expect_load_more 40
     67 
     68     17.times do
     69       mode.handle_input Ncurses::CharCode.character('j')
     70     end
     71     assert_equal 39, mode.curpos
     72     assert_equal 0, mode.topline
     73 
     74     ## From the bottom line, it wraps back to the top of the next page.
     75     mode.handle_input Ncurses::CharCode.character('j')
     76     assert_equal 40, mode.curpos
     77     assert_equal 40, mode.topline
     78   end
     79 
     80   def test_scroll_down
     81     mode = make_mode
     82     expect_load_more 41
     83 
     84     ## When the cursor is already at the top, it moves with the scroll.
     85     assert_equal 0, mode.curpos
     86     assert_equal 0, mode.topline
     87     mode.handle_input Ncurses::CharCode.character('J')
     88     assert_equal 1, mode.curpos
     89     assert_equal 1, mode.topline
     90 
     91     3.times do
     92       mode.handle_input Ncurses::CharCode.character('j')
     93     end
     94     assert_equal 4, mode.curpos
     95     assert_equal 1, mode.topline
     96 
     97     ## When the cursor is not at the top, it keeps its place and the
     98     ## buffer scrolls underneath it.
     99     mode.handle_input Ncurses::CharCode.character('J')
    100     assert_equal 4, mode.curpos
    101     assert_equal 2, mode.topline
    102 
    103     ## It always loads 10 more if we would scroll past the bottom.
    104     expect_load_more 10
    105   end
    106 
    107   def test_page_down
    108     mode = make_mode
    109     expect_load_more 41
    110 
    111     mode.handle_input Ncurses::CharCode.keycode(Ncurses::KEY_NPAGE)
    112     assert_equal 40, mode.curpos
    113     assert_equal 40, mode.topline
    114     expect_load_more 40
    115 
    116     mode.handle_input Ncurses::CharCode.keycode(Ncurses::KEY_NPAGE)
    117     assert_equal 80, mode.curpos
    118     assert_equal 80, mode.topline
    119     assert_equal 81, mode.lines
    120     expect_load_more 40
    121   end
    122 
    123   def test_page_down_when_fully_populated
    124     mode = make_mode
    125     expect_load_more 41
    126     (0...119).map { |i| @lines << "more line #{i}" }  # enough for 4 full pages
    127 
    128     mode.handle_input Ncurses::CharCode.keycode(Ncurses::KEY_NPAGE)
    129     assert_equal 40, mode.curpos
    130     assert_equal 40, mode.topline
    131 
    132     ## Relative cursor position is preserved when paging down.
    133     3.times do
    134       mode.handle_input Ncurses::CharCode.character('j')
    135     end
    136     assert_equal 43, mode.curpos
    137     assert_equal 40, mode.topline
    138     mode.handle_input Ncurses::CharCode.keycode(Ncurses::KEY_NPAGE)
    139     assert_equal 83, mode.curpos
    140     assert_equal 80, mode.topline
    141   end
    142 
    143   def test_half_page_down
    144     mode = make_mode
    145     expect_load_more 41
    146 
    147     mode.handle_input Ncurses::CharCode.character("\C-d")
    148     assert_equal 20, mode.curpos
    149     assert_equal 20, mode.topline
    150     expect_load_more 40
    151 
    152     mode.handle_input Ncurses::CharCode.character("\C-d")
    153     assert_equal 40, mode.curpos
    154     assert_equal 40, mode.topline
    155   end
    156 
    157   def test_half_page_down_when_fully_populated
    158     mode = make_mode
    159     expect_load_more 41
    160     (0...119).map { |i| @lines << "more line #{i}" }  # enough for 4 full pages
    161 
    162     mode.handle_input Ncurses::CharCode.character("\C-d")
    163     assert_equal 20, mode.curpos
    164     assert_equal 20, mode.topline
    165 
    166     25.times do
    167       mode.handle_input Ncurses::CharCode.character('j')
    168     end
    169     assert_equal 45, mode.curpos
    170     assert_equal 20, mode.topline
    171     mode.handle_input Ncurses::CharCode.character("\C-d")
    172     assert_equal 45, mode.curpos
    173     assert_equal 40, mode.topline
    174   end
    175 
    176   def test_half_page_up
    177     mode = make_mode
    178     expect_load_more 41
    179     (0...119).map { |i| @lines << "more line #{i}" }  # enough for 4 full pages
    180 
    181     mode.handle_input Ncurses::CharCode.keycode(Ncurses::KEY_NPAGE)
    182     assert_equal 40, mode.curpos
    183     assert_equal 40, mode.topline
    184 
    185     mode.handle_input Ncurses::CharCode.character("\C-u")
    186     assert_equal 40, mode.curpos
    187     assert_equal 20, mode.topline
    188 
    189     mode.handle_input Ncurses::CharCode.character('j')
    190     assert_equal 41, mode.curpos
    191     assert_equal 20, mode.topline
    192 
    193     mode.handle_input Ncurses::CharCode.character("\C-u")
    194     assert_equal 40, mode.curpos
    195     assert_equal 0, mode.topline
    196   end
    197 
    198   def test_jump_to_end
    199     mode = make_mode
    200     expect_load_more 41
    201 
    202     mode.handle_input Ncurses::CharCode.keycode(Ncurses::KEY_END)
    203     assert_equal 40, mode.curpos
    204     assert_equal 1, mode.topline
    205     assert_equal 41, mode.botline
    206     expect_load_more 40
    207   end
    208 end