ignore.t 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. #!/usr/bin/perl
  2. #
  3. # This file is part of GNU Stow.
  4. #
  5. # GNU Stow is free software: you can redistribute it and/or modify it
  6. # under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation, either version 3 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # GNU Stow is distributed in the hope that it will be useful, but
  11. # WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. # General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program. If not, see https://www.gnu.org/licenses/.
  17. #
  18. # Testing ignore lists.
  19. #
  20. use strict;
  21. use warnings;
  22. use File::Temp qw(tempdir);
  23. use Test::More tests => 287;
  24. use testutil;
  25. use Stow::Util qw(join_paths);
  26. init_test_dirs();
  27. cd("$TEST_DIR/target");
  28. my $stow = new_Stow();
  29. sub test_ignores {
  30. my ($stow_path, $package, $context, @tests) = @_;
  31. $context ||= '';
  32. while (@tests) {
  33. my $path = shift @tests;
  34. my $should_ignore = shift @tests;
  35. my $not = $should_ignore ? '' : ' not';
  36. my $was_ignored = $stow->ignore($stow_path, $package, $path);
  37. is(
  38. $was_ignored, $should_ignore,
  39. "Should$not ignore $path $context"
  40. );
  41. }
  42. }
  43. sub test_local_ignore_list_always_ignored_at_top_level {
  44. my ($stow_path, $package, $context) = @_;
  45. test_ignores(
  46. $stow_path, $package, $context,
  47. $Stow::LOCAL_IGNORE_FILE => 1,
  48. "subdir/" . $Stow::LOCAL_IGNORE_FILE => 0,
  49. );
  50. }
  51. sub test_built_in_list {
  52. my ($stow_path, $package, $context, $expect_ignores) = @_;
  53. for my $ignored ('CVS', '.cvsignore', '#autosave#') {
  54. for my $path ($ignored, "foo/bar/$ignored") {
  55. my $suffix = "$path.suffix";
  56. (my $prefix = $path) =~ s!([^/]+)$!prefix.$1!;
  57. test_ignores(
  58. $stow_path, $package, $context,
  59. $path => $expect_ignores,
  60. $prefix => 0,
  61. $suffix => 0,
  62. );
  63. }
  64. }
  65. # The pattern catching lock files allows suffixes but not prefixes
  66. for my $ignored ('.#lock-file') {
  67. for my $path ($ignored, "foo/bar/$ignored") {
  68. my $suffix = "$path.suffix";
  69. (my $prefix = $path) =~ s!([^/]+)$!prefix.$1!;
  70. test_ignores(
  71. $stow_path, $package, $context,
  72. $path => $expect_ignores,
  73. $prefix => 0,
  74. $suffix => $expect_ignores,
  75. );
  76. }
  77. }
  78. }
  79. sub test_user_global_list {
  80. my ($stow_path, $package, $context, $expect_ignores) = @_;
  81. for my $path ('', 'foo/bar/') {
  82. test_ignores(
  83. $stow_path, $package, $context,
  84. $path . 'exact' => $expect_ignores,
  85. $path . '0exact' => 0,
  86. $path . 'exact1' => 0,
  87. $path . '0exact1' => 0,
  88. $path . 'substring' => 0,
  89. $path . '0substring' => 0,
  90. $path . 'substring1' => 0,
  91. $path . '0substring1' => $expect_ignores,
  92. );
  93. }
  94. }
  95. sub setup_user_global_list {
  96. # Now test with global ignore list in home directory
  97. $ENV{HOME} = tempdir();
  98. make_file(join_paths($ENV{HOME}, $Stow::GLOBAL_IGNORE_FILE), <<EOF);
  99. exact
  100. .+substring.+ # here's a comment
  101. .+\.extension
  102. myprefix.+ #hi mum
  103. EOF
  104. }
  105. sub setup_package_local_list {
  106. my ($stow_path, $package, $list) = @_;
  107. my $package_path = join_paths($stow_path, $package);
  108. make_path($package_path);
  109. my $local_ignore = join_paths($package_path, $Stow::LOCAL_IGNORE_FILE);
  110. make_file($local_ignore, $list);
  111. $stow->invalidate_memoized_regexp($local_ignore);
  112. return $local_ignore;
  113. }
  114. sub main {
  115. my $stow_path = '../stow';
  116. my $package;
  117. my $context;
  118. # Test built-in list first. init_test_dirs() already set
  119. # $ENV{HOME} to ensure that we're not using the user's global
  120. # ignore list.
  121. $package = 'non-existent-package';
  122. $context = "when using built-in list";
  123. test_local_ignore_list_always_ignored_at_top_level($stow_path, $package, $context);
  124. test_built_in_list($stow_path, $package, $context, 1);
  125. # Test ~/.stow-global-ignore
  126. setup_user_global_list();
  127. $context = "when using ~/$Stow::GLOBAL_IGNORE_FILE";
  128. test_local_ignore_list_always_ignored_at_top_level($stow_path, $package, $context);
  129. test_built_in_list($stow_path, $package, $context, 0);
  130. test_user_global_list($stow_path, $package, $context, 1);
  131. # Test empty package-local .stow-local-ignore
  132. $package = 'ignorepkg';
  133. my $local_ignore = setup_package_local_list($stow_path, $package, "");
  134. $context = "when using empty $local_ignore";
  135. test_local_ignore_list_always_ignored_at_top_level($stow_path, $package, $context);
  136. test_built_in_list($stow_path, $package, $context, 0);
  137. test_user_global_list($stow_path, $package, $context, 0);
  138. test_ignores(
  139. $stow_path, $package, $context,
  140. 'random' => 0,
  141. 'foo2/bar' => 0,
  142. 'foo2/bars' => 0,
  143. 'foo2/bar/random' => 0,
  144. 'foo2/bazqux' => 0,
  145. 'xfoo2/bazqux' => 0,
  146. );
  147. # Test package-local .stow-local-ignore with only path segment regexps
  148. $local_ignore = setup_package_local_list($stow_path, $package, <<EOF);
  149. random
  150. EOF
  151. $context = "when using $local_ignore with only path segment regexps";
  152. test_local_ignore_list_always_ignored_at_top_level($stow_path, $package, $context);
  153. test_built_in_list($stow_path, $package, $context, 0);
  154. test_user_global_list($stow_path, $package, $context, 0);
  155. test_ignores(
  156. $stow_path, $package, $context,
  157. 'random' => 1,
  158. 'foo2/bar' => 0,
  159. 'foo2/bars' => 0,
  160. 'foo2/bar/random' => 1,
  161. 'foo2/bazqux' => 0,
  162. 'xfoo2/bazqux' => 0,
  163. );
  164. # Test package-local .stow-local-ignore with only full path regexps
  165. $local_ignore = setup_package_local_list($stow_path, $package, <<EOF);
  166. foo2/bar
  167. EOF
  168. $context = "when using $local_ignore with only full path regexps";
  169. test_local_ignore_list_always_ignored_at_top_level($stow_path, $package, $context);
  170. test_built_in_list($stow_path, $package, $context, 0);
  171. test_user_global_list($stow_path, $package, $context, 0);
  172. test_ignores(
  173. $stow_path, $package, $context,
  174. 'random' => 0,
  175. 'foo2/bar' => 1,
  176. 'foo2/bars' => 0,
  177. 'foo2/bar/random' => 1,
  178. 'foo2/bazqux' => 0,
  179. 'xfoo2/bazqux' => 0,
  180. );
  181. # Test package-local .stow-local-ignore with a mixture of regexps
  182. $local_ignore = setup_package_local_list($stow_path, $package, <<EOF);
  183. foo2/bar
  184. random
  185. foo2/baz.+
  186. EOF
  187. $context = "when using $local_ignore with mixture of regexps";
  188. test_local_ignore_list_always_ignored_at_top_level($stow_path, $package, $context);
  189. test_built_in_list($stow_path, $package, $context, 0);
  190. test_user_global_list($stow_path, $package, $context, 0);
  191. test_ignores(
  192. $stow_path, $package, $context,
  193. 'random' => 1,
  194. 'foo2/bar' => 1,
  195. 'foo2/bars' => 0,
  196. 'foo2/bar/random' => 1,
  197. 'foo2/bazqux' => 1,
  198. 'xfoo2/bazqux' => 0,
  199. );
  200. test_examples_in_manual($stow_path);
  201. test_invalid_regexp($stow_path, "Invalid segment regexp in list", <<EOF);
  202. this one's ok
  203. this one isn't|*!
  204. but this one is
  205. EOF
  206. test_invalid_regexp($stow_path, "Invalid full path regexp in list", <<EOF);
  207. this one's ok
  208. this/one isn't|*!
  209. but this one is
  210. EOF
  211. test_ignore_via_stow($stow_path);
  212. }
  213. sub test_examples_in_manual {
  214. my ($stow_path) = @_;
  215. my $package = 'ignorepkg';
  216. my $context = "(example from manual)";
  217. for my $re ('bazqux', 'baz.*', '.*qux', 'bar/.*x', '^/foo/.*qux') {
  218. my $local_ignore = setup_package_local_list($stow_path, $package, "$re\n");
  219. test_ignores(
  220. $stow_path, $package, $context,
  221. "foo/bar/bazqux" => 1,
  222. );
  223. }
  224. for my $re ('bar', 'baz', 'qux', 'o/bar/b') {
  225. my $local_ignore = setup_package_local_list($stow_path, $package, "$re\n");
  226. test_ignores(
  227. $stow_path, $package, $context,
  228. "foo/bar/bazqux" => 0,
  229. );
  230. }
  231. }
  232. sub test_invalid_regexp {
  233. my ($stow_path, $context, $list) = @_;
  234. my $package = 'ignorepkg';
  235. my $local_ignore = setup_package_local_list($stow_path, $package, $list);
  236. eval {
  237. test_ignores(
  238. $stow_path, $package, $context,
  239. "foo/bar/bazqux" => 1,
  240. );
  241. };
  242. like($@, qr/^Failed to compile regexp: Quantifier follows nothing in regex;/,
  243. $context);
  244. }
  245. sub test_ignore_via_stow {
  246. my ($stow_path) = @_;
  247. my $package = 'pkg1';
  248. make_path("$stow_path/$package/foo/bar");
  249. make_file("$stow_path/$package/foo/bar/baz");
  250. setup_package_local_list($stow_path, $package, 'foo');
  251. $stow->plan_stow($package);
  252. is($stow->get_tasks(), 0, 'top dir ignored');
  253. is($stow->get_conflicts(), 0, 'top dir ignored, no conflicts');
  254. make_path("foo");
  255. for my $ignore ('bar', 'foo/bar', '/foo/bar', '^/foo/bar', '^/fo.+ar') {
  256. setup_package_local_list($stow_path, $package, $ignore);
  257. $stow->plan_stow($package);
  258. is($stow->get_tasks(), 0, "bar ignored via $ignore");
  259. is($stow->get_conflicts(), 0, 'bar ignored, no conflicts');
  260. }
  261. make_file("$stow_path/$package/foo/qux");
  262. $stow->plan_stow($package);
  263. $stow->process_tasks();
  264. is($stow->get_conflicts(), 0, 'no conflicts stowing qux');
  265. ok(! -e "foo/bar", "bar ignore prevented stow");
  266. ok(-l "foo/qux", "qux not ignored and stowed");
  267. is(readlink("foo/qux"), "../$stow_path/$package/foo/qux", "qux stowed correctly");
  268. }
  269. main();