test_patch.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. # test_patch.py -- tests for patch.py
  2. # Copyright (C) 2010 Jelmer Vernooij <jelmer@jelmer.uk>
  3. #
  4. # Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU
  5. # General Public License as public by the Free Software Foundation; version 2.0
  6. # or (at your option) any later version. You can redistribute it and/or
  7. # modify it under the terms of either of these two licenses.
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. #
  15. # You should have received a copy of the licenses; if not, see
  16. # <http://www.gnu.org/licenses/> for a copy of the GNU General Public License
  17. # and <http://www.apache.org/licenses/LICENSE-2.0> for a copy of the Apache
  18. # License, Version 2.0.
  19. #
  20. """Tests for patch.py."""
  21. from io import BytesIO, StringIO
  22. from typing import NoReturn
  23. from dulwich.object_store import MemoryObjectStore
  24. from dulwich.objects import S_IFGITLINK, Blob, Commit, Tree
  25. from dulwich.patch import (
  26. get_summary,
  27. git_am_patch_split,
  28. write_blob_diff,
  29. write_commit_patch,
  30. write_object_diff,
  31. write_tree_diff,
  32. )
  33. from . import SkipTest, TestCase
  34. class WriteCommitPatchTests(TestCase):
  35. def test_simple_bytesio(self) -> None:
  36. f = BytesIO()
  37. c = Commit()
  38. c.committer = c.author = b"Jelmer <jelmer@samba.org>"
  39. c.commit_time = c.author_time = 1271350201
  40. c.commit_timezone = c.author_timezone = 0
  41. c.message = b"This is the first line\nAnd this is the second line.\n"
  42. c.tree = Tree().id
  43. write_commit_patch(f, c, b"CONTENTS", (1, 1), version="custom")
  44. f.seek(0)
  45. lines = f.readlines()
  46. self.assertTrue(
  47. lines[0].startswith(b"From 0b0d34d1b5b596c928adc9a727a4b9e03d025298")
  48. )
  49. self.assertEqual(lines[1], b"From: Jelmer <jelmer@samba.org>\n")
  50. self.assertTrue(lines[2].startswith(b"Date: "))
  51. self.assertEqual(
  52. [
  53. b"Subject: [PATCH 1/1] This is the first line\n",
  54. b"And this is the second line.\n",
  55. b"\n",
  56. b"\n",
  57. b"---\n",
  58. ],
  59. lines[3:8],
  60. )
  61. self.assertEqual([b"CONTENTS-- \n", b"custom\n"], lines[-2:])
  62. if len(lines) >= 12:
  63. # diffstat may not be present
  64. self.assertEqual(lines[8], b" 0 files changed\n")
  65. class ReadGitAmPatch(TestCase):
  66. def test_extract_string(self) -> None:
  67. text = b"""\
  68. From ff643aae102d8870cac88e8f007e70f58f3a7363 Mon Sep 17 00:00:00 2001
  69. From: Jelmer Vernooij <jelmer@samba.org>
  70. Date: Thu, 15 Apr 2010 15:40:28 +0200
  71. Subject: [PATCH 1/2] Remove executable bit from prey.ico (triggers a warning).
  72. ---
  73. pixmaps/prey.ico | Bin 9662 -> 9662 bytes
  74. 1 files changed, 0 insertions(+), 0 deletions(-)
  75. mode change 100755 => 100644 pixmaps/prey.ico
  76. --
  77. 1.7.0.4
  78. """
  79. c, diff, version = git_am_patch_split(StringIO(text.decode("utf-8")), "utf-8")
  80. self.assertEqual(b"Jelmer Vernooij <jelmer@samba.org>", c.committer)
  81. self.assertEqual(b"Jelmer Vernooij <jelmer@samba.org>", c.author)
  82. self.assertEqual(
  83. b"Remove executable bit from prey.ico " b"(triggers a warning).\n",
  84. c.message,
  85. )
  86. self.assertEqual(
  87. b""" pixmaps/prey.ico | Bin 9662 -> 9662 bytes
  88. 1 files changed, 0 insertions(+), 0 deletions(-)
  89. mode change 100755 => 100644 pixmaps/prey.ico
  90. """,
  91. diff,
  92. )
  93. self.assertEqual(b"1.7.0.4", version)
  94. def test_extract_bytes(self) -> None:
  95. text = b"""\
  96. From ff643aae102d8870cac88e8f007e70f58f3a7363 Mon Sep 17 00:00:00 2001
  97. From: Jelmer Vernooij <jelmer@samba.org>
  98. Date: Thu, 15 Apr 2010 15:40:28 +0200
  99. Subject: [PATCH 1/2] Remove executable bit from prey.ico (triggers a warning).
  100. ---
  101. pixmaps/prey.ico | Bin 9662 -> 9662 bytes
  102. 1 files changed, 0 insertions(+), 0 deletions(-)
  103. mode change 100755 => 100644 pixmaps/prey.ico
  104. --
  105. 1.7.0.4
  106. """
  107. c, diff, version = git_am_patch_split(BytesIO(text))
  108. self.assertEqual(b"Jelmer Vernooij <jelmer@samba.org>", c.committer)
  109. self.assertEqual(b"Jelmer Vernooij <jelmer@samba.org>", c.author)
  110. self.assertEqual(
  111. b"Remove executable bit from prey.ico " b"(triggers a warning).\n",
  112. c.message,
  113. )
  114. self.assertEqual(
  115. b""" pixmaps/prey.ico | Bin 9662 -> 9662 bytes
  116. 1 files changed, 0 insertions(+), 0 deletions(-)
  117. mode change 100755 => 100644 pixmaps/prey.ico
  118. """,
  119. diff,
  120. )
  121. self.assertEqual(b"1.7.0.4", version)
  122. def test_extract_spaces(self) -> None:
  123. text = b"""From ff643aae102d8870cac88e8f007e70f58f3a7363 Mon Sep 17 00:00:00 2001
  124. From: Jelmer Vernooij <jelmer@samba.org>
  125. Date: Thu, 15 Apr 2010 15:40:28 +0200
  126. Subject: [Dulwich-users] [PATCH] Added unit tests for
  127. dulwich.object_store.tree_lookup_path.
  128. * dulwich/tests/test_object_store.py
  129. (TreeLookupPathTests): This test case contains a few tests that ensure the
  130. tree_lookup_path function works as expected.
  131. ---
  132. pixmaps/prey.ico | Bin 9662 -> 9662 bytes
  133. 1 files changed, 0 insertions(+), 0 deletions(-)
  134. mode change 100755 => 100644 pixmaps/prey.ico
  135. --
  136. 1.7.0.4
  137. """
  138. c, diff, version = git_am_patch_split(BytesIO(text), "utf-8")
  139. self.assertEqual(
  140. b"""\
  141. Added unit tests for dulwich.object_store.tree_lookup_path.
  142. * dulwich/tests/test_object_store.py
  143. (TreeLookupPathTests): This test case contains a few tests that ensure the
  144. tree_lookup_path function works as expected.
  145. """,
  146. c.message,
  147. )
  148. def test_extract_pseudo_from_header(self) -> None:
  149. text = b"""From ff643aae102d8870cac88e8f007e70f58f3a7363 Mon Sep 17 00:00:00 2001
  150. From: Jelmer Vernooij <jelmer@samba.org>
  151. Date: Thu, 15 Apr 2010 15:40:28 +0200
  152. Subject: [Dulwich-users] [PATCH] Added unit tests for
  153. dulwich.object_store.tree_lookup_path.
  154. From: Jelmer Vernooij <jelmer@debian.org>
  155. * dulwich/tests/test_object_store.py
  156. (TreeLookupPathTests): This test case contains a few tests that ensure the
  157. tree_lookup_path function works as expected.
  158. ---
  159. pixmaps/prey.ico | Bin 9662 -> 9662 bytes
  160. 1 files changed, 0 insertions(+), 0 deletions(-)
  161. mode change 100755 => 100644 pixmaps/prey.ico
  162. --
  163. 1.7.0.4
  164. """
  165. c, diff, version = git_am_patch_split(BytesIO(text), "utf-8")
  166. self.assertEqual(b"Jelmer Vernooij <jelmer@debian.org>", c.author)
  167. self.assertEqual(
  168. b"""\
  169. Added unit tests for dulwich.object_store.tree_lookup_path.
  170. * dulwich/tests/test_object_store.py
  171. (TreeLookupPathTests): This test case contains a few tests that ensure the
  172. tree_lookup_path function works as expected.
  173. """,
  174. c.message,
  175. )
  176. def test_extract_no_version_tail(self) -> None:
  177. text = b"""\
  178. From ff643aae102d8870cac88e8f007e70f58f3a7363 Mon Sep 17 00:00:00 2001
  179. From: Jelmer Vernooij <jelmer@samba.org>
  180. Date: Thu, 15 Apr 2010 15:40:28 +0200
  181. Subject: [Dulwich-users] [PATCH] Added unit tests for
  182. dulwich.object_store.tree_lookup_path.
  183. From: Jelmer Vernooij <jelmer@debian.org>
  184. ---
  185. pixmaps/prey.ico | Bin 9662 -> 9662 bytes
  186. 1 files changed, 0 insertions(+), 0 deletions(-)
  187. mode change 100755 => 100644 pixmaps/prey.ico
  188. """
  189. c, diff, version = git_am_patch_split(BytesIO(text), "utf-8")
  190. self.assertEqual(None, version)
  191. def test_extract_mercurial(self) -> NoReturn:
  192. raise SkipTest(
  193. "git_am_patch_split doesn't handle Mercurial patches " "properly yet"
  194. )
  195. expected_diff = """\
  196. diff --git a/dulwich/tests/test_patch.py b/dulwich/tests/test_patch.py
  197. --- a/dulwich/tests/test_patch.py
  198. +++ b/dulwich/tests/test_patch.py
  199. @@ -158,7 +158,7 @@
  200. '''
  201. c, diff, version = git_am_patch_split(BytesIO(text))
  202. - self.assertIs(None, version)
  203. + self.assertEqual(None, version)
  204. class DiffTests(TestCase):
  205. """
  206. text = f"""\
  207. From dulwich-users-bounces+jelmer=samba.org@lists.launchpad.net \
  208. Mon Nov 29 00:58:18 2010
  209. Date: Sun, 28 Nov 2010 17:57:27 -0600
  210. From: Augie Fackler <durin42@gmail.com>
  211. To: dulwich-users <dulwich-users@lists.launchpad.net>
  212. Subject: [Dulwich-users] [PATCH] test_patch: fix tests on Python 2.6
  213. Content-Transfer-Encoding: 8bit
  214. Change-Id: I5e51313d4ae3a65c3f00c665002a7489121bb0d6
  215. {expected_diff}
  216. _______________________________________________
  217. Mailing list: https://launchpad.net/~dulwich-users
  218. Post to : dulwich-users@lists.launchpad.net
  219. Unsubscribe : https://launchpad.net/~dulwich-users
  220. More help : https://help.launchpad.net/ListHelp
  221. """
  222. c, diff, version = git_am_patch_split(BytesIO(text))
  223. self.assertEqual(expected_diff, diff)
  224. self.assertEqual(None, version)
  225. class DiffTests(TestCase):
  226. """Tests for write_blob_diff and write_tree_diff."""
  227. def test_blob_diff(self) -> None:
  228. f = BytesIO()
  229. write_blob_diff(
  230. f,
  231. (b"foo.txt", 0o644, Blob.from_string(b"old\nsame\n")),
  232. (b"bar.txt", 0o644, Blob.from_string(b"new\nsame\n")),
  233. )
  234. self.assertEqual(
  235. [
  236. b"diff --git a/foo.txt b/bar.txt",
  237. b"index 3b0f961..a116b51 644",
  238. b"--- a/foo.txt",
  239. b"+++ b/bar.txt",
  240. b"@@ -1,2 +1,2 @@",
  241. b"-old",
  242. b"+new",
  243. b" same",
  244. ],
  245. f.getvalue().splitlines(),
  246. )
  247. def test_blob_add(self) -> None:
  248. f = BytesIO()
  249. write_blob_diff(
  250. f,
  251. (None, None, None),
  252. (b"bar.txt", 0o644, Blob.from_string(b"new\nsame\n")),
  253. )
  254. self.assertEqual(
  255. [
  256. b"diff --git a/bar.txt b/bar.txt",
  257. b"new file mode 644",
  258. b"index 0000000..a116b51",
  259. b"--- /dev/null",
  260. b"+++ b/bar.txt",
  261. b"@@ -0,0 +1,2 @@",
  262. b"+new",
  263. b"+same",
  264. ],
  265. f.getvalue().splitlines(),
  266. )
  267. def test_blob_remove(self) -> None:
  268. f = BytesIO()
  269. write_blob_diff(
  270. f,
  271. (b"bar.txt", 0o644, Blob.from_string(b"new\nsame\n")),
  272. (None, None, None),
  273. )
  274. self.assertEqual(
  275. [
  276. b"diff --git a/bar.txt b/bar.txt",
  277. b"deleted file mode 644",
  278. b"index a116b51..0000000",
  279. b"--- a/bar.txt",
  280. b"+++ /dev/null",
  281. b"@@ -1,2 +0,0 @@",
  282. b"-new",
  283. b"-same",
  284. ],
  285. f.getvalue().splitlines(),
  286. )
  287. def test_tree_diff(self) -> None:
  288. f = BytesIO()
  289. store = MemoryObjectStore()
  290. added = Blob.from_string(b"add\n")
  291. removed = Blob.from_string(b"removed\n")
  292. changed1 = Blob.from_string(b"unchanged\nremoved\n")
  293. changed2 = Blob.from_string(b"unchanged\nadded\n")
  294. unchanged = Blob.from_string(b"unchanged\n")
  295. tree1 = Tree()
  296. tree1.add(b"removed.txt", 0o644, removed.id)
  297. tree1.add(b"changed.txt", 0o644, changed1.id)
  298. tree1.add(b"unchanged.txt", 0o644, changed1.id)
  299. tree2 = Tree()
  300. tree2.add(b"added.txt", 0o644, added.id)
  301. tree2.add(b"changed.txt", 0o644, changed2.id)
  302. tree2.add(b"unchanged.txt", 0o644, changed1.id)
  303. store.add_objects(
  304. [
  305. (o, None)
  306. for o in [
  307. tree1,
  308. tree2,
  309. added,
  310. removed,
  311. changed1,
  312. changed2,
  313. unchanged,
  314. ]
  315. ]
  316. )
  317. write_tree_diff(f, store, tree1.id, tree2.id)
  318. self.assertEqual(
  319. [
  320. b"diff --git a/added.txt b/added.txt",
  321. b"new file mode 644",
  322. b"index 0000000..76d4bb8",
  323. b"--- /dev/null",
  324. b"+++ b/added.txt",
  325. b"@@ -0,0 +1 @@",
  326. b"+add",
  327. b"diff --git a/changed.txt b/changed.txt",
  328. b"index bf84e48..1be2436 644",
  329. b"--- a/changed.txt",
  330. b"+++ b/changed.txt",
  331. b"@@ -1,2 +1,2 @@",
  332. b" unchanged",
  333. b"-removed",
  334. b"+added",
  335. b"diff --git a/removed.txt b/removed.txt",
  336. b"deleted file mode 644",
  337. b"index 2c3f0b3..0000000",
  338. b"--- a/removed.txt",
  339. b"+++ /dev/null",
  340. b"@@ -1 +0,0 @@",
  341. b"-removed",
  342. ],
  343. f.getvalue().splitlines(),
  344. )
  345. def test_tree_diff_submodule(self) -> None:
  346. f = BytesIO()
  347. store = MemoryObjectStore()
  348. tree1 = Tree()
  349. tree1.add(
  350. b"asubmodule",
  351. S_IFGITLINK,
  352. b"06d0bdd9e2e20377b3180e4986b14c8549b393e4",
  353. )
  354. tree2 = Tree()
  355. tree2.add(
  356. b"asubmodule",
  357. S_IFGITLINK,
  358. b"cc975646af69f279396d4d5e1379ac6af80ee637",
  359. )
  360. store.add_objects([(o, None) for o in [tree1, tree2]])
  361. write_tree_diff(f, store, tree1.id, tree2.id)
  362. self.assertEqual(
  363. [
  364. b"diff --git a/asubmodule b/asubmodule",
  365. b"index 06d0bdd..cc97564 160000",
  366. b"--- a/asubmodule",
  367. b"+++ b/asubmodule",
  368. b"@@ -1 +1 @@",
  369. b"-Subproject commit 06d0bdd9e2e20377b3180e4986b14c8549b393e4",
  370. b"+Subproject commit cc975646af69f279396d4d5e1379ac6af80ee637",
  371. ],
  372. f.getvalue().splitlines(),
  373. )
  374. def test_object_diff_blob(self) -> None:
  375. f = BytesIO()
  376. b1 = Blob.from_string(b"old\nsame\n")
  377. b2 = Blob.from_string(b"new\nsame\n")
  378. store = MemoryObjectStore()
  379. store.add_objects([(b1, None), (b2, None)])
  380. write_object_diff(
  381. f, store, (b"foo.txt", 0o644, b1.id), (b"bar.txt", 0o644, b2.id)
  382. )
  383. self.assertEqual(
  384. [
  385. b"diff --git a/foo.txt b/bar.txt",
  386. b"index 3b0f961..a116b51 644",
  387. b"--- a/foo.txt",
  388. b"+++ b/bar.txt",
  389. b"@@ -1,2 +1,2 @@",
  390. b"-old",
  391. b"+new",
  392. b" same",
  393. ],
  394. f.getvalue().splitlines(),
  395. )
  396. def test_object_diff_add_blob(self) -> None:
  397. f = BytesIO()
  398. store = MemoryObjectStore()
  399. b2 = Blob.from_string(b"new\nsame\n")
  400. store.add_object(b2)
  401. write_object_diff(f, store, (None, None, None), (b"bar.txt", 0o644, b2.id))
  402. self.assertEqual(
  403. [
  404. b"diff --git a/bar.txt b/bar.txt",
  405. b"new file mode 644",
  406. b"index 0000000..a116b51",
  407. b"--- /dev/null",
  408. b"+++ b/bar.txt",
  409. b"@@ -0,0 +1,2 @@",
  410. b"+new",
  411. b"+same",
  412. ],
  413. f.getvalue().splitlines(),
  414. )
  415. def test_object_diff_remove_blob(self) -> None:
  416. f = BytesIO()
  417. b1 = Blob.from_string(b"new\nsame\n")
  418. store = MemoryObjectStore()
  419. store.add_object(b1)
  420. write_object_diff(f, store, (b"bar.txt", 0o644, b1.id), (None, None, None))
  421. self.assertEqual(
  422. [
  423. b"diff --git a/bar.txt b/bar.txt",
  424. b"deleted file mode 644",
  425. b"index a116b51..0000000",
  426. b"--- a/bar.txt",
  427. b"+++ /dev/null",
  428. b"@@ -1,2 +0,0 @@",
  429. b"-new",
  430. b"-same",
  431. ],
  432. f.getvalue().splitlines(),
  433. )
  434. def test_object_diff_bin_blob_force(self) -> None:
  435. f = BytesIO()
  436. # Prepare two slightly different PNG headers
  437. b1 = Blob.from_string(
  438. b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"
  439. b"\x00\x00\x00\x0d\x49\x48\x44\x52"
  440. b"\x00\x00\x01\xd5\x00\x00\x00\x9f"
  441. b"\x08\x04\x00\x00\x00\x05\x04\x8b"
  442. )
  443. b2 = Blob.from_string(
  444. b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"
  445. b"\x00\x00\x00\x0d\x49\x48\x44\x52"
  446. b"\x00\x00\x01\xd5\x00\x00\x00\x9f"
  447. b"\x08\x03\x00\x00\x00\x98\xd3\xb3"
  448. )
  449. store = MemoryObjectStore()
  450. store.add_objects([(b1, None), (b2, None)])
  451. write_object_diff(
  452. f,
  453. store,
  454. (b"foo.png", 0o644, b1.id),
  455. (b"bar.png", 0o644, b2.id),
  456. diff_binary=True,
  457. )
  458. self.assertEqual(
  459. [
  460. b"diff --git a/foo.png b/bar.png",
  461. b"index f73e47d..06364b7 644",
  462. b"--- a/foo.png",
  463. b"+++ b/bar.png",
  464. b"@@ -1,4 +1,4 @@",
  465. b" \x89PNG",
  466. b" \x1a",
  467. b" \x00\x00\x00",
  468. b"-IHDR\x00\x00\x01\xd5\x00\x00\x00"
  469. b"\x9f\x08\x04\x00\x00\x00\x05\x04\x8b",
  470. b"\\ No newline at end of file",
  471. b"+IHDR\x00\x00\x01\xd5\x00\x00\x00\x9f"
  472. b"\x08\x03\x00\x00\x00\x98\xd3\xb3",
  473. b"\\ No newline at end of file",
  474. ],
  475. f.getvalue().splitlines(),
  476. )
  477. def test_object_diff_bin_blob(self) -> None:
  478. f = BytesIO()
  479. # Prepare two slightly different PNG headers
  480. b1 = Blob.from_string(
  481. b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"
  482. b"\x00\x00\x00\x0d\x49\x48\x44\x52"
  483. b"\x00\x00\x01\xd5\x00\x00\x00\x9f"
  484. b"\x08\x04\x00\x00\x00\x05\x04\x8b"
  485. )
  486. b2 = Blob.from_string(
  487. b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"
  488. b"\x00\x00\x00\x0d\x49\x48\x44\x52"
  489. b"\x00\x00\x01\xd5\x00\x00\x00\x9f"
  490. b"\x08\x03\x00\x00\x00\x98\xd3\xb3"
  491. )
  492. store = MemoryObjectStore()
  493. store.add_objects([(b1, None), (b2, None)])
  494. write_object_diff(
  495. f, store, (b"foo.png", 0o644, b1.id), (b"bar.png", 0o644, b2.id)
  496. )
  497. self.assertEqual(
  498. [
  499. b"diff --git a/foo.png b/bar.png",
  500. b"index f73e47d..06364b7 644",
  501. b"Binary files a/foo.png and b/bar.png differ",
  502. ],
  503. f.getvalue().splitlines(),
  504. )
  505. def test_object_diff_add_bin_blob(self) -> None:
  506. f = BytesIO()
  507. b2 = Blob.from_string(
  508. b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"
  509. b"\x00\x00\x00\x0d\x49\x48\x44\x52"
  510. b"\x00\x00\x01\xd5\x00\x00\x00\x9f"
  511. b"\x08\x03\x00\x00\x00\x98\xd3\xb3"
  512. )
  513. store = MemoryObjectStore()
  514. store.add_object(b2)
  515. write_object_diff(f, store, (None, None, None), (b"bar.png", 0o644, b2.id))
  516. self.assertEqual(
  517. [
  518. b"diff --git a/bar.png b/bar.png",
  519. b"new file mode 644",
  520. b"index 0000000..06364b7",
  521. b"Binary files /dev/null and b/bar.png differ",
  522. ],
  523. f.getvalue().splitlines(),
  524. )
  525. def test_object_diff_remove_bin_blob(self) -> None:
  526. f = BytesIO()
  527. b1 = Blob.from_string(
  528. b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"
  529. b"\x00\x00\x00\x0d\x49\x48\x44\x52"
  530. b"\x00\x00\x01\xd5\x00\x00\x00\x9f"
  531. b"\x08\x04\x00\x00\x00\x05\x04\x8b"
  532. )
  533. store = MemoryObjectStore()
  534. store.add_object(b1)
  535. write_object_diff(f, store, (b"foo.png", 0o644, b1.id), (None, None, None))
  536. self.assertEqual(
  537. [
  538. b"diff --git a/foo.png b/foo.png",
  539. b"deleted file mode 644",
  540. b"index f73e47d..0000000",
  541. b"Binary files a/foo.png and /dev/null differ",
  542. ],
  543. f.getvalue().splitlines(),
  544. )
  545. def test_object_diff_kind_change(self) -> None:
  546. f = BytesIO()
  547. b1 = Blob.from_string(b"new\nsame\n")
  548. store = MemoryObjectStore()
  549. store.add_object(b1)
  550. write_object_diff(
  551. f,
  552. store,
  553. (b"bar.txt", 0o644, b1.id),
  554. (
  555. b"bar.txt",
  556. 0o160000,
  557. b"06d0bdd9e2e20377b3180e4986b14c8549b393e4",
  558. ),
  559. )
  560. self.assertEqual(
  561. [
  562. b"diff --git a/bar.txt b/bar.txt",
  563. b"old file mode 644",
  564. b"new file mode 160000",
  565. b"index a116b51..06d0bdd 160000",
  566. b"--- a/bar.txt",
  567. b"+++ b/bar.txt",
  568. b"@@ -1,2 +1 @@",
  569. b"-new",
  570. b"-same",
  571. b"+Subproject commit 06d0bdd9e2e20377b3180e4986b14c8549b393e4",
  572. ],
  573. f.getvalue().splitlines(),
  574. )
  575. class GetSummaryTests(TestCase):
  576. def test_simple(self) -> None:
  577. c = Commit()
  578. c.committer = c.author = b"Jelmer <jelmer@samba.org>"
  579. c.commit_time = c.author_time = 1271350201
  580. c.commit_timezone = c.author_timezone = 0
  581. c.message = b"This is the first line\nAnd this is the second line.\n"
  582. c.tree = Tree().id
  583. self.assertEqual("This-is-the-first-line", get_summary(c))