patch 8.1.1218: cannot set a directory for a tab page

Problem:    Cannot set a directory for a tab page.
Solution:   Add the tab-local directory. (Yegappan Lakshmanan, closes #4212)
diff --git a/src/testdir/test_getcwd.vim b/src/testdir/test_getcwd.vim
index ca09878..50c940f 100644
--- a/src/testdir/test_getcwd.vim
+++ b/src/testdir/test_getcwd.vim
@@ -97,6 +97,17 @@
   call assert_equal("y Xdir2 1", GetCwdInfo(2, tp_nr))
   call assert_equal("z Xdir3 1", GetCwdInfo(1, tp_nr))
   call assert_equal(g:topdir, getcwd(-1))
+  " Non existing windows and tab pages
+  call assert_equal('', getcwd(100))
+  call assert_equal(0, haslocaldir(100))
+  call assert_equal('', getcwd(10, 1))
+  call assert_equal(0, haslocaldir(10, 1))
+  call assert_equal('', getcwd(1, 5))
+  call assert_equal(0, haslocaldir(1, 5))
+  call assert_fails('call getcwd([])', 'E745:')
+  call assert_fails('call getcwd(1, [])', 'E745:')
+  call assert_fails('call haslocaldir([])', 'E745:')
+  call assert_fails('call haslocaldir(1, [])', 'E745:')
 endfunc
 
 function Test_GetCwd_lcd_shellslash()
@@ -110,3 +121,144 @@
     call assert_equal(cwd[-1:], '\')
   endif
 endfunc
+
+" Test for :tcd
+function Test_Tab_Local_Cwd()
+  enew | only | tabonly
+
+  call mkdir('Xtabdir1')
+  call mkdir('Xtabdir2')
+  call mkdir('Xwindir1')
+  call mkdir('Xwindir2')
+  call mkdir('Xwindir3')
+
+  " Create three tabpages with three windows each
+  edit a
+  botright new b
+  botright new c
+  tabnew m
+  botright new n
+  botright new o
+  tabnew x
+  botright new y
+  botright new z
+
+  " Setup different directories for the tab pages and windows
+  tabrewind
+  1wincmd w
+  lcd Xwindir1
+  tabnext
+  tcd Xtabdir1
+  2wincmd w
+  lcd ../Xwindir2
+  tabnext
+  tcd Xtabdir2
+  3wincmd w
+  lcd ../Xwindir3
+
+  " Check the directories of various windows
+  call assert_equal("a Xwindir1 1", GetCwdInfo(1, 1))
+  call assert_equal("b Xtopdir 0", GetCwdInfo(2, 1))
+  call assert_equal("c Xtopdir 0", GetCwdInfo(3, 1))
+  call assert_equal("m Xtabdir1 2", GetCwdInfo(1, 2))
+  call assert_equal("n Xwindir2 1", GetCwdInfo(2, 2))
+  call assert_equal("o Xtabdir1 2", GetCwdInfo(3, 2))
+  call assert_equal("x Xtabdir2 2", GetCwdInfo(1, 3))
+  call assert_equal("y Xtabdir2 2", GetCwdInfo(2, 3))
+  call assert_equal("z Xwindir3 1", GetCwdInfo(3, 3))
+
+  " Check the tabpage directories
+  call assert_equal('Xtopdir', fnamemodify(getcwd(-1, 1), ':t'))
+  call assert_equal('Xtabdir1', fnamemodify(getcwd(-1, 2), ':t'))
+  call assert_equal('Xtabdir2', fnamemodify(getcwd(-1, 3), ':t'))
+  call assert_equal('', fnamemodify(getcwd(-1, 4), ':t'))
+
+  " Jump to different windows in the tab pages and check the current directory
+  tabrewind | 1wincmd w
+  call assert_equal('Xwindir1', fnamemodify(getcwd(), ':t'))
+  call assert_equal('Xwindir1', fnamemodify(getcwd(0), ':t'))
+  call assert_equal('Xwindir1', fnamemodify(getcwd(0, 0), ':t'))
+  call assert_true(haslocaldir(0))
+  call assert_equal(0, haslocaldir(-1, 0))
+  call assert_equal('Xtopdir', fnamemodify(getcwd(-1, 0), ':t'))
+  call assert_equal(g:topdir, getcwd(-1))
+  2wincmd w
+  call assert_equal('Xtopdir', fnamemodify(getcwd(), ':t'))
+  call assert_equal('Xtopdir', fnamemodify(getcwd(0), ':t'))
+  call assert_equal('Xtopdir', fnamemodify(getcwd(0, 0), ':t'))
+  call assert_false(haslocaldir(0))
+  call assert_equal(0, haslocaldir(-1, 0))
+  call assert_equal('Xtopdir', fnamemodify(getcwd(-1, 0), ':t'))
+  call assert_equal(g:topdir, getcwd(-1))
+  tabnext | 1wincmd w
+  call assert_equal('Xtabdir1', fnamemodify(getcwd(), ':t'))
+  call assert_equal('Xtabdir1', fnamemodify(getcwd(0), ':t'))
+  call assert_equal('Xtabdir1', fnamemodify(getcwd(0, 0), ':t'))
+  call assert_true(haslocaldir(0))
+  call assert_equal(2, haslocaldir(-1, 0))
+  call assert_equal('Xtabdir1', fnamemodify(getcwd(-1, 0), ':t'))
+  call assert_equal(g:topdir, getcwd(-1))
+  2wincmd w
+  call assert_equal('Xwindir2', fnamemodify(getcwd(), ':t'))
+  call assert_equal('Xwindir2', fnamemodify(getcwd(0), ':t'))
+  call assert_equal('Xwindir2', fnamemodify(getcwd(0, 0), ':t'))
+  call assert_true(haslocaldir(0))
+  call assert_equal(2, haslocaldir(-1, 0))
+  call assert_equal('Xtabdir1', fnamemodify(getcwd(-1, 0), ':t'))
+  call assert_equal(g:topdir, getcwd(-1))
+  tabnext | 1wincmd w
+  call assert_equal('Xtabdir2', fnamemodify(getcwd(), ':t'))
+  call assert_equal('Xtabdir2', fnamemodify(getcwd(0), ':t'))
+  call assert_equal('Xtabdir2', fnamemodify(getcwd(0, 0), ':t'))
+  call assert_true(haslocaldir(0))
+  call assert_equal(2, haslocaldir(-1, 0))
+  call assert_equal('Xtabdir2', fnamemodify(getcwd(-1, 0), ':t'))
+  call assert_equal(g:topdir, getcwd(-1))
+  3wincmd w
+  call assert_equal('Xwindir3', fnamemodify(getcwd(), ':t'))
+  call assert_equal('Xwindir3', fnamemodify(getcwd(0), ':t'))
+  call assert_equal('Xwindir3', fnamemodify(getcwd(0, 0), ':t'))
+  call assert_true(haslocaldir(0))
+  call assert_equal(2, haslocaldir(-1, 0))
+  call assert_equal('Xtabdir2', fnamemodify(getcwd(-1, 0), ':t'))
+  call assert_equal(g:topdir, getcwd(-1))
+
+  " A new tab page should inherit the directory of the current tab page
+  tabrewind | 1wincmd w
+  tabnew g
+  call assert_equal("g Xwindir1 1", GetCwdInfo(0, 0))
+  tabclose | tabrewind
+  2wincmd w
+  tabnew h
+  call assert_equal("h Xtopdir 0", GetCwdInfo(0, 0))
+  tabclose
+  tabnext 2 | 1wincmd w
+  tabnew j
+  call assert_equal("j Xtabdir1 2", GetCwdInfo(0, 0))
+  tabclose
+
+  " Change the global directory for the first tab page
+  tabrewind | 1wincmd w
+  cd ../Xdir1
+  call assert_equal("a Xdir1 0", GetCwdInfo(1, 1))
+  call assert_equal("b Xdir1 0", GetCwdInfo(2, 1))
+  call assert_equal("m Xtabdir1 2", GetCwdInfo(1, 2))
+  call assert_equal("n Xwindir2 1", GetCwdInfo(2, 2))
+
+  " Change the global directory for the second tab page
+  tabnext | 1wincmd w
+  cd ../Xdir3
+  call assert_equal("m Xdir3 0", GetCwdInfo(1, 2))
+  call assert_equal("n Xwindir2 1", GetCwdInfo(2, 2))
+  call assert_equal("o Xdir3 0", GetCwdInfo(3, 2))
+
+  " Change the tab-local directory for the third tab page
+  tabnext | 1wincmd w
+  cd ../Xdir1
+  call assert_equal("x Xdir1 0", GetCwdInfo(1, 3))
+  call assert_equal("y Xdir1 0", GetCwdInfo(2, 3))
+  call assert_equal("z Xwindir3 1", GetCwdInfo(3, 3))
+
+  enew | only | tabonly
+  new
+endfunc