@@ -218,6 +218,35 @@ def test_subwindows_references(self):
218218 del win2
219219 gc_collect ()
220220
221+ def test_dupwin (self ):
222+ win = curses .newwin (5 , 10 , 2 , 3 )
223+ win .addstr (0 , 0 , 'ABCDE' )
224+ win .addstr (1 , 0 , 'fghij' )
225+ dup = win .dupwin ()
226+ # Same geometry and contents as the original.
227+ self .assertEqual (dup .getbegyx (), win .getbegyx ())
228+ self .assertEqual (dup .getmaxyx (), win .getmaxyx ())
229+ self .assertEqual (dup .instr (0 , 0 , 5 ), b'ABCDE' )
230+ self .assertEqual (dup .instr (1 , 0 , 5 ), b'fghij' )
231+ # The duplicate is independent, not a subwindow.
232+ if hasattr (dup , 'is_subwin' ):
233+ self .assertIs (dup .is_subwin (), False )
234+ self .assertIsNone (dup .getparent ())
235+ # Changes to one do not affect the other.
236+ dup .addstr (0 , 0 , 'xxxxx' )
237+ win .addstr (1 , 0 , 'YYYYY' )
238+ self .assertEqual (win .instr (0 , 0 , 5 ), b'ABCDE' )
239+ self .assertEqual (dup .instr (0 , 0 , 5 ), b'xxxxx' )
240+ self .assertEqual (dup .instr (1 , 0 , 5 ), b'fghij' )
241+ self .assertEqual (win .instr (1 , 0 , 5 ), b'YYYYY' )
242+ # A subwindow can also be duplicated; the duplicate is independent.
243+ sub = win .subwin (3 , 5 , 2 , 3 )
244+ subdup = sub .dupwin ()
245+ self .assertEqual (subdup .getmaxyx (), sub .getmaxyx ())
246+ if hasattr (subdup , 'is_subwin' ):
247+ self .assertIs (subdup .is_subwin (), False )
248+ self .assertIsNone (subdup .getparent ())
249+
221250 def test_move_cursor (self ):
222251 stdscr = self .stdscr
223252 win = stdscr .subwin (10 , 15 , 2 , 5 )
@@ -1096,6 +1125,43 @@ def test_putwin(self):
10961125 self .assertEqual (win .getmaxyx (), (5 , 12 ))
10971126 self .assertEqual (win .instr (2 , 0 ), b' Lorem ipsum' )
10981127
1128+ def test_scr_dump (self ):
1129+ # Test scr_dump(), scr_restore(), scr_init() and scr_set().
1130+ # scr_dump() writes the virtual screen to a named file; the other three
1131+ # functions load it back. The dumped image is internal curses state,
1132+ # not a window, so the round-trip is checked by comparing dump files
1133+ # rather than reading cells.
1134+ stdscr = self .stdscr
1135+ stdscr .erase ()
1136+ stdscr .addstr (0 , 0 , 'screen dump test' )
1137+ stdscr .refresh ()
1138+ with tempfile .TemporaryDirectory () as d :
1139+ dump = os .path .join (d , 'dump' )
1140+ self .assertIsNone (curses .scr_dump (dump ))
1141+ # Dumping the same screen again is deterministic.
1142+ dump2 = os .path .join (d , 'dump2' )
1143+ curses .scr_dump (dump2 )
1144+ with open (dump , 'rb' ) as f1 , open (dump2 , 'rb' ) as f2 :
1145+ self .assertEqual (f1 .read (), f2 .read ())
1146+ # scr_restore() reloads that virtual screen, so dumping it again
1147+ # reproduces the original file even after the screen has changed.
1148+ stdscr .erase ()
1149+ stdscr .addstr (0 , 0 , 'something else' )
1150+ stdscr .refresh ()
1151+ self .assertIsNone (curses .scr_restore (dump ))
1152+ restored = os .path .join (d , 'restored' )
1153+ curses .scr_dump (restored )
1154+ with open (dump , 'rb' ) as f1 , open (restored , 'rb' ) as f2 :
1155+ self .assertEqual (f1 .read (), f2 .read ())
1156+ # scr_init() and scr_set() accept a dump file and return None.
1157+ self .assertIsNone (curses .scr_init (dump ))
1158+ self .assertIsNone (curses .scr_set (dump ))
1159+ # A bytes (path-like) filename is accepted too.
1160+ curses .scr_dump (os .fsencode (dump ))
1161+ # Restoring from a missing file is an error.
1162+ self .assertRaises (curses .error ,
1163+ curses .scr_restore , os .path .join (d , 'nope' ))
1164+
10991165 def test_borders_and_lines (self ):
11001166 win = curses .newwin (5 , 10 , 5 , 2 )
11011167 win .border ('|' , '!' , '-' , '_' ,
@@ -1339,8 +1405,6 @@ def test_state_getters(self):
13391405 # Each is_*() getter returns the value set by the matching setter.
13401406 for setter , getter in [
13411407 ('clearok' , 'is_cleared' ),
1342- ('idcok' , 'is_idcok' ),
1343- ('idlok' , 'is_idlok' ),
13441408 ('keypad' , 'is_keypad' ),
13451409 ('leaveok' , 'is_leaveok' ),
13461410 ('nodelay' , 'is_nodelay' ),
@@ -1351,6 +1415,19 @@ def test_state_getters(self):
13511415 self .assertIs (getattr (stdscr , getter )(), True )
13521416 getattr (stdscr , setter )(False )
13531417 self .assertIs (getattr (stdscr , getter )(), False )
1418+
1419+ # idcok()/idlok() only take effect if the terminal can insert/delete
1420+ # characters/lines, so the getter reflects that capability.
1421+ stdscr .idcok (True )
1422+ self .assertIs (stdscr .is_idcok (), curses .has_ic ())
1423+ stdscr .idcok (False )
1424+ self .assertIs (stdscr .is_idcok (), False )
1425+
1426+ stdscr .idlok (True )
1427+ self .assertIs (stdscr .is_idlok (),
1428+ curses .has_il () or curses .tigetstr ('csr' ) is not None )
1429+ stdscr .idlok (False )
1430+ self .assertIs (stdscr .is_idlok (), False )
13541431 if hasattr (stdscr , 'immedok' ):
13551432 stdscr .immedok (True )
13561433 self .assertIs (stdscr .is_immedok (), True )
0 commit comments