1# Copyright (C) 2006, 2007, 2009-2012, 2016 Canonical Ltd 2# 3# This program is free software; you can redistribute it and/or modify 4# it under the terms of the GNU General Public License as published by 5# the Free Software Foundation; either version 2 of the License, or 6# (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program; if not, write to the Free Software 15# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 16# 17 18"""Tests of the 'brz add' command.""" 19 20import os 21 22from breezy import ( 23 osutils, 24 tests, 25 ) 26from breezy.tests import ( 27 features, 28 script, 29 ) 30from breezy.tests.scenarios import load_tests_apply_scenarios 31 32 33load_tests = load_tests_apply_scenarios 34 35 36class TestAdd(tests.TestCaseWithTransport): 37 38 scenarios = [ 39 ('pre-views', {'branch_tree_format': 'pack-0.92'}), 40 ('view-aware', {'branch_tree_format': '2a'}), 41 ] 42 43 def make_branch_and_tree(self, dir): 44 return super(TestAdd, self).make_branch_and_tree( 45 dir, format=self.branch_tree_format) 46 47 def test_add_reports(self): 48 """add command prints the names of added files.""" 49 tree = self.make_branch_and_tree('.') 50 self.build_tree(['top.txt', 'dir/', 'dir/sub.txt', 'CVS']) 51 self.build_tree_contents([('.bzrignore', b'CVS\n')]) 52 out = self.run_bzr('add')[0] 53 # the ordering is not defined at the moment 54 results = sorted(out.rstrip('\n').split('\n')) 55 self.assertEqual(['adding .bzrignore', 56 'adding dir', 57 'adding dir/sub.txt', 58 'adding top.txt'], 59 results) 60 out = self.run_bzr('add -v')[0] 61 results = sorted(out.rstrip('\n').split('\n')) 62 self.assertEqual(['ignored CVS matching "CVS"'], 63 results) 64 65 def test_add_quiet_is(self): 66 """add -q does not print the names of added files.""" 67 tree = self.make_branch_and_tree('.') 68 self.build_tree(['top.txt', 'dir/', 'dir/sub.txt']) 69 out = self.run_bzr('add -q')[0] 70 # the ordering is not defined at the moment 71 results = sorted(out.rstrip('\n').split('\n')) 72 self.assertEqual([''], results) 73 74 def test_add_in_unversioned(self): 75 """Try to add a file in an unversioned directory. 76 77 "brz add" should add the parent(s) as necessary. 78 """ 79 tree = self.make_branch_and_tree('.') 80 self.build_tree(['inertiatic/', 'inertiatic/esp']) 81 self.assertEqual(self.run_bzr('unknowns')[0], 'inertiatic\n') 82 self.run_bzr('add inertiatic/esp') 83 self.assertEqual(self.run_bzr('unknowns')[0], '') 84 85 # Multiple unversioned parents 86 self.build_tree(['veil/', 'veil/cerpin/', 'veil/cerpin/taxt']) 87 self.assertEqual(self.run_bzr('unknowns')[0], 'veil\n') 88 self.run_bzr('add veil/cerpin/taxt') 89 self.assertEqual(self.run_bzr('unknowns')[0], '') 90 91 # Check whacky paths work 92 self.build_tree(['cicatriz/', 'cicatriz/esp']) 93 self.assertEqual(self.run_bzr('unknowns')[0], 'cicatriz\n') 94 self.run_bzr('add inertiatic/../cicatriz/esp') 95 self.assertEqual(self.run_bzr('unknowns')[0], '') 96 97 def test_add_no_recurse(self): 98 tree = self.make_branch_and_tree('.') 99 self.build_tree(['inertiatic/', 'inertiatic/esp']) 100 self.assertEqual(self.run_bzr('unknowns')[0], 'inertiatic\n') 101 self.run_bzr('add -N inertiatic') 102 self.assertEqual(self.run_bzr('unknowns')[0], 'inertiatic/esp\n') 103 104 def test_add_in_versioned(self): 105 """Try to add a file in a versioned directory. 106 107 "brz add" should do this happily. 108 """ 109 tree = self.make_branch_and_tree('.') 110 self.build_tree(['inertiatic/', 'inertiatic/esp']) 111 self.assertEqual(self.run_bzr('unknowns')[0], 'inertiatic\n') 112 self.run_bzr('add --no-recurse inertiatic') 113 self.assertEqual(self.run_bzr('unknowns')[0], 'inertiatic/esp\n') 114 self.run_bzr('add inertiatic/esp') 115 self.assertEqual(self.run_bzr('unknowns')[0], '') 116 117 def test_subdir_add(self): 118 """Add in subdirectory should add only things from there down""" 119 eq = self.assertEqual 120 ass = self.assertTrue 121 122 t = self.make_branch_and_tree('.') 123 b = t.branch 124 self.build_tree(['src/', 'README']) 125 126 eq(sorted(t.unknowns()), 127 ['README', 'src']) 128 129 self.run_bzr('add src') 130 131 self.build_tree(['src/foo.c']) 132 133 # add with no arguments in a subdirectory gets only files below that 134 # subdirectory 135 self.run_bzr('add', working_dir='src') 136 self.assertEqual('README\n', 137 self.run_bzr('unknowns', working_dir='src')[0]) 138 # reopen to see the new changes 139 t = t.controldir.open_workingtree('src') 140 versioned = [path for path, entry in t.iter_entries_by_dir()] 141 self.assertEqual(versioned, ['', 'src', 'src/foo.c']) 142 143 # add from the parent directory should pick up all file names 144 self.run_bzr('add') 145 self.assertEqual(self.run_bzr('unknowns')[0], '') 146 self.run_bzr('check') 147 148 def test_add_missing(self): 149 """brz add foo where foo is missing should error.""" 150 self.make_branch_and_tree('.') 151 self.run_bzr('add missing-file', retcode=3) 152 153 def test_add_from(self): 154 base_tree = self.make_branch_and_tree('base') 155 self.build_tree(['base/a', 'base/b/', 'base/b/c']) 156 base_tree.add(['a', 'b', 'b/c']) 157 base_tree.commit('foo') 158 159 new_tree = self.make_branch_and_tree('new') 160 self.build_tree(['new/a', 'new/b/', 'new/b/c', 'd']) 161 162 out, err = self.run_bzr('add --file-ids-from ../base', 163 working_dir='new') 164 self.assertEqual('', err) 165 self.assertEqualDiff('adding a w/ file id from a\n' 166 'adding b w/ file id from b\n' 167 'adding b/c w/ file id from b/c\n', 168 out) 169 new_tree = new_tree.controldir.open_workingtree() 170 self.assertEqual(base_tree.path2id('a'), new_tree.path2id('a')) 171 self.assertEqual(base_tree.path2id('b'), new_tree.path2id('b')) 172 self.assertEqual(base_tree.path2id('b/c'), new_tree.path2id('b/c')) 173 174 def test_add_from_subdir(self): 175 base_tree = self.make_branch_and_tree('base') 176 self.build_tree(['base/a', 'base/b/', 'base/b/c', 'base/b/d']) 177 base_tree.add(['a', 'b', 'b/c', 'b/d']) 178 base_tree.commit('foo') 179 180 new_tree = self.make_branch_and_tree('new') 181 self.build_tree(['new/c', 'new/d']) 182 183 out, err = self.run_bzr('add --file-ids-from ../base/b', 184 working_dir='new') 185 self.assertEqual('', err) 186 self.assertEqualDiff('adding c w/ file id from b/c\n' 187 'adding d w/ file id from b/d\n', 188 out) 189 190 new_tree = new_tree.controldir.open_workingtree('new') 191 self.assertEqual(base_tree.path2id('b/c'), new_tree.path2id('c')) 192 self.assertEqual(base_tree.path2id('b/d'), new_tree.path2id('d')) 193 194 def test_add_dry_run(self): 195 """Test a dry run add, make sure nothing is added.""" 196 wt = self.make_branch_and_tree('.') 197 self.build_tree(['inertiatic/', 'inertiatic/esp']) 198 self.assertEqual(list(wt.unknowns()), ['inertiatic']) 199 self.run_bzr('add --dry-run') 200 self.assertEqual(list(wt.unknowns()), ['inertiatic']) 201 202 def test_add_control_dir(self): 203 """The control dir and its content should be refused.""" 204 self.make_branch_and_tree('.') 205 err = self.run_bzr('add .bzr', retcode=3)[1] 206 self.assertContainsRe(err, r'ERROR:.*\.bzr.*control file') 207 err = self.run_bzr('add .bzr/README', retcode=3)[1] 208 self.assertContainsRe(err, r'ERROR:.*\.bzr.*control file') 209 self.build_tree(['.bzr/crescent']) 210 err = self.run_bzr('add .bzr/crescent', retcode=3)[1] 211 self.assertContainsRe(err, r'ERROR:.*\.bzr.*control file') 212 213 def test_add_via_symlink(self): 214 self.requireFeature(features.SymlinkFeature) 215 self.make_branch_and_tree('source') 216 self.build_tree(['source/top.txt']) 217 os.symlink('source', 'link') 218 out = self.run_bzr(['add', 'link/top.txt'])[0] 219 self.assertEqual(out, 'adding top.txt\n') 220 221 def test_add_symlink_to_abspath(self): 222 self.requireFeature(features.SymlinkFeature) 223 self.make_branch_and_tree('tree') 224 os.symlink(osutils.abspath('target'), 'tree/link') 225 out = self.run_bzr(['add', 'tree/link'])[0] 226 self.assertEqual(out, 'adding link\n') 227 228 def test_add_not_child(self): 229 # https://bugs.launchpad.net/bzr/+bug/98735 230 sr = script.ScriptRunner() 231 self.make_branch_and_tree('tree1') 232 self.make_branch_and_tree('tree2') 233 self.build_tree(['tree1/a', 'tree2/b']) 234 sr.run_script(self, ''' 235 $ brz add tree1/a tree2/b 236 2>brz: ERROR: Path "...tree2/b" is not a child of path "...tree1" 237 ''') 238 239 def test_add_multiple_files_in_unicode_cwd(self): 240 """Adding multiple files in a non-ascii cwd, see lp:686611""" 241 self.requireFeature(features.UnicodeFilenameFeature) 242 self.make_branch_and_tree(u"\xA7") 243 self.build_tree([u"\xA7/a", u"\xA7/b"]) 244 out, err = self.run_bzr(["add", "a", "b"], working_dir=u"\xA7") 245 self.assertEqual(out, "adding a\n" "adding b\n") 246 self.assertEqual(err, "") 247 248 def test_add_skip_large_files(self): 249 """Test skipping files larger than add.maximum_file_size""" 250 tree = self.make_branch_and_tree('.') 251 self.build_tree(['small.txt', 'big.txt', 'big2.txt']) 252 self.build_tree_contents([('small.txt', b'0\n')]) 253 self.build_tree_contents([('big.txt', b'01234567890123456789\n')]) 254 self.build_tree_contents([('big2.txt', b'01234567890123456789\n')]) 255 tree.branch.get_config_stack().set('add.maximum_file_size', 5) 256 out = self.run_bzr('add')[0] 257 results = sorted(out.rstrip('\n').split('\n')) 258 self.assertEqual(['adding small.txt'], results) 259 # named items never skipped, even if over max 260 out, err = self.run_bzr(["add", "big2.txt"]) 261 results = sorted(out.rstrip('\n').split('\n')) 262 self.assertEqual(['adding big2.txt'], results) 263 self.assertEqual("", err) 264 tree.branch.get_config_stack().set('add.maximum_file_size', 30) 265 out = self.run_bzr('add')[0] 266 results = sorted(out.rstrip('\n').split('\n')) 267 self.assertEqual(['adding big.txt'], results) 268 269 def test_add_backslash(self): 270 # pad.lv/165151 271 if os.path.sep == '\\': 272 # TODO(jelmer): Test that backslashes are appropriately 273 # ignored? 274 raise tests.TestNotApplicable( 275 'unable to add filenames with backslashes where ' 276 ' it is the path separator') 277 tree = self.make_branch_and_tree('.') 278 self.build_tree(['\\']) 279 self.assertEqual('adding \\\n', self.run_bzr('add \\\\')[0]) 280 self.assertEqual('\\\n', self.run_bzr('ls --versioned')[0]) 281