diff options
| author | Edward Thomson <ethomson@edwardthomson.com> | 2018-11-11 16:40:56 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-11-11 16:40:56 +0000 |
| commit | 11fbead80b425eacf483fe16beaf8891f582f905 (patch) | |
| tree | 347128ac534ff09809772ac5e87f6ccbbb742793 /tests | |
| parent | 2f5f3cfdcd7b15fc74fa1ed4b1695150ed071504 (diff) | |
| parent | 4e746d80d229a77b08c5689a64d880bde5fd960f (diff) | |
| download | libgit2-11fbead80b425eacf483fe16beaf8891f582f905.tar.gz | |
Merge pull request #4705 from libgit2/ethomson/apply
Patch (diff) application
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/apply/apply_helpers.h | 587 | ||||
| -rw-r--r-- | tests/apply/both.c | 736 | ||||
| -rw-r--r-- | tests/apply/callbacks.c | 128 | ||||
| -rw-r--r-- | tests/apply/fromdiff.c | 48 | ||||
| -rw-r--r-- | tests/apply/fromfile.c | 2 | ||||
| -rw-r--r-- | tests/apply/index.c | 321 | ||||
| -rw-r--r-- | tests/apply/partial.c | 232 | ||||
| -rw-r--r-- | tests/apply/tree.c | 58 | ||||
| -rw-r--r-- | tests/apply/workdir.c | 358 | ||||
| -rw-r--r-- | tests/iterator/workdir.c | 46 | ||||
| -rw-r--r-- | tests/patch/patch_common.h | 106 | ||||
| -rw-r--r-- | tests/resources/merge-recursive/.gitted/objects/06/d3fefb8726ab1099acc76e02dfb85e034b2538 | bin | 0 -> 375 bytes |
12 files changed, 2620 insertions, 2 deletions
diff --git a/tests/apply/apply_helpers.h b/tests/apply/apply_helpers.h new file mode 100644 index 000000000..81563351e --- /dev/null +++ b/tests/apply/apply_helpers.h @@ -0,0 +1,587 @@ +#include "../merge/merge_helpers.h" + +#define TEST_REPO_PATH "merge-recursive" + +#define DIFF_MODIFY_TWO_FILES \ + "diff --git a/asparagus.txt b/asparagus.txt\n" \ + "index f516580..ffb36e5 100644\n" \ + "--- a/asparagus.txt\n" \ + "+++ b/asparagus.txt\n" \ + "@@ -1 +1 @@\n" \ + "-ASPARAGUS SOUP!\n" \ + "+ASPARAGUS SOUP.\n" \ + "diff --git a/veal.txt b/veal.txt\n" \ + "index 94d2c01..a7b0665 100644\n" \ + "--- a/veal.txt\n" \ + "+++ b/veal.txt\n" \ + "@@ -1 +1 @@\n" \ + "-VEAL SOUP!\n" \ + "+VEAL SOUP.\n" \ + "@@ -7 +7 @@ occasionally, then put into it a shin of veal, let it boil two hours\n" \ + "-longer. take out the slices of ham, and skim off the grease if any\n" \ + "+longer; take out the slices of ham, and skim off the grease if any\n" + +#define DIFF_DELETE_FILE \ + "diff --git a/gravy.txt b/gravy.txt\n" \ + "deleted file mode 100644\n" \ + "index c4e6cca..0000000\n" \ + "--- a/gravy.txt\n" \ + "+++ /dev/null\n" \ + "@@ -1,8 +0,0 @@\n" \ + "-GRAVY SOUP.\n" \ + "-\n" \ + "-Get eight pounds of coarse lean beef--wash it clean and lay it in your\n" \ + "-pot, put in the same ingredients as for the shin soup, with the same\n" \ + "-quantity of water, and follow the process directed for that. Strain the\n" \ + "-soup through a sieve, and serve it up clear, with nothing more than\n" \ + "-toasted bread in it; two table-spoonsful of mushroom catsup will add a\n" \ + "-fine flavour to the soup.\n" + +#define DIFF_ADD_FILE \ + "diff --git a/newfile.txt b/newfile.txt\n" \ + "new file mode 100644\n" \ + "index 0000000..6370543\n" \ + "--- /dev/null\n" \ + "+++ b/newfile.txt\n" \ + "@@ -0,0 +1,2 @@\n" \ + "+This is a new file!\n" \ + "+Added by a patch.\n" + +#define DIFF_EXECUTABLE_FILE \ + "diff --git a/beef.txt b/beef.txt\n" \ + "old mode 100644\n" \ + "new mode 100755\n" + +#define DIFF_MANY_CHANGES_ONE \ + "diff --git a/veal.txt b/veal.txt\n" \ + "index 94d2c01..c9d7d5d 100644\n" \ + "--- a/veal.txt\n" \ + "+++ b/veal.txt\n" \ + "@@ -1,2 +1,2 @@\n" \ + "-VEAL SOUP!\n" \ + "+VEAL SOUP\n" \ + " \n" \ + "@@ -4,3 +4,2 @@\n" \ + " spoonful of black pepper pounded, and two of salt, with two or three\n" \ + "-slices of lean ham; let it boil steadily two hours; skim it\n" \ + " occasionally, then put into it a shin of veal, let it boil two hours\n" \ + "@@ -8,3 +7,3 @@\n" \ + " should rise, take a gill of good cream, mix with it two table-spoonsful\n" \ + "-of flour very nicely, and the yelks of two eggs beaten well, strain this\n" \ + "+OF FLOUR very nicely, and the yelks of two eggs beaten well, strain this\n" \ + " mixture, and add some chopped parsley; pour some soup on by degrees,\n" \ + "@@ -12,2 +11,3 @@\n" \ + " boiled two or three minutes to take off the raw taste of the eggs. If\n" \ + "+Inserted line.\n" \ + " the cream be not perfectly sweet, and the eggs quite new, the thickening\n" \ + "@@ -15,3 +15,3 @@\n" \ + " in, first taking off their skins, by letting them stand a few minutes in\n" \ + "-hot water, when they may be easily peeled. When made in this way you\n" \ + "+Changed line.\n" \ + " must thicken it with the flour only. Any part of the veal may be used,\n" + +#define DIFF_MANY_CHANGES_TWO \ + "diff --git a/veal.txt b/veal.txt\n" \ + "index 94d2c01..6b943d6 100644\n" \ + "--- a/veal.txt\n" \ + "+++ b/veal.txt\n" \ + "@@ -1,2 +1,2 @@\n" \ + "-VEAL SOUP!\n" \ + "+VEAL SOUP!!!\n" \ + " \n" \ + "@@ -4,3 +4,2 @@\n" \ + " spoonful of black pepper pounded, and two of salt, with two or three\n" \ + "-slices of lean ham; let it boil steadily two hours; skim it\n" \ + " occasionally, then put into it a shin of veal, let it boil two hours\n" \ + "@@ -8,3 +7,3 @@\n" \ + " should rise, take a gill of good cream, mix with it two table-spoonsful\n" \ + "-of flour very nicely, and the yelks of two eggs beaten well, strain this\n" \ + "+of flour very nicely, AND the yelks of two eggs beaten well, strain this\n" \ + " mixture, and add some chopped parsley; pour some soup on by degrees,\n" \ + "@@ -12,2 +11,3 @@\n" \ + " boiled two or three minutes to take off the raw taste of the eggs. If\n" \ + "+New line.\n" \ + " the cream be not perfectly sweet, and the eggs quite new, the thickening\n" \ + "@@ -15,4 +15,5 @@\n" \ + " in, first taking off their skins, by letting them stand a few minutes in\n" \ + "-hot water, when they may be easily peeled. When made in this way you\n" \ + "-must thicken it with the flour only. Any part of the veal may be used,\n" \ + "-but the shin or knuckle is the nicest.\n" \ + "+HOT water, when they may be easily peeled. When made in this way you\n" \ + "+must THICKEN it with the flour only. Any part of the veal may be used,\n" \ + "+but the shin OR knuckle is the nicest.\n" \ + "+Another new line.\n" \ + +#define DIFF_RENAME_FILE \ + "diff --git a/beef.txt b/notbeef.txt\n" \ + "similarity index 100%\n" \ + "rename from beef.txt\n" \ + "rename to notbeef.txt\n" + +#define DIFF_RENAME_AND_MODIFY_FILE \ + "diff --git a/beef.txt b/notbeef.txt\n" \ + "similarity index 97%\n" \ + "rename from beef.txt\n" \ + "rename to notbeef.txt\n" \ + "index 68f6182..6fa1014 100644\n" \ + "--- a/beef.txt\n" \ + "+++ b/notbeef.txt\n" \ + "@@ -1,4 +1,4 @@\n" \ + "-BEEF SOUP.\n" \ + "+THIS IS NOT BEEF SOUP, IT HAS A NEW NAME.\n" \ + "\n" \ + " Take the hind shin of beef, cut off all the flesh off the leg-bone,\n" \ + " which must be taken away entirely, or the soup will be greasy. Wash the\n" + +#define DIFF_RENAME_A_TO_B_TO_C \ + "diff --git a/asparagus.txt b/asparagus.txt\n" \ + "deleted file mode 100644\n" \ + "index f516580..0000000\n" \ + "--- a/asparagus.txt\n" \ + "+++ /dev/null\n" \ + "@@ -1,10 +0,0 @@\n" \ + "-ASPARAGUS SOUP!\n" \ + "-\n" \ + "-Take four large bunches of asparagus, scrape it nicely, cut off one inch\n" \ + "-of the tops, and lay them in water, chop the stalks and put them on the\n" \ + "-fire with a piece of bacon, a large onion cut up, and pepper and salt;\n" \ + "-add two quarts of water, boil them till the stalks are quite soft, then\n" \ + "-pulp them through a sieve, and strain the water to it, which must be put\n" \ + "-back in the pot; put into it a chicken cut up, with the tops of\n" \ + "-asparagus which had been laid by, boil it until these last articles are\n" \ + "-sufficiently done, thicken with flour, butter and milk, and serve it up.\n" \ + "diff --git a/beef.txt b/beef.txt\n" \ + "index 68f6182..f516580 100644\n" \ + "--- a/beef.txt\n" \ + "+++ b/beef.txt\n" \ + "@@ -1,22 +1,10 @@\n" \ + "-BEEF SOUP.\n" \ + "+ASPARAGUS SOUP!\n" \ + "\n" \ + "-Take the hind shin of beef, cut off all the flesh off the leg-bone,\n" \ + "-which must be taken away entirely, or the soup will be greasy. Wash the\n" \ + "-meat clean and lay it in a pot, sprinkle over it one small\n" \ + "-table-spoonful of pounded black pepper, and two of salt; three onions\n" \ + "-the size of a hen's egg, cut small, six small carrots scraped and cut\n" \ + "-up, two small turnips pared and cut into dice; pour on three quarts of\n" \ + "-water, cover the pot close, and keep it gently and steadily boiling five\n" \ + "-hours, which will leave about three pints of clear soup; do not let the\n" \ + "-pot boil over, but take off the scum carefully, as it rises. When it has\n" \ + "-boiled four hours, put in a small bundle of thyme and parsley, and a\n" \ + "-pint of celery cut small, or a tea-spoonful of celery seed pounded.\n" \ + "-These latter ingredients would lose their delicate flavour if boiled too\n" \ + "-much. Just before you take it up, brown it in the following manner: put\n" \ + "-a small table-spoonful of nice brown sugar into an iron skillet, set it\n" \ + "-on the fire and stir it till it melts and looks very dark, pour into it\n" \ + "-a ladle full of the soup, a little at a time; stirring it all the while.\n" \ + "-Strain this browning and mix it well with the soup; take out the bundle\n" \ + "-of thyme and parsley, put the nicest pieces of meat in your tureen, and\n" \ + "-pour on the soup and vegetables; put in some toasted bread cut in dice,\n" \ + "-and serve it up.\n" \ + "+Take four large bunches of asparagus, scrape it nicely, cut off one inch\n" \ + "+of the tops, and lay them in water, chop the stalks and put them on the\n" \ + "+fire with a piece of bacon, a large onion cut up, and pepper and salt;\n" \ + "+add two quarts of water, boil them till the stalks are quite soft, then\n" \ + "+pulp them through a sieve, and strain the water to it, which must be put\n" \ + "+back in the pot; put into it a chicken cut up, with the tops of\n" \ + "+asparagus which had been laid by, boil it until these last articles are\n" \ + "+sufficiently done, thicken with flour, butter and milk, and serve it up.\n" \ + "diff --git a/notbeef.txt b/notbeef.txt\n" \ + "new file mode 100644\n" \ + "index 0000000..68f6182\n" \ + "--- /dev/null\n" \ + "+++ b/notbeef.txt\n" \ + "@@ -0,0 +1,22 @@\n" \ + "+BEEF SOUP.\n" \ + "+\n" \ + "+Take the hind shin of beef, cut off all the flesh off the leg-bone,\n" \ + "+which must be taken away entirely, or the soup will be greasy. Wash the\n" \ + "+meat clean and lay it in a pot, sprinkle over it one small\n" \ + "+table-spoonful of pounded black pepper, and two of salt; three onions\n" \ + "+the size of a hen's egg, cut small, six small carrots scraped and cut\n" \ + "+up, two small turnips pared and cut into dice; pour on three quarts of\n" \ + "+water, cover the pot close, and keep it gently and steadily boiling five\n" \ + "+hours, which will leave about three pints of clear soup; do not let the\n" \ + "+pot boil over, but take off the scum carefully, as it rises. When it has\n" \ + "+boiled four hours, put in a small bundle of thyme and parsley, and a\n" \ + "+pint of celery cut small, or a tea-spoonful of celery seed pounded.\n" \ + "+These latter ingredients would lose their delicate flavour if boiled too\n" \ + "+much. Just before you take it up, brown it in the following manner: put\n" \ + "+a small table-spoonful of nice brown sugar into an iron skillet, set it\n" \ + "+on the fire and stir it till it melts and looks very dark, pour into it\n" \ + "+a ladle full of the soup, a little at a time; stirring it all the while.\n" \ + "+Strain this browning and mix it well with the soup; take out the bundle\n" \ + "+of thyme and parsley, put the nicest pieces of meat in your tureen, and\n" \ + "+pour on the soup and vegetables; put in some toasted bread cut in dice,\n" \ + "+and serve it up.\n" + +#define DIFF_RENAME_A_TO_B_TO_C_EXACT \ + "diff --git a/asparagus.txt b/beef.txt\n" \ + "similarity index 100%\n" \ + "rename from asparagus.txt\n" \ + "rename to beef.txt\n" \ + "diff --git a/beef.txt b/notbeef.txt\n" \ + "similarity index 100%\n" \ + "rename from beef.txt\n" \ + "rename to notbeef.txt\n" + +#define DIFF_RENAME_CIRCULAR \ + "diff --git a/asparagus.txt b/beef.txt\n" \ + "similarity index 100%\n" \ + "rename from asparagus.txt\n" \ + "rename to beef.txt\n" \ + "diff --git a/beef.txt b/notbeef.txt\n" \ + "similarity index 100%\n" \ + "rename from beef.txt\n" \ + "rename to asparagus.txt\n" + +#define DIFF_RENAME_2_TO_1 \ + "diff --git a/asparagus.txt b/2.txt\n" \ + "similarity index 100%\n" \ + "rename from asparagus.txt\n" \ + "rename to 2.txt\n" \ + "diff --git a/beef.txt b/2.txt\n" \ + "similarity index 100%\n" \ + "rename from beef.txt\n" \ + "rename to 2.txt\n" + +#define DIFF_RENAME_1_TO_2 \ + "diff --git a/asparagus.txt b/2.txt\n" \ + "similarity index 100%\n" \ + "rename from asparagus.txt\n" \ + "rename to 1.txt\n" \ + "diff --git a/asparagus.txt b/2.txt\n" \ + "similarity index 100%\n" \ + "rename from asparagus.txt\n" \ + "rename to 2.txt\n" + +#define DIFF_TWO_DELTAS_ONE_FILE \ + "diff --git a/beef.txt b/beef.txt\n" \ + "index 68f6182..235069d 100644\n" \ + "--- a/beef.txt\n" \ + "+++ b/beef.txt\n" \ + "@@ -1,4 +1,4 @@\n" \ + "-BEEF SOUP.\n" \ + "+BEEF SOUP!\n" \ + "\n" \ + " Take the hind shin of beef, cut off all the flesh off the leg-bone,\n" \ + " which must be taken away entirely, or the soup will be greasy. Wash the\n" \ + "diff --git a/beef.txt b/beef.txt\n" \ + "index 68f6182..e059eb5 100644\n" \ + "--- a/beef.txt\n" \ + "+++ b/beef.txt\n" \ + "@@ -19,4 +19,4 @@ a ladle full of the soup, a little at a time; stirring it all the while.\n" \ + " Strain this browning and mix it well with the soup; take out the bundle\n" \ + " of thyme and parsley, put the nicest pieces of meat in your tureen, and\n" \ + " pour on the soup and vegetables; put in some toasted bread cut in dice,\n" \ + "-and serve it up.\n" \ + "+and serve it up!\n" + +#define DIFF_TWO_DELTAS_ONE_NEW_FILE \ + "diff --git a/newfile.txt b/newfile.txt\n" \ + "new file mode 100644\n" \ + "index 0000000..6434b13\n" \ + "--- /dev/null\n" \ + "+++ b/newfile.txt\n" \ + "@@ -0,0 +1 @@\n" \ + "+This is a new file.\n" \ + "diff --git a/newfile.txt b/newfile.txt\n" \ + "index 6434b13..08d4c44 100644\n" \ + "--- a/newfile.txt\n" \ + "+++ b/newfile.txt\n" \ + "@@ -1 +1,3 @@\n" \ + " This is a new file.\n" \ + "+\n" \ + "+This is another change to a new file.\n" + +#define DIFF_RENAME_AND_MODIFY_DELTAS \ + "diff --git a/veal.txt b/asdf.txt\n" \ + "similarity index 96%\n" \ + "rename from veal.txt\n" \ + "rename to asdf.txt\n" \ + "index 94d2c01..292cb60 100644\n" \ + "--- a/veal.txt\n" \ + "+++ b/asdf.txt\n" \ + "@@ -15,4 +15,4 @@ will curdle in the soup. For a change you may put a dozen ripe tomatos\n" \ + " in, first taking off their skins, by letting them stand a few minutes in\n" \ + " hot water, when they may be easily peeled. When made in this way you\n" \ + " must thicken it with the flour only. Any part of the veal may be used,\n" \ + "-but the shin or knuckle is the nicest.\n" \ + "+but the shin or knuckle is the nicest!\n" \ + "diff --git a/asdf.txt b/asdf.txt\n" \ + "index 292cb60..61c686b 100644\n" \ + "--- a/asdf.txt\n" \ + "+++ b/asdf.txt\n" \ + "@@ -1,4 +1,4 @@\n" \ + "-VEAL SOUP!\n" \ + "+VEAL SOUP\n" \ + "\n" \ + " Put into a pot three quarts of water, three onions cut small, one\n" \ + " spoonful of black pepper pounded, and two of salt, with two or three\n" + +#define DIFF_RENAME_AFTER_MODIFY \ + "diff --git a/veal.txt b/veal.txt\n" \ + "index 292cb60..61c686b 100644\n" \ + "--- a/veal.txt\n" \ + "+++ b/veal.txt\n" \ + "@@ -1,4 +1,4 @@\n" \ + "-VEAL SOUP!\n" \ + "+VEAL SOUP\n" \ + "\n" \ + " Put into a pot three quarts of water, three onions cut small, one\n" \ + " spoonful of black pepper pounded, and two of salt, with two or three\n" \ + "diff --git a/veal.txt b/other.txt\n" \ + "similarity index 96%\n" \ + "rename from veal.txt\n" \ + "rename to other.txt\n" \ + "index 94d2c01..292cb60 100644\n" \ + "--- a/veal.txt\n" \ + "+++ b/other.txt\n" \ + "@@ -15,4 +15,4 @@ will curdle in the soup. For a change you may put a dozen ripe tomatos\n" \ + " in, first taking off their skins, by letting them stand a few minutes in\n" \ + " hot water, when they may be easily peeled. When made in this way you\n" \ + " must thicken it with the flour only. Any part of the veal may be used,\n" \ + "-but the shin or knuckle is the nicest.\n" \ + "+but the shin or knuckle is the nicest!\n" + +#define DIFF_RENAME_AFTER_MODIFY_TARGET_PATH \ + "diff --git a/beef.txt b/beef.txt\n" \ + "index 292cb60..61c686b 100644\n" \ + "--- a/beef.txt\n" \ + "+++ b/beef.txt\n" \ + "@@ -1,4 +1,4 @@\n" \ + "-VEAL SOUP!\n" \ + "+VEAL SOUP\n" \ + "\n" \ + " Put into a pot three quarts of water, three onions cut small, one\n" \ + " spoonful of black pepper pounded, and two of salt, with two or three\n" \ + "diff --git a/veal.txt b/beef.txt\n" \ + "similarity index 96%\n" \ + "rename from veal.txt\n" \ + "rename to beef.txt\n" \ + "index 94d2c01..292cb60 100644\n" \ + "--- a/veal.txt\n" \ + "+++ b/beef.txt\n" \ + "@@ -15,4 +15,4 @@ will curdle in the soup. For a change you may put a dozen ripe tomatos\n" \ + " in, first taking off their skins, by letting them stand a few minutes in\n" \ + " hot water, when they may be easily peeled. When made in this way you\n" \ + " must thicken it with the flour only. Any part of the veal may be used,\n" \ + "-but the shin or knuckle is the nicest.\n" \ + "+but the shin or knuckle is the nicest!\n" + +#define DIFF_RENAME_AND_MODIFY_SOURCE_PATH \ + "diff --git a/veal.txt b/asdf.txt\n" \ + "similarity index 96%\n" \ + "rename from veal.txt\n" \ + "rename to asdf.txt\n" \ + "index 94d2c01..292cb60 100644\n" \ + "--- a/veal.txt\n" \ + "+++ b/asdf.txt\n" \ + "@@ -15,4 +15,4 @@ will curdle in the soup. For a change you may put a dozen ripe tomatos\n" \ + " in, first taking off their skins, by letting them stand a few minutes in\n" \ + " hot water, when they may be easily peeled. When made in this way you\n" \ + " must thicken it with the flour only. Any part of the veal may be used,\n" \ + "-but the shin or knuckle is the nicest.\n" \ + "+but the shin or knuckle is the nicest!\n" \ + "diff --git a/veal.txt b/veal.txt\n" \ + "index 292cb60..61c686b 100644\n" \ + "--- a/veal.txt\n" \ + "+++ b/veal.txt\n" \ + "@@ -1,4 +1,4 @@\n" \ + "-VEAL SOUP!\n" \ + "+VEAL SOUP\n" \ + "\n" \ + " Put into a pot three quarts of water, three onions cut small, one\n" \ + " spoonful of black pepper pounded, and two of salt, with two or three\n" + +#define DIFF_DELETE_AND_READD_FILE \ + "diff --git a/asparagus.txt b/asparagus.txt\n" \ + "deleted file mode 100644\n" \ + "index f516580..0000000\n" \ + "--- a/asparagus.txt\n" \ + "+++ /dev/null\n" \ + "@@ -1,10 +0,0 @@\n" \ + "-ASPARAGUS SOUP!\n" \ + "-\n" \ + "-Take four large bunches of asparagus, scrape it nicely, cut off one inch\n" \ + "-of the tops, and lay them in water, chop the stalks and put them on the\n" \ + "-fire with a piece of bacon, a large onion cut up, and pepper and salt;\n" \ + "-add two quarts of water, boil them till the stalks are quite soft, then\n" \ + "-pulp them through a sieve, and strain the water to it, which must be put\n" \ + "-back in the pot; put into it a chicken cut up, with the tops of\n" \ + "-asparagus which had been laid by, boil it until these last articles are\n" \ + "-sufficiently done, thicken with flour, butter and milk, and serve it up.\n" \ + "diff --git a/asparagus.txt b/asparagus.txt\n" \ + "new file mode 100644\n" \ + "index 0000000..2dc7f8b\n" \ + "--- /dev/null\n" \ + "+++ b/asparagus.txt\n" \ + "@@ -0,0 +1 @@\n" \ + "+New file.\n" \ + +#define DIFF_REMOVE_FILE_TWICE \ + "diff --git a/asparagus.txt b/asparagus.txt\n" \ + "deleted file mode 100644\n" \ + "index f516580..0000000\n" \ + "--- a/asparagus.txt\n" \ + "+++ /dev/null\n" \ + "@@ -1,10 +0,0 @@\n" \ + "-ASPARAGUS SOUP!\n" \ + "-\n" \ + "-Take four large bunches of asparagus, scrape it nicely, cut off one inch\n" \ + "-of the tops, and lay them in water, chop the stalks and put them on the\n" \ + "-fire with a piece of bacon, a large onion cut up, and pepper and salt;\n" \ + "-add two quarts of water, boil them till the stalks are quite soft, then\n" \ + "-pulp them through a sieve, and strain the water to it, which must be put\n" \ + "-back in the pot; put into it a chicken cut up, with the tops of\n" \ + "-asparagus which had been laid by, boil it until these last articles are\n" \ + "-sufficiently done, thicken with flour, butter and milk, and serve it up.\n" \ + "diff --git a/asparagus.txt b/asparagus.txt\n" \ + "deleted file mode 100644\n" \ + "index f516580..0000000\n" \ + "--- a/asparagus.txt\n" \ + "+++ /dev/null\n" \ + "@@ -1,10 +0,0 @@\n" \ + "-ASPARAGUS SOUP!\n" \ + "-\n" \ + "-Take four large bunches of asparagus, scrape it nicely, cut off one inch\n" \ + "-of the tops, and lay them in water, chop the stalks and put them on the\n" \ + "-fire with a piece of bacon, a large onion cut up, and pepper and salt;\n" \ + "-add two quarts of water, boil them till the stalks are quite soft, then\n" \ + "-pulp them through a sieve, and strain the water to it, which must be put\n" \ + "-back in the pot; put into it a chicken cut up, with the tops of\n" \ + "-asparagus which had been laid by, boil it until these last articles are\n" \ + "-sufficiently done, thicken with flour, butter and milk, and serve it up.\n" + +struct iterator_compare_data { + struct merge_index_entry *expected; + size_t cnt; + size_t idx; +}; + +static int iterator_compare(const git_index_entry *entry, void *_data) +{ + git_oid expected_id; + + struct iterator_compare_data *data = (struct iterator_compare_data *)_data; + + cl_assert_equal_i(GIT_IDXENTRY_STAGE(entry), data->expected[data->idx].stage); + cl_git_pass(git_oid_fromstr(&expected_id, data->expected[data->idx].oid_str)); + cl_assert_equal_oid(&entry->id, &expected_id); + cl_assert_equal_i(entry->mode, data->expected[data->idx].mode); + cl_assert_equal_s(entry->path, data->expected[data->idx].path); + + if (data->idx >= data->cnt) + return -1; + + data->idx++; + + return 0; +} + +static void validate_apply_workdir( + git_repository *repo, + struct merge_index_entry *workdir_entries, + size_t workdir_cnt) +{ + git_index *index; + git_iterator *iterator; + git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT; + struct iterator_compare_data data = { workdir_entries, workdir_cnt }; + + opts.flags |= GIT_ITERATOR_INCLUDE_HASH; + + cl_git_pass(git_repository_index(&index, repo)); + cl_git_pass(git_iterator_for_workdir(&iterator, repo, index, NULL, &opts)); + + cl_git_pass(git_iterator_foreach(iterator, iterator_compare, &data)); + cl_assert_equal_i(data.idx, data.cnt); + + git_iterator_free(iterator); + git_index_free(index); +} + +static void validate_apply_index( + git_repository *repo, + struct merge_index_entry *index_entries, + size_t index_cnt) +{ + git_index *index; + git_iterator *iterator; + struct iterator_compare_data data = { index_entries, index_cnt }; + + cl_git_pass(git_repository_index(&index, repo)); + cl_git_pass(git_iterator_for_index(&iterator, repo, index, NULL)); + + cl_git_pass(git_iterator_foreach(iterator, iterator_compare, &data)); + cl_assert_equal_i(data.idx, data.cnt); + + git_iterator_free(iterator); + git_index_free(index); +} + +static int iterator_eq(const git_index_entry **entry, void *_data) +{ + GIT_UNUSED(_data); + + if (!entry[0] || !entry[1]) + return -1; + + cl_assert_equal_i(GIT_IDXENTRY_STAGE(entry[0]), GIT_IDXENTRY_STAGE(entry[1])); + cl_assert_equal_oid(&entry[0]->id, &entry[1]->id); + cl_assert_equal_i(entry[0]->mode, entry[1]->mode); + cl_assert_equal_s(entry[0]->path, entry[1]->path); + + return 0; +} + +static void validate_index_unchanged(git_repository *repo) +{ + git_tree *head; + git_index *index; + git_iterator *head_iterator, *index_iterator, *iterators[2]; + + cl_git_pass(git_repository_head_tree(&head, repo)); + cl_git_pass(git_repository_index(&index, repo)); + + cl_git_pass(git_iterator_for_tree(&head_iterator, head, NULL)); + cl_git_pass(git_iterator_for_index(&index_iterator, repo, index, NULL)); + + iterators[0] = head_iterator; + iterators[1] = index_iterator; + + cl_git_pass(git_iterator_walk(iterators, 2, iterator_eq, NULL)); + + git_iterator_free(head_iterator); + git_iterator_free(index_iterator); + + git_tree_free(head); + git_index_free(index); +} + +static void validate_workdir_unchanged(git_repository *repo) +{ + git_tree *head; + git_index *index; + git_iterator *head_iterator, *workdir_iterator, *iterators[2]; + git_iterator_options workdir_opts = GIT_ITERATOR_OPTIONS_INIT; + + cl_git_pass(git_repository_head_tree(&head, repo)); + cl_git_pass(git_repository_index(&index, repo)); + + workdir_opts.flags |= GIT_ITERATOR_INCLUDE_HASH; + + cl_git_pass(git_iterator_for_tree(&head_iterator, head, NULL)); + cl_git_pass(git_iterator_for_workdir(&workdir_iterator, repo, index, NULL, &workdir_opts)); + + iterators[0] = head_iterator; + iterators[1] = workdir_iterator; + + cl_git_pass(git_iterator_walk(iterators, 2, iterator_eq, NULL)); + + git_iterator_free(head_iterator); + git_iterator_free(workdir_iterator); + + git_tree_free(head); + git_index_free(index); +} diff --git a/tests/apply/both.c b/tests/apply/both.c new file mode 100644 index 000000000..5091b8cfd --- /dev/null +++ b/tests/apply/both.c @@ -0,0 +1,736 @@ +#include "clar_libgit2.h" +#include "apply_helpers.h" + +static git_repository *repo; + +#define TEST_REPO_PATH "merge-recursive" + +void test_apply_both__initialize(void) +{ + git_oid oid; + git_commit *commit; + + repo = cl_git_sandbox_init(TEST_REPO_PATH); + + git_oid_fromstr(&oid, "539bd011c4822c560c1d17cab095006b7a10f707"); + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL)); + git_commit_free(commit); +} + +void test_apply_both__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_apply_both__generated_diff(void) +{ + git_oid a_oid, b_oid; + git_commit *a_commit, *b_commit; + git_tree *a_tree, *b_tree; + git_diff *diff; + git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT; + + struct merge_index_entry both_expected[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + size_t both_expected_cnt = sizeof(both_expected) / + sizeof(struct merge_index_entry); + + git_oid_fromstr(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707"); + git_oid_fromstr(&b_oid, "7c7bf85e978f1d18c0566f702d2cb7766b9c8d4f"); + cl_git_pass(git_commit_lookup(&a_commit, repo, &a_oid)); + cl_git_pass(git_commit_lookup(&b_commit, repo, &b_oid)); + + cl_git_pass(git_commit_tree(&a_tree, a_commit)); + cl_git_pass(git_commit_tree(&b_tree, b_commit)); + + cl_git_pass(git_diff_tree_to_tree(&diff, repo, a_tree, b_tree, &diff_opts)); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + validate_apply_index(repo, both_expected, both_expected_cnt); + validate_apply_workdir(repo, both_expected, both_expected_cnt); + + git_diff_free(diff); + git_tree_free(a_tree); + git_tree_free(b_tree); + git_commit_free(a_commit); + git_commit_free(b_commit); +} + +void test_apply_both__parsed_diff(void) +{ + git_diff *diff; + + struct merge_index_entry both_expected[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + size_t both_expected_cnt = sizeof(both_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, + DIFF_MODIFY_TWO_FILES, strlen(DIFF_MODIFY_TWO_FILES))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + validate_apply_index(repo, both_expected, both_expected_cnt); + validate_apply_workdir(repo, both_expected, both_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_both__removes_file(void) +{ + git_diff *diff; + + struct merge_index_entry both_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, + }; + size_t both_expected_cnt = sizeof(both_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, DIFF_DELETE_FILE, + strlen(DIFF_DELETE_FILE))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + validate_apply_index(repo, both_expected, both_expected_cnt); + validate_apply_workdir(repo, both_expected, both_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_both__adds_file(void) +{ + git_diff *diff; + + struct merge_index_entry both_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "6370543fcfedb3e6516ec53b06158f3687dc1447", 0, "newfile.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, + }; + size_t both_expected_cnt = sizeof(both_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, + DIFF_ADD_FILE, strlen(DIFF_ADD_FILE))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + validate_apply_index(repo, both_expected, both_expected_cnt); + validate_apply_workdir(repo, both_expected, both_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_both__application_failure_leaves_index_unmodified(void) +{ + git_diff *diff; + git_index *index; + + const char *diff_file = DIFF_MODIFY_TWO_FILES; + + struct merge_index_entry index_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + }; + size_t index_expected_cnt = sizeof(index_expected) / + sizeof(struct merge_index_entry); + + /* mutate the index */ + cl_git_pass(git_repository_index(&index, repo)); + cl_git_pass(git_index_remove(index, "veal.txt", 0)); + cl_git_pass(git_index_write(index)); + git_index_free(index); + + cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_fail_with(GIT_EAPPLYFAIL, git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + validate_apply_index(repo, index_expected, index_expected_cnt); + validate_workdir_unchanged(repo); + + git_diff_free(diff); +} + +void test_apply_both__index_must_match_workdir(void) +{ + git_diff *diff; + git_index *index; + git_index_entry idx_entry; + + const char *diff_file = DIFF_MODIFY_TWO_FILES; + + /* + * Append a line to the end of the file in both the index and the + * working directory. Although the appended line would allow for + * patch application in each, the line appended is different in + * each, so the application should not be allowed. + */ + cl_git_append2file("merge-recursive/asparagus.txt", + "This is a modification.\n"); + + cl_git_pass(git_repository_index(&index, repo)); + + memset(&idx_entry, 0, sizeof(git_index_entry)); + idx_entry.mode = 0100644; + idx_entry.path = "asparagus.txt"; + cl_git_pass(git_oid_fromstr(&idx_entry.id, "06d3fefb8726ab1099acc76e02dfb85e034b2538")); + cl_git_pass(git_index_add(index, &idx_entry)); + + cl_git_pass(git_index_write(index)); + git_index_free(index); + + cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_fail_with(GIT_EAPPLYFAIL, git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + git_diff_free(diff); +} + +void test_apply_both__index_mode_must_match_workdir(void) +{ + git_diff *diff; + + if (!cl_is_chmod_supported()) + clar__skip(); + + /* Set a file in the working directory executable. */ + cl_must_pass(p_chmod("merge-recursive/asparagus.txt", 0755)); + + cl_git_pass(git_diff_from_buffer(&diff, DIFF_MODIFY_TWO_FILES, + strlen(DIFF_MODIFY_TWO_FILES))); + cl_git_fail_with(GIT_EAPPLYFAIL, git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + git_diff_free(diff); +} + +void test_apply_both__application_failure_leaves_workdir_unmodified(void) +{ + git_diff *diff; + git_index *index; + + const char *diff_file = DIFF_MODIFY_TWO_FILES; + + struct merge_index_entry workdir_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "8684724651336001c5dbce74bed6736d2443958d", 0, "veal.txt" }, + }; + size_t workdir_expected_cnt = sizeof(workdir_expected) / + sizeof(struct merge_index_entry); + + /* mutate the workdir */ + cl_git_rewritefile("merge-recursive/veal.txt", + "This is a modification.\n"); + + cl_git_pass(git_repository_index(&index, repo)); + git_index_add_bypath(index, "veal.txt"); + cl_git_pass(git_index_write(index)); + git_index_free(index); + + cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_fail_with(GIT_EAPPLYFAIL, git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_both__keeps_nonconflicting_changes(void) +{ + git_diff *diff; + git_index *index; + git_index_entry idx_entry; + + const char *diff_file = DIFF_MODIFY_TWO_FILES; + + struct merge_index_entry index_expected[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "898d12687fb35be271c27c795a6b32c8b51da79e", 0, "beef.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + size_t index_expected_cnt = sizeof(index_expected) / + sizeof(struct merge_index_entry); + + struct merge_index_entry workdir_expected[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "f75ba05f340c51065cbea2e1fdbfe5fe13144c97", 0, "gravy.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + size_t workdir_expected_cnt = sizeof(workdir_expected) / + sizeof(struct merge_index_entry); + + /* mutate the index */ + cl_git_pass(git_repository_index(&index, repo)); + + memset(&idx_entry, 0, sizeof(git_index_entry)); + idx_entry.mode = 0100644; + idx_entry.path = "beef.txt"; + cl_git_pass(git_oid_fromstr(&idx_entry.id, "898d12687fb35be271c27c795a6b32c8b51da79e")); + git_index_add(index, &idx_entry); + + cl_git_pass(git_index_remove(index, "bouilli.txt", 0)); + cl_git_pass(git_index_write(index)); + git_index_free(index); + + /* and mutate the working directory */ + cl_git_rmfile("merge-recursive/oyster.txt"); + cl_git_rewritefile("merge-recursive/gravy.txt", "Hello, world.\n"); + + cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + validate_apply_index(repo, index_expected, index_expected_cnt); + validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_both__can_apply_nonconflicting_file_changes(void) +{ + git_diff *diff; + git_index *index; + + const char *diff_file = DIFF_MODIFY_TWO_FILES; + + struct merge_index_entry both_expected[] = { + { 0100644, "f8a701c8a1a22c1729ee50faff1111f2d64f96fc", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + size_t both_expected_cnt = sizeof(both_expected) / + sizeof(struct merge_index_entry); + + /* + * Replace the workdir file with a version that is different than + * HEAD but such that the patch still applies cleanly. This item + * has a new line appended. + */ + cl_git_append2file("merge-recursive/asparagus.txt", + "This line is added in the index and the workdir.\n"); + + cl_git_pass(git_repository_index(&index, repo)); + git_index_add_bypath(index, "asparagus.txt"); + cl_git_pass(git_index_write(index)); + git_index_free(index); + + cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + validate_apply_index(repo, both_expected, both_expected_cnt); + validate_apply_workdir(repo, both_expected, both_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_both__honors_crlf_attributes(void) +{ + git_diff *diff; + git_oid oid; + git_commit *commit; + + const char *diff_file = DIFF_MODIFY_TWO_FILES; + + struct merge_index_entry index_expected[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + size_t index_expected_cnt = sizeof(index_expected) / + sizeof(struct merge_index_entry); + + struct merge_index_entry workdir_expected[] = { + { 0100644, "176a458f94e0ea5272ce67c36bf30b6be9caf623", 0, ".gitattributes" }, + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + size_t workdir_expected_cnt = sizeof(workdir_expected) / + sizeof(struct merge_index_entry); + + cl_git_mkfile("merge-recursive/.gitattributes", "* text=auto\n"); + + cl_git_rmfile("merge-recursive/asparagus.txt"); + cl_git_rmfile("merge-recursive/veal.txt"); + + git_oid_fromstr(&oid, "539bd011c4822c560c1d17cab095006b7a10f707"); + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL)); + git_commit_free(commit); + + cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + validate_apply_index(repo, index_expected, index_expected_cnt); + validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_both__rename(void) +{ + git_diff *diff; + + struct merge_index_entry both_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "notbeef.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, + }; + size_t both_expected_cnt = sizeof(both_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_FILE, + strlen(DIFF_RENAME_FILE))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + validate_apply_index(repo, both_expected, both_expected_cnt); + validate_apply_workdir(repo, both_expected, both_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_both__rename_and_modify(void) +{ + git_diff *diff; + + struct merge_index_entry both_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "6fa10147f00fe1fab1d5e835529a9dad53db8552", 0, "notbeef.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, + }; + size_t both_expected_cnt = sizeof(both_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_AND_MODIFY_FILE, + strlen(DIFF_RENAME_AND_MODIFY_FILE))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + validate_apply_index(repo, both_expected, both_expected_cnt); + validate_apply_workdir(repo, both_expected, both_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_both__rename_a_to_b_to_c(void) +{ + git_diff *diff; + + struct merge_index_entry both_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "notbeef.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, + }; + size_t both_expected_cnt = sizeof(both_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_A_TO_B_TO_C, + strlen(DIFF_RENAME_A_TO_B_TO_C))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + validate_apply_index(repo, both_expected, both_expected_cnt); + validate_apply_workdir(repo, both_expected, both_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_both__rename_a_to_b_to_c_exact(void) +{ + git_diff *diff; + + struct merge_index_entry both_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "notbeef.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, + }; + size_t both_expected_cnt = sizeof(both_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_A_TO_B_TO_C_EXACT, + strlen(DIFF_RENAME_A_TO_B_TO_C_EXACT))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + validate_apply_index(repo, both_expected, both_expected_cnt); + validate_apply_workdir(repo, both_expected, both_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_both__rename_circular(void) +{ + git_diff *diff; + + struct merge_index_entry both_expected[] = { + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "asparagus.txt" }, + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" } + }; + size_t both_expected_cnt = sizeof(both_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_CIRCULAR, + strlen(DIFF_RENAME_CIRCULAR))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + validate_apply_index(repo, both_expected, both_expected_cnt); + validate_apply_workdir(repo, both_expected, both_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_both__rename_2_to_1(void) +{ + git_diff *diff; + + struct merge_index_entry both_expected[] = { + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "2.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" } + }; + size_t both_expected_cnt = sizeof(both_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_2_TO_1, + strlen(DIFF_RENAME_2_TO_1))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + validate_apply_index(repo, both_expected, both_expected_cnt); + validate_apply_workdir(repo, both_expected, both_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_both__rename_1_to_2(void) +{ + git_diff *diff; + + struct merge_index_entry both_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "1.txt" }, + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "2.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" } + }; + size_t both_expected_cnt = sizeof(both_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_1_TO_2, + strlen(DIFF_RENAME_1_TO_2))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + validate_apply_index(repo, both_expected, both_expected_cnt); + validate_apply_workdir(repo, both_expected, both_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_both__two_deltas_one_file(void) +{ + git_diff *diff; + + struct merge_index_entry both_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100644, "0a9fd4415635e72573f0f6b5e68084cfe18f5075", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" } + }; + size_t both_expected_cnt = sizeof(both_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, DIFF_TWO_DELTAS_ONE_FILE, + strlen(DIFF_TWO_DELTAS_ONE_FILE))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + validate_apply_index(repo, both_expected, both_expected_cnt); + validate_apply_workdir(repo, both_expected, both_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_both__two_deltas_one_new_file(void) +{ + git_diff *diff; + + struct merge_index_entry both_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "08d4c445cf0078f3d9b604b82f32f4d87e083325", 0, "newfile.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" } + }; + size_t both_expected_cnt = sizeof(both_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, DIFF_TWO_DELTAS_ONE_NEW_FILE, + strlen(DIFF_TWO_DELTAS_ONE_NEW_FILE))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + validate_apply_index(repo, both_expected, both_expected_cnt); + validate_apply_workdir(repo, both_expected, both_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_both__rename_and_modify_deltas(void) +{ + git_diff *diff; + + struct merge_index_entry both_expected[] = { + { 0100644, "61c686bed39684eee8a2757ceb1291004a21333f", 0, "asdf.txt" }, + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + }; + size_t both_expected_cnt = sizeof(both_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_AND_MODIFY_DELTAS, + strlen(DIFF_RENAME_AND_MODIFY_DELTAS))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + validate_apply_index(repo, both_expected, both_expected_cnt); + validate_apply_workdir(repo, both_expected, both_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_both__rename_delta_after_modify_delta(void) +{ + git_diff *diff; + + struct merge_index_entry both_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "292cb60ce5e25c337c5b6e12957bbbfe1be4bf49", 0, "other.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "c8c120f466591bbe3b8867361d5ec3cdd9fda756", 0, "veal.txt" } + }; + size_t both_expected_cnt = sizeof(both_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_AFTER_MODIFY, + strlen(DIFF_RENAME_AFTER_MODIFY))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + validate_apply_index(repo, both_expected, both_expected_cnt); + validate_apply_workdir(repo, both_expected, both_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_both__cant_rename_after_modify_nonexistent_target_path(void) +{ + git_diff *diff; + + cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_AFTER_MODIFY_TARGET_PATH, + strlen(DIFF_RENAME_AFTER_MODIFY_TARGET_PATH))); + cl_git_fail(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + git_diff_free(diff); +} + +void test_apply_both__cant_modify_source_path_after_rename(void) +{ + git_diff *diff; + + cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_AND_MODIFY_SOURCE_PATH, + strlen(DIFF_RENAME_AND_MODIFY_SOURCE_PATH))); + cl_git_fail(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + git_diff_free(diff); +} + +void test_apply_both__readd_deleted_file(void) +{ + git_diff *diff; + + struct merge_index_entry both_expected[] = { + { 0100644, "2dc7f8b24ba27f3888368bd180df03ff4c6c6fab", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" } + }; + size_t both_expected_cnt = sizeof(both_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, DIFF_DELETE_AND_READD_FILE, + strlen(DIFF_DELETE_AND_READD_FILE))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + validate_apply_index(repo, both_expected, both_expected_cnt); + validate_apply_workdir(repo, both_expected, both_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_both__cant_remove_file_twice(void) +{ + git_diff *diff; + + cl_git_pass(git_diff_from_buffer(&diff, DIFF_REMOVE_FILE_TWICE, + strlen(DIFF_REMOVE_FILE_TWICE))); + cl_git_fail(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL)); + + git_diff_free(diff); +} diff --git a/tests/apply/callbacks.c b/tests/apply/callbacks.c new file mode 100644 index 000000000..1b759dc9b --- /dev/null +++ b/tests/apply/callbacks.c @@ -0,0 +1,128 @@ +#include "clar_libgit2.h" +#include "apply_helpers.h" + +static git_repository *repo; + +#define TEST_REPO_PATH "merge-recursive" + +void test_apply_callbacks__initialize(void) +{ + git_oid oid; + git_commit *commit; + + repo = cl_git_sandbox_init(TEST_REPO_PATH); + + git_oid_fromstr(&oid, "539bd011c4822c560c1d17cab095006b7a10f707"); + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL)); + git_commit_free(commit); +} + +void test_apply_callbacks__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +static int delta_abort_cb(const git_diff_delta *delta, void *payload) +{ + GIT_UNUSED(payload); + + if (!strcmp(delta->old_file.path, "veal.txt")) + return -99; + + return 0; +} + +void test_apply_callbacks__delta_aborts(void) +{ + git_diff *diff; + git_apply_options opts = GIT_APPLY_OPTIONS_INIT; + + opts.delta_cb = delta_abort_cb; + + cl_git_pass(git_diff_from_buffer(&diff, + DIFF_MODIFY_TWO_FILES, strlen(DIFF_MODIFY_TWO_FILES))); + cl_git_fail_with(-99, + git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, &opts)); + + validate_index_unchanged(repo); + validate_workdir_unchanged(repo); + + git_diff_free(diff); +} + +static int delta_skip_cb(const git_diff_delta *delta, void *payload) +{ + GIT_UNUSED(payload); + + if (!strcmp(delta->old_file.path, "asparagus.txt")) + return 1; + + return 0; +} + +void test_apply_callbacks__delta_can_skip(void) +{ + git_diff *diff; + git_apply_options opts = GIT_APPLY_OPTIONS_INIT; + + struct merge_index_entry workdir_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + size_t workdir_expected_cnt = sizeof(workdir_expected) / + sizeof(struct merge_index_entry); + + opts.delta_cb = delta_skip_cb; + + cl_git_pass(git_diff_from_buffer(&diff, + DIFF_MODIFY_TWO_FILES, strlen(DIFF_MODIFY_TWO_FILES))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, &opts)); + + validate_index_unchanged(repo); + validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); + + git_diff_free(diff); +} + +static int hunk_skip_odds_cb(const git_diff_hunk *hunk, void *payload) +{ + int *count = (int *)payload; + GIT_UNUSED(hunk); + + return ((*count)++ % 2 == 1); +} + +void test_apply_callbacks__hunk_can_skip(void) +{ + git_diff *diff; + git_apply_options opts = GIT_APPLY_OPTIONS_INIT; + int count = 0; + + struct merge_index_entry workdir_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "06f751b6ba4f017ddbf4248015768300268e092a", 0, "veal.txt" }, + }; + size_t workdir_expected_cnt = sizeof(workdir_expected) / + sizeof(struct merge_index_entry); + + opts.hunk_cb = hunk_skip_odds_cb; + opts.payload = &count; + + cl_git_pass(git_diff_from_buffer(&diff, + DIFF_MANY_CHANGES_ONE, strlen(DIFF_MANY_CHANGES_ONE))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, &opts)); + + validate_index_unchanged(repo); + validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); + + git_diff_free(diff); +} diff --git a/tests/apply/fromdiff.c b/tests/apply/fromdiff.c index 611060988..8a6d8fa0a 100644 --- a/tests/apply/fromdiff.c +++ b/tests/apply/fromdiff.c @@ -49,7 +49,7 @@ static int apply_gitbuf( cl_assert_equal_s(patch_expected, patchbuf.ptr); } - error = git_apply__patch(&result, &filename, &mode, old ? old->ptr : NULL, old ? old->size : 0, patch); + error = git_apply__patch(&result, &filename, &mode, old ? old->ptr : NULL, old ? old->size : 0, patch, NULL); if (error == 0 && new == NULL) { cl_assert_equal_i(0, result.size); @@ -150,6 +150,52 @@ void test_apply_fromdiff__prepend_nocontext(void) PATCH_ORIGINAL_TO_PREPEND_NOCONTEXT, &diff_opts)); } +void test_apply_fromdiff__prepend_and_change(void) +{ + cl_git_pass(apply_buf( + FILE_ORIGINAL, "file.txt", + FILE_PREPEND_AND_CHANGE, "file.txt", + PATCH_ORIGINAL_TO_PREPEND_AND_CHANGE, NULL)); +} + +void test_apply_fromdiff__prepend_and_change_nocontext(void) +{ + git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT; + diff_opts.context_lines = 0; + + cl_git_pass(apply_buf( + FILE_ORIGINAL, "file.txt", + FILE_PREPEND_AND_CHANGE, "file.txt", + PATCH_ORIGINAL_TO_PREPEND_AND_CHANGE_NOCONTEXT, &diff_opts)); +} + +void test_apply_fromdiff__delete_and_change(void) +{ + cl_git_pass(apply_buf( + FILE_ORIGINAL, "file.txt", + FILE_DELETE_AND_CHANGE, "file.txt", + PATCH_ORIGINAL_TO_DELETE_AND_CHANGE, NULL)); +} + +void test_apply_fromdiff__delete_and_change_nocontext(void) +{ + git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT; + diff_opts.context_lines = 0; + + cl_git_pass(apply_buf( + FILE_ORIGINAL, "file.txt", + FILE_DELETE_AND_CHANGE, "file.txt", + PATCH_ORIGINAL_TO_DELETE_AND_CHANGE_NOCONTEXT, &diff_opts)); +} + +void test_apply_fromdiff__delete_firstline(void) +{ + cl_git_pass(apply_buf( + FILE_ORIGINAL, "file.txt", + FILE_DELETE_FIRSTLINE, "file.txt", + PATCH_ORIGINAL_TO_DELETE_FIRSTLINE, NULL)); +} + void test_apply_fromdiff__append(void) { cl_git_pass(apply_buf( diff --git a/tests/apply/fromfile.c b/tests/apply/fromfile.c index 0ace639fc..6d4379b1b 100644 --- a/tests/apply/fromfile.c +++ b/tests/apply/fromfile.c @@ -39,7 +39,7 @@ static int apply_patchfile( cl_git_pass(git_patch_from_buffer(&patch, patchfile, strlen(patchfile), NULL)); - error = git_apply__patch(&result, &filename, &mode, old, old_len, patch); + error = git_apply__patch(&result, &filename, &mode, old, old_len, patch, NULL); if (error == 0) { cl_assert_equal_i(new_len, result.size); diff --git a/tests/apply/index.c b/tests/apply/index.c new file mode 100644 index 000000000..9c9094cce --- /dev/null +++ b/tests/apply/index.c @@ -0,0 +1,321 @@ +#include "clar_libgit2.h" +#include "apply_helpers.h" + +static git_repository *repo; + +#define TEST_REPO_PATH "merge-recursive" + +void test_apply_index__initialize(void) +{ + git_oid oid; + git_commit *commit; + + repo = cl_git_sandbox_init(TEST_REPO_PATH); + + git_oid_fromstr(&oid, "539bd011c4822c560c1d17cab095006b7a10f707"); + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL)); + git_commit_free(commit); +} + +void test_apply_index__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_apply_index__generate_diff(void) +{ + git_oid a_oid, b_oid; + git_commit *a_commit, *b_commit; + git_tree *a_tree, *b_tree; + git_diff *diff; + git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT; + + struct merge_index_entry index_expected[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + size_t index_expected_cnt = sizeof(index_expected) / + sizeof(struct merge_index_entry); + + git_oid_fromstr(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707"); + git_oid_fromstr(&b_oid, "7c7bf85e978f1d18c0566f702d2cb7766b9c8d4f"); + cl_git_pass(git_commit_lookup(&a_commit, repo, &a_oid)); + cl_git_pass(git_commit_lookup(&b_commit, repo, &b_oid)); + + cl_git_pass(git_commit_tree(&a_tree, a_commit)); + cl_git_pass(git_commit_tree(&b_tree, b_commit)); + + cl_git_pass(git_diff_tree_to_tree(&diff, repo, a_tree, b_tree, &diff_opts)); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); + + validate_apply_index(repo, index_expected, index_expected_cnt); + validate_workdir_unchanged(repo); + + git_diff_free(diff); + git_tree_free(a_tree); + git_tree_free(b_tree); + git_commit_free(a_commit); + git_commit_free(b_commit); +} + +void test_apply_index__parsed_diff(void) +{ + git_diff *diff; + + struct merge_index_entry index_expected[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + size_t index_expected_cnt = sizeof(index_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, + DIFF_MODIFY_TWO_FILES, strlen(DIFF_MODIFY_TWO_FILES))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); + + validate_apply_index(repo, index_expected, index_expected_cnt); + validate_workdir_unchanged(repo); + + git_diff_free(diff); +} + +void test_apply_index__removes_file(void) +{ + git_diff *diff; + + struct merge_index_entry index_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, + }; + size_t index_expected_cnt = sizeof(index_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, DIFF_DELETE_FILE, + strlen(DIFF_DELETE_FILE))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); + + validate_apply_index(repo, index_expected, index_expected_cnt); + validate_workdir_unchanged(repo); + + git_diff_free(diff); +} + +void test_apply_index__adds_file(void) +{ + git_diff *diff; + + struct merge_index_entry index_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "6370543fcfedb3e6516ec53b06158f3687dc1447", 0, "newfile.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, + }; + size_t index_expected_cnt = sizeof(index_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, + DIFF_ADD_FILE, strlen(DIFF_ADD_FILE))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); + + validate_apply_index(repo, index_expected, index_expected_cnt); + validate_workdir_unchanged(repo); + + git_diff_free(diff); +} + +void test_apply_index__modified_workdir_with_unmodified_index_is_ok(void) +{ + git_diff *diff; + + const char *diff_file = DIFF_MODIFY_TWO_FILES; + + struct merge_index_entry index_expected[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + size_t index_expected_cnt = sizeof(index_expected) / + sizeof(struct merge_index_entry); + + struct merge_index_entry workdir_expected[] = { + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "f75ba05f340c51065cbea2e1fdbfe5fe13144c97", 0, "veal.txt" } + }; + size_t workdir_expected_cnt = sizeof(workdir_expected) / + sizeof(struct merge_index_entry); + + /* mutate the workdir and leave the index matching HEAD */ + cl_git_rmfile("merge-recursive/asparagus.txt"); + cl_git_rewritefile("merge-recursive/veal.txt", "Hello, world.\n"); + + cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); + + validate_apply_index(repo, index_expected, index_expected_cnt); + validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_index__application_failure_leaves_index_unmodified(void) +{ + git_diff *diff; + git_index *index; + + const char *diff_file = DIFF_MODIFY_TWO_FILES; + + struct merge_index_entry index_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + }; + size_t index_expected_cnt = sizeof(index_expected) / + sizeof(struct merge_index_entry); + + /* mutate the index */ + cl_git_pass(git_repository_index(&index, repo)); + cl_git_pass(git_index_remove(index, "veal.txt", 0)); + cl_git_pass(git_index_write(index)); + git_index_free(index); + + cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_fail_with(GIT_EAPPLYFAIL, git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); + + validate_apply_index(repo, index_expected, index_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_index__keeps_nonconflicting_changes(void) +{ + git_diff *diff; + git_index *index; + git_index_entry idx_entry; + + const char *diff_file = DIFF_MODIFY_TWO_FILES; + + struct merge_index_entry index_expected[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "898d12687fb35be271c27c795a6b32c8b51da79e", 0, "beef.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + size_t index_expected_cnt = sizeof(index_expected) / + sizeof(struct merge_index_entry); + + /* mutate the index */ + cl_git_pass(git_repository_index(&index, repo)); + + memset(&idx_entry, 0, sizeof(git_index_entry)); + idx_entry.mode = 0100644; + idx_entry.path = "beef.txt"; + cl_git_pass(git_oid_fromstr(&idx_entry.id, "898d12687fb35be271c27c795a6b32c8b51da79e")); + cl_git_pass(git_index_add(index, &idx_entry)); + + cl_git_pass(git_index_remove(index, "bouilli.txt", 0)); + cl_git_pass(git_index_write(index)); + git_index_free(index); + + cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); + + validate_apply_index(repo, index_expected, index_expected_cnt); + validate_workdir_unchanged(repo); + + git_diff_free(diff); +} + +void test_apply_index__can_apply_nonconflicting_file_changes(void) +{ + git_diff *diff; + git_index *index; + git_index_entry idx_entry; + + const char *diff_file = DIFF_MODIFY_TWO_FILES; + + struct merge_index_entry index_expected[] = { + { 0100644, "4f2d1645dee99ced096877911de540c65ade2ef8", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + size_t index_expected_cnt = sizeof(index_expected) / + sizeof(struct merge_index_entry); + + /* + * Replace the index entry with a version that is different than + * HEAD but such that the patch still applies cleanly. This item + * has a new line appended. + */ + + cl_git_pass(git_repository_index(&index, repo)); + + memset(&idx_entry, 0, sizeof(git_index_entry)); + idx_entry.mode = 0100644; + idx_entry.path = "asparagus.txt"; + cl_git_pass(git_oid_fromstr(&idx_entry.id, "06d3fefb8726ab1099acc76e02dfb85e034b2538")); + cl_git_pass(git_index_add(index, &idx_entry)); + + cl_git_pass(git_index_write(index)); + git_index_free(index); + + cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); + + validate_apply_index(repo, index_expected, index_expected_cnt); + validate_workdir_unchanged(repo); + + git_diff_free(diff); +} + +void test_apply_index__change_mode(void) +{ + git_diff *diff; + + const char *diff_file = DIFF_EXECUTABLE_FILE; + + struct merge_index_entry index_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100755, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, + }; + size_t index_expected_cnt = sizeof(index_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, NULL)); + + validate_apply_index(repo, index_expected, index_expected_cnt); + validate_workdir_unchanged(repo); + + git_diff_free(diff); +} diff --git a/tests/apply/partial.c b/tests/apply/partial.c new file mode 100644 index 000000000..243dccf0f --- /dev/null +++ b/tests/apply/partial.c @@ -0,0 +1,232 @@ +#include "clar_libgit2.h" +#include "git2/sys/repository.h" + +#include "apply.h" +#include "repository.h" +#include "buf_text.h" + +#include "../patch/patch_common.h" + +static git_repository *repo = NULL; + +void test_apply_partial__initialize(void) +{ + repo = cl_git_sandbox_init("renames"); +} + +void test_apply_partial__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +static int skip_addition( + const git_diff_hunk *hunk, + void *payload) +{ + GIT_UNUSED(payload); + + return (hunk->new_lines > hunk->old_lines) ? 1 : 0; +} + +static int skip_deletion( + const git_diff_hunk *hunk, + void *payload) +{ + GIT_UNUSED(payload); + + return (hunk->new_lines < hunk->old_lines) ? 1 : 0; +} + +static int skip_change( + const git_diff_hunk *hunk, + void *payload) +{ + GIT_UNUSED(payload); + + return (hunk->new_lines == hunk->old_lines) ? 1 : 0; +} + +static int abort_addition( + const git_diff_hunk *hunk, + void *payload) +{ + GIT_UNUSED(payload); + + return (hunk->new_lines > hunk->old_lines) ? GIT_EUSER : 0; +} + +static int abort_deletion( + const git_diff_hunk *hunk, + void *payload) +{ + GIT_UNUSED(payload); + + return (hunk->new_lines < hunk->old_lines) ? GIT_EUSER : 0; +} + +static int abort_change( + const git_diff_hunk *hunk, + void *payload) +{ + GIT_UNUSED(payload); + + return (hunk->new_lines == hunk->old_lines) ? GIT_EUSER : 0; +} + +static int apply_buf( + const char *old, + const char *oldname, + const char *new, + const char *newname, + const char *expected, + const git_diff_options *diff_opts, + git_apply_hunk_cb hunk_cb, + void *payload) +{ + git_patch *patch; + git_buf result = GIT_BUF_INIT; + git_buf patchbuf = GIT_BUF_INIT; + git_apply_options opts = GIT_APPLY_OPTIONS_INIT; + char *filename; + unsigned int mode; + int error; + size_t oldsize = strlen(old); + size_t newsize = strlen(new); + + opts.hunk_cb = hunk_cb; + opts.payload = payload; + + cl_git_pass(git_patch_from_buffers(&patch, old, oldsize, oldname, new, newsize, newname, diff_opts)); + if ((error = git_apply__patch(&result, &filename, &mode, old, oldsize, patch, &opts)) == 0) { + cl_assert_equal_s(expected, result.ptr); + cl_assert_equal_s(newname, filename); + cl_assert_equal_i(0100644, mode); + } + + git__free(filename); + git_buf_free(&result); + git_buf_free(&patchbuf); + git_patch_free(patch); + + return error; +} + +void test_apply_partial__prepend_and_change_skip_addition(void) +{ + cl_git_pass(apply_buf( + FILE_ORIGINAL, "file.txt", + FILE_PREPEND_AND_CHANGE, "file.txt", + FILE_ORIGINAL, NULL, skip_addition, NULL)); +} + +void test_apply_partial__prepend_and_change_nocontext_skip_addition(void) +{ + git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT; + diff_opts.context_lines = 0; + + cl_git_pass(apply_buf( + FILE_ORIGINAL, "file.txt", + FILE_PREPEND_AND_CHANGE, "file.txt", + FILE_CHANGE_MIDDLE, &diff_opts, skip_addition, NULL)); +} + +void test_apply_partial__prepend_and_change_nocontext_abort_addition(void) +{ + git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT; + diff_opts.context_lines = 0; + + cl_git_fail(apply_buf( + FILE_ORIGINAL, "file.txt", + FILE_PREPEND_AND_CHANGE, "file.txt", + FILE_ORIGINAL, &diff_opts, abort_addition, NULL)); +} + +void test_apply_partial__prepend_and_change_skip_change(void) +{ + cl_git_pass(apply_buf( + FILE_ORIGINAL, "file.txt", + FILE_PREPEND_AND_CHANGE, "file.txt", + FILE_PREPEND_AND_CHANGE, NULL, skip_change, NULL)); +} + +void test_apply_partial__prepend_and_change_nocontext_skip_change(void) +{ + git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT; + diff_opts.context_lines = 0; + + cl_git_pass(apply_buf( + FILE_ORIGINAL, "file.txt", + FILE_PREPEND_AND_CHANGE, "file.txt", + FILE_PREPEND, &diff_opts, skip_change, NULL)); +} + +void test_apply_partial__prepend_and_change_nocontext_abort_change(void) +{ + git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT; + diff_opts.context_lines = 0; + + cl_git_fail(apply_buf( + FILE_ORIGINAL, "file.txt", + FILE_PREPEND_AND_CHANGE, "file.txt", + FILE_PREPEND, &diff_opts, abort_change, NULL)); +} + +void test_apply_partial__delete_and_change_skip_deletion(void) +{ + cl_git_pass(apply_buf( + FILE_ORIGINAL, "file.txt", + FILE_DELETE_AND_CHANGE, "file.txt", + FILE_ORIGINAL, NULL, skip_deletion, NULL)); +} + +void test_apply_partial__delete_and_change_nocontext_skip_deletion(void) +{ + git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT; + diff_opts.context_lines = 0; + + cl_git_pass(apply_buf( + FILE_ORIGINAL, "file.txt", + FILE_DELETE_AND_CHANGE, "file.txt", + FILE_CHANGE_MIDDLE, &diff_opts, skip_deletion, NULL)); +} + +void test_apply_partial__delete_and_change_nocontext_abort_deletion(void) +{ + git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT; + diff_opts.context_lines = 0; + + cl_git_fail(apply_buf( + FILE_ORIGINAL, "file.txt", + FILE_DELETE_AND_CHANGE, "file.txt", + FILE_ORIGINAL, &diff_opts, abort_deletion, NULL)); +} + +void test_apply_partial__delete_and_change_skip_change(void) +{ + cl_git_pass(apply_buf( + FILE_ORIGINAL, "file.txt", + FILE_DELETE_AND_CHANGE, "file.txt", + FILE_DELETE_AND_CHANGE, NULL, skip_change, NULL)); +} + +void test_apply_partial__delete_and_change_nocontext_skip_change(void) +{ + git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT; + diff_opts.context_lines = 0; + + cl_git_pass(apply_buf( + FILE_ORIGINAL, "file.txt", + FILE_DELETE_AND_CHANGE, "file.txt", + FILE_DELETE_FIRSTLINE, &diff_opts, skip_change, NULL)); +} + +void test_apply_partial__delete_and_change_nocontext_abort_change(void) +{ + git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT; + diff_opts.context_lines = 0; + + cl_git_fail(apply_buf( + FILE_ORIGINAL, "file.txt", + FILE_DELETE_AND_CHANGE, "file.txt", + FILE_DELETE_FIRSTLINE, &diff_opts, abort_change, NULL)); +} diff --git a/tests/apply/tree.c b/tests/apply/tree.c new file mode 100644 index 000000000..f35b13ce0 --- /dev/null +++ b/tests/apply/tree.c @@ -0,0 +1,58 @@ +#include "clar_libgit2.h" +#include "../merge/merge_helpers.h" + +static git_repository *repo; + +#define TEST_REPO_PATH "merge-recursive" + + +void test_apply_tree__initialize(void) +{ + repo = cl_git_sandbox_init(TEST_REPO_PATH); +} + +void test_apply_tree__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_apply_tree__one(void) +{ + git_oid a_oid, b_oid; + git_commit *a_commit, *b_commit; + git_tree *a_tree, *b_tree; + git_diff *diff; + git_index *index = NULL; + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + + struct merge_index_entry expected[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + + git_oid_fromstr(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707"); + git_oid_fromstr(&b_oid, "7c7bf85e978f1d18c0566f702d2cb7766b9c8d4f"); + + cl_git_pass(git_commit_lookup(&a_commit, repo, &a_oid)); + cl_git_pass(git_commit_lookup(&b_commit, repo, &b_oid)); + + cl_git_pass(git_commit_tree(&a_tree, a_commit)); + cl_git_pass(git_commit_tree(&b_tree, b_commit)); + + cl_git_pass(git_diff_tree_to_tree(&diff, repo, a_tree, b_tree, &opts)); + + cl_git_pass(git_apply_to_tree(&index, repo, a_tree, diff, NULL)); + merge_test_index(index, expected, 6); + + git_index_free(index); + git_diff_free(diff); + git_tree_free(a_tree); + git_tree_free(b_tree); + git_commit_free(a_commit); + git_commit_free(b_commit); +} + diff --git a/tests/apply/workdir.c b/tests/apply/workdir.c new file mode 100644 index 000000000..1a8292508 --- /dev/null +++ b/tests/apply/workdir.c @@ -0,0 +1,358 @@ +#include "clar_libgit2.h" +#include "apply_helpers.h" + +static git_repository *repo; + +#define TEST_REPO_PATH "merge-recursive" + +void test_apply_workdir__initialize(void) +{ + git_oid oid; + git_commit *commit; + + repo = cl_git_sandbox_init(TEST_REPO_PATH); + + git_oid_fromstr(&oid, "539bd011c4822c560c1d17cab095006b7a10f707"); + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL)); + git_commit_free(commit); +} + +void test_apply_workdir__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_apply_workdir__generated_diff(void) +{ + git_oid a_oid, b_oid; + git_commit *a_commit, *b_commit; + git_tree *a_tree, *b_tree; + git_diff *diff; + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + + struct merge_index_entry workdir_expected[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + size_t workdir_expected_cnt = sizeof(workdir_expected) / + sizeof(struct merge_index_entry); + + git_oid_fromstr(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707"); + git_oid_fromstr(&b_oid, "7c7bf85e978f1d18c0566f702d2cb7766b9c8d4f"); cl_git_pass(git_commit_lookup(&a_commit, repo, &a_oid)); + cl_git_pass(git_commit_lookup(&b_commit, repo, &b_oid)); + + cl_git_pass(git_commit_tree(&a_tree, a_commit)); + cl_git_pass(git_commit_tree(&b_tree, b_commit)); + + cl_git_pass(git_diff_tree_to_tree(&diff, repo, a_tree, b_tree, &opts)); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); + + validate_index_unchanged(repo); + validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); + + git_diff_free(diff); + git_tree_free(a_tree); + git_tree_free(b_tree); + git_commit_free(a_commit); + git_commit_free(b_commit); +} + +void test_apply_workdir__parsed_diff(void) +{ + git_diff *diff; + + struct merge_index_entry workdir_expected[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + size_t workdir_expected_cnt = sizeof(workdir_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, + DIFF_MODIFY_TWO_FILES, strlen(DIFF_MODIFY_TWO_FILES))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); + + validate_index_unchanged(repo); + validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_workdir__removes_file(void) +{ + git_diff *diff; + + struct merge_index_entry workdir_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, + }; + size_t workdir_expected_cnt = sizeof(workdir_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, DIFF_DELETE_FILE, + strlen(DIFF_DELETE_FILE))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); + + validate_index_unchanged(repo); + validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_workdir__adds_file(void) +{ + git_diff *diff; + + struct merge_index_entry workdir_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "6370543fcfedb3e6516ec53b06158f3687dc1447", 0, "newfile.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, + }; + size_t workdir_expected_cnt = sizeof(workdir_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, + DIFF_ADD_FILE, strlen(DIFF_ADD_FILE))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); + + validate_index_unchanged(repo); + validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_workdir__modified_index_with_unmodified_workdir_is_ok(void) +{ + git_index *index; + git_index_entry idx_entry = {{0}}; + git_diff *diff; + + const char *diff_file = DIFF_MODIFY_TWO_FILES; + + struct merge_index_entry index_expected[] = { + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "veal.txt" } + }; + size_t index_expected_cnt = sizeof(index_expected) / + sizeof(struct merge_index_entry); + + struct merge_index_entry workdir_expected[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + size_t workdir_expected_cnt = sizeof(workdir_expected) / + sizeof(struct merge_index_entry); + + /* mutate the index and leave the workdir matching HEAD */ + git_repository_index(&index, repo); + + idx_entry.mode = 0100644; + idx_entry.path = "veal.txt"; + cl_git_pass(git_oid_fromstr(&idx_entry.id, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d")); + + cl_git_pass(git_index_add(index, &idx_entry)); + cl_git_pass(git_index_remove(index, "asparagus.txt", 0)); + cl_git_pass(git_index_write(index)); + + cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); + + validate_apply_index(repo, index_expected, index_expected_cnt); + validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); + + git_index_free(index); + git_diff_free(diff); +} + +void test_apply_workdir__application_failure_leaves_workdir_unmodified(void) +{ + git_diff *diff; + + const char *diff_file = DIFF_MODIFY_TWO_FILES; + + struct merge_index_entry workdir_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "8684724651336001c5dbce74bed6736d2443958d", 0, "veal.txt" }, + }; + size_t workdir_expected_cnt = sizeof(workdir_expected) / + sizeof(struct merge_index_entry); + + /* mutate the workdir */ + cl_git_rewritefile("merge-recursive/veal.txt", + "This is a modification.\n"); + + cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_fail_with(GIT_EAPPLYFAIL, git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); + + validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_workdir__keeps_nonconflicting_changes(void) +{ + git_diff *diff; + + struct merge_index_entry workdir_expected[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "f75ba05f340c51065cbea2e1fdbfe5fe13144c97", 0, "gravy.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + size_t workdir_expected_cnt = sizeof(workdir_expected) / + sizeof(struct merge_index_entry); + + cl_git_rmfile("merge-recursive/oyster.txt"); + cl_git_rewritefile("merge-recursive/gravy.txt", "Hello, world.\n"); + + cl_git_pass(git_diff_from_buffer(&diff, + DIFF_MODIFY_TWO_FILES, strlen(DIFF_MODIFY_TWO_FILES))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); + + validate_index_unchanged(repo); + validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_workdir__can_apply_nonconflicting_file_changes(void) +{ + git_diff *diff; + + const char *diff_file = DIFF_MODIFY_TWO_FILES; + + struct merge_index_entry workdir_expected[] = { + { 0100644, "5db1a0fef164cb66cc0c00d35cc5af979ddc1a64", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, + }; + size_t workdir_expected_cnt = sizeof(workdir_expected) / + sizeof(struct merge_index_entry); + + /* + * Replace the workdir file with a version that is different than + * HEAD but such that the patch still applies cleanly. This item + * has a new line appended. + */ + cl_git_append2file("merge-recursive/asparagus.txt", + "This line is added in the workdir.\n"); + + cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); + + validate_index_unchanged(repo); + validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_workdir__change_mode(void) +{ +#ifndef GIT_WIN32 + git_diff *diff; + + const char *diff_file = DIFF_EXECUTABLE_FILE; + + struct merge_index_entry workdir_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100755, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }, + }; + size_t workdir_expected_cnt = sizeof(workdir_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, NULL)); + + validate_index_unchanged(repo); + validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); + + git_diff_free(diff); +#endif +} + +void test_apply_workdir__apply_many_changes_one(void) +{ + git_diff *diff; + git_apply_options opts = GIT_APPLY_OPTIONS_INIT; + + struct merge_index_entry workdir_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "c9d7d5d58088bc91f6e06f17ca3a205091568d3a", 0, "veal.txt" }, + }; + size_t workdir_expected_cnt = sizeof(workdir_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, + DIFF_MANY_CHANGES_ONE, strlen(DIFF_MANY_CHANGES_ONE))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, &opts)); + + validate_index_unchanged(repo); + validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); + + git_diff_free(diff); +} + +void test_apply_workdir__apply_many_changes_two(void) +{ + git_diff *diff; + git_apply_options opts = GIT_APPLY_OPTIONS_INIT; + + struct merge_index_entry workdir_expected[] = { + { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, + { 0100644, "6b943d65af6d8db74d747284fa4ca7d716ad5bbb", 0, "veal.txt" }, + }; + size_t workdir_expected_cnt = sizeof(workdir_expected) / + sizeof(struct merge_index_entry); + + cl_git_pass(git_diff_from_buffer(&diff, + DIFF_MANY_CHANGES_TWO, strlen(DIFF_MANY_CHANGES_TWO))); + cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_WORKDIR, &opts)); + + validate_index_unchanged(repo); + validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt); + + git_diff_free(diff); +} diff --git a/tests/iterator/workdir.c b/tests/iterator/workdir.c index a16acd722..889fcd6c0 100644 --- a/tests/iterator/workdir.c +++ b/tests/iterator/workdir.c @@ -3,6 +3,7 @@ #include "repository.h" #include "fileops.h" #include "../submodule/submodule_helpers.h" +#include "../merge/merge_helpers.h" #include "iterator_helpers.h" #include <stdarg.h> @@ -1474,3 +1475,48 @@ void test_iterator_workdir__pathlist_with_directory_include_trees(void) git_vector_free(&filelist); } +void test_iterator_workdir__hash_when_requested(void) +{ + git_iterator *iter; + const git_index_entry *entry; + git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT; + git_oid expected_id = {{0}}; + size_t i; + + struct merge_index_entry expected[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "7c7e08f9559d9e1551b91e1cf68f1d0066109add", 0, "oyster.txt" }, + { 0100644, "898d12687fb35be271c27c795a6b32c8b51da79e", 0, "veal.txt" }, + }; + + g_repo = cl_git_sandbox_init("merge-recursive"); + + /* do the iteration normally, ensure there are no hashes */ + cl_git_pass(git_iterator_for_workdir(&iter, g_repo, NULL, NULL, &iter_opts)); + + for (i = 0; i < sizeof(expected) / sizeof(struct merge_index_entry); i++) { + cl_git_pass(git_iterator_advance(&entry, iter)); + + cl_assert_equal_oid(&expected_id, &entry->id); + cl_assert_equal_s(expected[i].path, entry->path); + } + cl_assert_equal_i(GIT_ITEROVER, git_iterator_advance(&entry, iter)); + git_iterator_free(iter); + + /* do the iteration requesting hashes */ + iter_opts.flags |= GIT_ITERATOR_INCLUDE_HASH; + cl_git_pass(git_iterator_for_workdir(&iter, g_repo, NULL, NULL, &iter_opts)); + + for (i = 0; i < sizeof(expected) / sizeof(struct merge_index_entry); i++) { + cl_git_pass(git_iterator_advance(&entry, iter)); + + cl_git_pass(git_oid_fromstr(&expected_id, expected[i].oid_str)); + cl_assert_equal_oid(&expected_id, &entry->id); + cl_assert_equal_s(expected[i].path, entry->path); + } + cl_assert_equal_i(GIT_ITEROVER, git_iterator_advance(&entry, iter)); + git_iterator_free(iter); +} diff --git a/tests/patch/patch_common.h b/tests/patch/patch_common.h index e838e6089..3f2668ddc 100644 --- a/tests/patch/patch_common.h +++ b/tests/patch/patch_common.h @@ -220,6 +220,112 @@ "@@ -0,0 +1 @@\n" \ "+insert at front\n" +/* An insertion at the beginning of the file and change in the middle */ + +#define FILE_PREPEND_AND_CHANGE \ + "insert at front\n" \ + "hey!\n" \ + "this is some context!\n" \ + "around some lines\n" \ + "that will change\n" \ + "yes it is!\n" \ + "(THIS line is changed!)\n" \ + "and this\n" \ + "is additional context\n" \ + "below it!\n" + +#define PATCH_ORIGINAL_TO_PREPEND_AND_CHANGE \ + "diff --git a/file.txt b/file.txt\n" \ + "index 9432026..f73c8bb 100644\n" \ + "--- a/file.txt\n" \ + "+++ b/file.txt\n" \ + "@@ -1,9 +1,10 @@\n" \ + "+insert at front\n" \ + " hey!\n" \ + " this is some context!\n" \ + " around some lines\n" \ + " that will change\n" \ + " yes it is!\n" \ + "-(this line is changed)\n" \ + "+(THIS line is changed!)\n" \ + " and this\n" \ + " is additional context\n" \ + " below it!\n" + +#define PATCH_ORIGINAL_TO_PREPEND_AND_CHANGE_NOCONTEXT \ + "diff --git a/file.txt b/file.txt\n" \ + "index 9432026..f73c8bb 100644\n" \ + "--- a/file.txt\n" \ + "+++ b/file.txt\n" \ + "@@ -0,0 +1 @@\n" \ + "+insert at front\n" \ + "@@ -6 +7 @@ yes it is!\n" \ + "-(this line is changed)\n" \ + "+(THIS line is changed!)\n" + +/* A deletion at the beginning of the file and a change in the middle */ + +#define FILE_DELETE_AND_CHANGE \ + "this is some context!\n" \ + "around some lines\n" \ + "that will change\n" \ + "yes it is!\n" \ + "(THIS line is changed!)\n" \ + "and this\n" \ + "is additional context\n" \ + "below it!\n" + +#define PATCH_ORIGINAL_TO_DELETE_AND_CHANGE \ + "diff --git a/file.txt b/file.txt\n" \ + "index 9432026..1e2dfa6 100644\n" \ + "--- a/file.txt\n" \ + "+++ b/file.txt\n" \ + "@@ -1,9 +1,8 @@\n" \ + "-hey!\n" \ + " this is some context!\n" \ + " around some lines\n" \ + " that will change\n" \ + " yes it is!\n" \ + "-(this line is changed)\n" \ + "+(THIS line is changed!)\n" \ + " and this\n" \ + " is additional context\n" \ + " below it!\n" + +#define PATCH_ORIGINAL_TO_DELETE_AND_CHANGE_NOCONTEXT \ + "diff --git a/file.txt b/file.txt\n" \ + "index 9432026..1e2dfa6 100644\n" \ + "--- a/file.txt\n" \ + "+++ b/file.txt\n" \ + "@@ -1 +0,0 @@\n" \ + "-hey!\n" \ + "@@ -6 +5 @@ yes it is!\n" \ + "-(this line is changed)\n" \ + "+(THIS line is changed!)\n" + +/* A deletion at the beginning of the file */ + +#define FILE_DELETE_FIRSTLINE \ + "this is some context!\n" \ + "around some lines\n" \ + "that will change\n" \ + "yes it is!\n" \ + "(this line is changed)\n" \ + "and this\n" \ + "is additional context\n" \ + "below it!\n" + +#define PATCH_ORIGINAL_TO_DELETE_FIRSTLINE \ + "diff --git a/file.txt b/file.txt\n" \ + "index 9432026..f31fa13 100644\n" \ + "--- a/file.txt\n" \ + "+++ b/file.txt\n" \ + "@@ -1,4 +1,3 @@\n" \ + "-hey!\n" \ + " this is some context!\n" \ + " around some lines\n" \ + " that will change\n" + /* An insertion at the end of the file (and the resultant patch) */ #define FILE_APPEND \ diff --git a/tests/resources/merge-recursive/.gitted/objects/06/d3fefb8726ab1099acc76e02dfb85e034b2538 b/tests/resources/merge-recursive/.gitted/objects/06/d3fefb8726ab1099acc76e02dfb85e034b2538 Binary files differnew file mode 100644 index 000000000..b3919aab6 --- /dev/null +++ b/tests/resources/merge-recursive/.gitted/objects/06/d3fefb8726ab1099acc76e02dfb85e034b2538 |
