D5986: tests: add tests of pathcopies()

martinvonz (Martin von Zweigbergk) phabricator at mercurial-scm.org
Thu Feb 21 00:27:45 UTC 2019


martinvonz created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  I'm working on support for storing copy metadata in the changeset
  instead of in the filelog. When storing it in the changeset, it will
  obviously be efficient to get the copy metadata for all files in a
  single changeset, but it will be more expensive to get the copy
  metadata all revisions of a single file. Some algorithms will then
  need to be optimized differently. The first method I'm going to
  rewrite is pathcopies().
  
  This commit adds many tests for pathcopies(), so we can run the tests
  with both old and new versions of the code, as well as with metadata
  stored in filelog or in changeset (later). They use the
  debugpathcopies command I recently added (with no tests when it was
  added). They show a few bugs and few cases of slightly weird
  behavior. I'll fix the bugs in the next few commits.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D5986

AFFECTED FILES
  tests/test-copies.t

CHANGE DETAILS

diff --git a/tests/test-copies.t b/tests/test-copies.t
new file mode 100644
--- /dev/null
+++ b/tests/test-copies.t
@@ -0,0 +1,435 @@
+
+  $ cat >> $HGRCPATH << EOF
+  > [alias]
+  > l = log -G -T '{rev} {desc}\n{files}\n'
+  > EOF
+
+  $ REPONUM=0
+  $ newrepo() {
+  >     cd $TESTTMP
+  >     REPONUM=`expr $REPONUM + 1`
+  >     hg init repo-$REPONUM
+  >     cd repo-$REPONUM
+  > }
+
+Simple rename case
+  $ newrepo
+  $ echo x > x
+  $ hg ci -Aqm 'add x'
+  $ hg mv x y
+  $ hg ci -m 'rename x to y'
+  $ hg l
+  @  1 rename x to y
+  |  x y
+  o  0 add x
+     x
+  $ hg debugpathcopies 0 1
+  x -> y
+  $ hg debugpathcopies 1 0
+  y -> x
+Test filtering copies by path. We do filtering by destination.
+  $ hg debugpathcopies 0 1 x
+  $ hg debugpathcopies 1 0 x
+  y -> x
+  $ hg debugpathcopies 0 1 y
+  x -> y
+BROKEN: the following command should not include the copy
+  $ hg debugpathcopies 1 0 y
+  y -> x
+
+Copy a file onto another file
+  $ newrepo
+  $ echo x > x
+  $ echo y > y
+  $ hg ci -Aqm 'add x and y'
+  $ hg cp -f x y
+  $ hg ci -m 'copy x onto y'
+  $ hg l
+  @  1 copy x onto y
+  |  y
+  o  0 add x and y
+     x y
+Incorrectly doesn't show the rename
+  $ hg debugpathcopies 0 1
+
+Copy a file onto another file with same content. If metadata is stored in changeset, this does not
+produce a new filelog entry. The changeset's "files" entry should still list the file.
+  $ newrepo
+  $ echo x > x
+  $ echo x > x2
+  $ hg ci -Aqm 'add x and x2 with same content'
+  $ hg cp -f x x2
+  $ hg ci -m 'copy x onto x2'
+  $ hg l
+  @  1 copy x onto x2
+  |  x2
+  o  0 add x and x2 with same content
+     x x2
+Incorrectly doesn't show the rename
+  $ hg debugpathcopies 0 1
+
+Copy a file, then delete destination, then copy again. This does not create a new filelog entry.
+  $ newrepo
+  $ echo x > x
+  $ hg ci -Aqm 'add x'
+  $ hg cp x y
+  $ hg ci -m 'copy x to y'
+  $ hg rm y
+  $ hg ci -m 'remove y'
+  $ hg cp -f x y
+  $ hg ci -m 'copy x onto y (again)'
+  $ hg l
+  @  3 copy x onto y (again)
+  |  y
+  o  2 remove y
+  |  y
+  o  1 copy x to y
+  |  y
+  o  0 add x
+     x
+  $ hg debugpathcopies 0 3
+  x -> y
+
+Rename file in a loop: x->y->z->x
+  $ newrepo
+  $ echo x > x
+  $ hg ci -Aqm 'add x'
+  $ hg mv x y
+  $ hg ci -m 'rename x to y'
+  $ hg mv y z
+  $ hg ci -m 'rename y to z'
+  $ hg mv z x
+  $ hg ci -m 'rename z to x'
+  $ hg l
+  @  3 rename z to x
+  |  x z
+  o  2 rename y to z
+  |  y z
+  o  1 rename x to y
+  |  x y
+  o  0 add x
+     x
+  $ hg debugpathcopies 0 3
+
+Copy x to y, then remove y, then add back y. With copy metadata in the changeset, this could easily
+end up reporting y as copied from x (if we don't unmark it as a copy when it's removed).
+  $ newrepo
+  $ echo x > x
+  $ hg ci -Aqm 'add x'
+  $ hg mv x y
+  $ hg ci -m 'rename x to y'
+  $ hg rm y
+  $ hg ci -qm 'remove y'
+  $ echo x > y
+  $ hg ci -Aqm 'add back y'
+  $ hg l
+  @  3 add back y
+  |  y
+  o  2 remove y
+  |  y
+  o  1 rename x to y
+  |  x y
+  o  0 add x
+     x
+  $ hg debugpathcopies 0 3
+
+Copy x to z, then remove z, then copy x2 (same content as x) to z. With copy metadata in the
+changeset, the two copies here will have the same filelog entry, so ctx['z'].introrev() might point
+to the first commit that added the file. We should still report the copy as being from x2.
+  $ newrepo
+  $ echo x > x
+  $ echo x > x2
+  $ hg ci -Aqm 'add x and x2 with same content'
+  $ hg cp x z
+  $ hg ci -qm 'copy x to z'
+  $ hg rm z
+  $ hg ci -m 'remove z'
+  $ hg cp x2 z
+  $ hg ci -m 'copy x2 to z'
+  $ hg l
+  @  3 copy x2 to z
+  |  z
+  o  2 remove z
+  |  z
+  o  1 copy x to z
+  |  z
+  o  0 add x and x2 with same content
+     x x2
+  $ hg debugpathcopies 0 3
+  x2 -> z
+
+Create x and y, then rename them both to the same name, but on different sides of a fork
+  $ newrepo
+  $ echo x > x
+  $ echo y > y
+  $ hg ci -Aqm 'add x and y'
+  $ hg mv x z
+  $ hg ci -qm 'rename x to z'
+  $ hg co -q 0
+  $ hg mv y z
+  $ hg ci -qm 'rename y to z'
+  $ hg l
+  @  2 rename y to z
+  |  y z
+  | o  1 rename x to z
+  |/   x z
+  o  0 add x and y
+     x y
+  $ hg debugpathcopies 1 2
+  z -> x
+  y -> z
+
+Fork renames x to y on one side and removes x on the other
+  $ newrepo
+  $ echo x > x
+  $ hg ci -Aqm 'add x'
+  $ hg mv x y
+  $ hg ci -m 'rename x to y'
+  $ hg co -q 0
+  $ hg rm x
+  $ hg ci -m 'remove x'
+  created new head
+  $ hg l
+  @  2 remove x
+  |  x
+  | o  1 rename x to y
+  |/   x y
+  o  0 add x
+     x
+BROKEN: x doesn't exist here
+  $ hg debugpathcopies 1 2
+  y -> x
+
+Copies via null revision (there shouldn't be any)
+  $ newrepo
+  $ echo x > x
+  $ hg ci -Aqm 'add x'
+  $ hg cp x y
+  $ hg ci -m 'copy x to y'
+  $ hg co -q null
+  $ echo x > x
+  $ hg ci -Aqm 'add x (again)'
+  $ hg l
+  @  2 add x (again)
+     x
+  o  1 copy x to y
+  |  y
+  o  0 add x
+     x
+  $ hg debugpathcopies 1 2
+  $ hg debugpathcopies 2 1
+
+Merge rename from other branch
+  $ newrepo
+  $ echo x > x
+  $ hg ci -Aqm 'add x'
+  $ hg mv x y
+  $ hg ci -m 'rename x to y'
+  $ hg co -q 0
+  $ echo z > z
+  $ hg ci -Aqm 'add z'
+  $ hg merge -q 1
+  $ hg ci -m 'merge rename from p2'
+  $ hg l
+  @    3 merge rename from p2
+  |\   x
+  | o  2 add z
+  | |  z
+  o |  1 rename x to y
+  |/   x y
+  o  0 add x
+     x
+Perhaps we should indicate the rename here, but `hg status` is documented to be weird during
+merges, so...
+  $ hg debugpathcopies 0 3
+  x -> y
+  $ hg debugpathcopies 1 2
+  y -> x
+  $ hg debugpathcopies 1 3
+  $ hg debugpathcopies 2 3
+  x -> y
+
+Copy file from either side in a merge
+  $ newrepo
+  $ echo x > x
+  $ hg ci -Aqm 'add x'
+  $ hg co -q null
+  $ echo y > y
+  $ hg ci -Aqm 'add y'
+  $ hg merge -q 0
+  $ hg cp y z
+  $ hg ci -m 'copy file from p1 in merge'
+  $ hg co -q 1
+  $ hg merge -q 0
+  $ hg cp x z
+  $ hg ci -qm 'copy file from p2 in merge'
+  $ hg l
+  @    3 copy file from p2 in merge
+  |\   z
+  +---o  2 copy file from p1 in merge
+  | |/   z
+  | o  1 add y
+  |    y
+  o  0 add x
+     x
+  $ hg debugpathcopies 1 2
+  y -> z
+  $ hg debugpathcopies 0 2
+  $ hg debugpathcopies 1 3
+  $ hg debugpathcopies 0 3
+  x -> z
+
+Copy file that exists on both sides of the merge, same content on both sides
+  $ newrepo
+  $ echo x > x
+  $ hg ci -Aqm 'add x on branch 1'
+  $ hg co -q null
+  $ echo x > x
+  $ hg ci -Aqm 'add x on branch 2'
+  $ hg merge -q 0
+  $ hg cp x z
+  $ hg ci -qm 'merge'
+  $ hg l
+  @    2 merge
+  |\   z
+  | o  1 add x on branch 2
+  |    x
+  o  0 add x on branch 1
+     x
+It's a little weird that it shows up on both sides
+  $ hg debugpathcopies 1 2
+  x -> z
+  $ hg debugpathcopies 0 2
+  x -> z
+
+Copy file that exists on both sides of the merge, different content
+  $ newrepo
+  $ echo branch1 > x
+  $ hg ci -Aqm 'add x on branch 1'
+  $ hg co -q null
+  $ echo branch2 > x
+  $ hg ci -Aqm 'add x on branch 2'
+  $ hg merge -q 0
+  warning: conflicts while merging x! (edit, then use 'hg resolve --mark')
+  [1]
+  $ echo resolved > x
+  $ hg resolve -m x
+  (no more unresolved files)
+  $ hg cp x z
+  $ hg ci -qm 'merge'
+  $ hg l
+  @    2 merge
+  |\   x z
+  | o  1 add x on branch 2
+  |    x
+  o  0 add x on branch 1
+     x
+  $ hg debugpathcopies 1 2
+  $ hg debugpathcopies 0 2
+  x -> z
+
+Copy x->y on one side of merge and copy x->z on the other side. Pathcopies from one parent
+of the merge to the merge should include the copy from the other side.
+  $ newrepo
+  $ echo x > x
+  $ hg ci -Aqm 'add x'
+  $ hg cp x y
+  $ hg ci -qm 'copy x to y'
+  $ hg co -q 0
+  $ hg cp x z
+  $ hg ci -qm 'copy x to z'
+  $ hg merge -q 1
+  $ hg ci -m 'merge copy x->y and copy x->z'
+  $ hg l
+  @    3 merge copy x->y and copy x->z
+  |\
+  | o  2 copy x to z
+  | |  z
+  o |  1 copy x to y
+  |/   y
+  o  0 add x
+     x
+  $ hg debugpathcopies 2 3
+  x -> y
+  $ hg debugpathcopies 1 3
+  x -> z
+
+Copy x to y on one side of merge, create y and rename to z on the other side. Pathcopies from the
+first side should not include the y->z rename since y didn't exist in the merge base.
+  $ newrepo
+  $ echo x > x
+  $ hg ci -Aqm 'add x'
+  $ hg cp x y
+  $ hg ci -qm 'copy x to y'
+  $ hg co -q 0
+  $ echo y > y
+  $ hg ci -Aqm 'add y'
+  $ hg mv y z
+  $ hg ci -m 'rename y to z'
+  $ hg merge -q 1
+  $ hg ci -m 'merge'
+  $ hg l
+  @    4 merge
+  |\
+  | o  3 rename y to z
+  | |  y z
+  | o  2 add y
+  | |  y
+  o |  1 copy x to y
+  |/   y
+  o  0 add x
+     x
+  $ hg debugpathcopies 2 3
+  y -> z
+  $ hg debugpathcopies 1 3
+
+Create x and y, then rename x to z on one side of merge, and rename y to z and modify z on the
+other side.
+  $ newrepo
+  $ echo x > x
+  $ echo y > y
+  $ hg ci -Aqm 'add x and y'
+  $ hg mv x z
+  $ hg ci -qm 'rename x to z'
+  $ hg co -q 0
+  $ hg mv y z
+  $ hg ci -qm 'rename y to z'
+  $ echo z >> z
+  $ hg ci -m 'modify z'
+  $ hg merge -q 1
+  warning: conflicts while merging z! (edit, then use 'hg resolve --mark')
+  [1]
+  $ echo z > z
+  $ hg resolve -qm z
+  $ hg ci -m 'merge 1 into 3'
+Try merging the other direction too
+  $ hg co -q 1
+  $ hg merge -q 3
+  warning: conflicts while merging z! (edit, then use 'hg resolve --mark')
+  [1]
+  $ echo z > z
+  $ hg resolve -qm z
+  $ hg ci -m 'merge 3 into 1'
+  created new head
+  $ hg l
+  @    5 merge 3 into 1
+  |\   y z
+  +---o  4 merge 1 into 3
+  | |/   x z
+  | o  3 modify z
+  | |  z
+  | o  2 rename y to z
+  | |  y z
+  o |  1 rename x to z
+  |/   x z
+  o  0 add x and y
+     x y
+  $ hg debugpathcopies 1 4
+  $ hg debugpathcopies 2 4
+  $ hg debugpathcopies 0 4
+  x -> z
+  $ hg debugpathcopies 1 5
+  $ hg debugpathcopies 2 5
+  $ hg debugpathcopies 0 5
+  x -> z
+



To: martinvonz, #hg-reviewers
Cc: mercurial-devel


More information about the Mercurial-devel mailing list