From 728e5a2f1ed16e2cfe0ca5586edac6c10da436c5 Mon Sep 17 00:00:00 2001
From: =?utf8?q?=C5=81ukasz=20Langa?= <lukasz@langa.pl>
Date: Mon, 4 Jun 2018 17:10:32 -0700
Subject: [PATCH] Properly format unified diff

Previously we weren't using timestamps.
---
 README.md             |  2 ++
 black.py              | 13 +++++++++----
 tests/expression.diff |  4 ++--
 tests/test_black.py   | 15 ++++++++++++---
 4 files changed, 25 insertions(+), 9 deletions(-)

diff --git a/README.md b/README.md
index beba56c..911d1f9 100644
--- a/README.md
+++ b/README.md
@@ -717,6 +717,8 @@ More details can be found in [CONTRIBUTING](CONTRIBUTING.md).
 
 * added `--verbose` (#283)
 
+* the header output in `--diff` now actually conforms to the unified diff spec
+
 * fixed stdin handling not working correctly if an old version of Click was
   used (#276)
 
diff --git a/black.py b/black.py
index 7138d29..2783a10 100644
--- a/black.py
+++ b/black.py
@@ -1,6 +1,7 @@
 import asyncio
 from asyncio.base_events import BaseEventLoop
 from concurrent.futures import Executor, ProcessPoolExecutor
+from datetime import datetime
 from enum import Enum, Flag
 from functools import partial, wraps
 import io
@@ -469,6 +470,7 @@ def format_file_in_place(
     if src.suffix == ".pyi":
         mode |= FileMode.PYI
 
+    then = datetime.utcfromtimestamp(src.stat().st_mtime)
     with open(src, "rb") as buf:
         src_contents, encoding, newline = decode_bytes(buf.read())
     try:
@@ -482,8 +484,9 @@ def format_file_in_place(
         with open(src, "w", encoding=encoding, newline=newline) as f:
             f.write(dst_contents)
     elif write_back == write_back.DIFF:
-        src_name = f"{src}  (original)"
-        dst_name = f"{src}  (formatted)"
+        now = datetime.utcnow()
+        src_name = f"{src}\t{then} +0000"
+        dst_name = f"{src}\t{now} +0000"
         diff_contents = diff(src_contents, dst_contents, src_name, dst_name)
         if lock:
             lock.acquire()
@@ -514,6 +517,7 @@ def format_stdin_to_stdout(
     `line_length`, `fast`, `is_pyi`, and `force_py36` arguments are passed to
     :func:`format_file_contents`.
     """
+    then = datetime.utcnow()
     src, encoding, newline = decode_bytes(sys.stdin.buffer.read())
     dst = src
     try:
@@ -530,8 +534,9 @@ def format_stdin_to_stdout(
         if write_back == WriteBack.YES:
             f.write(dst)
         elif write_back == WriteBack.DIFF:
-            src_name = "<stdin>  (original)"
-            dst_name = "<stdin>  (formatted)"
+            now = datetime.utcnow()
+            src_name = f"STDIN\t{then} +0000"
+            dst_name = f"STDOUT\t{now} +0000"
             f.write(diff(src, dst, src_name, dst_name))
         f.detach()
 
diff --git a/tests/expression.diff b/tests/expression.diff
index 4a4bb14..2632349 100644
--- a/tests/expression.diff
+++ b/tests/expression.diff
@@ -1,5 +1,5 @@
---- <stdin>  (original)
-+++ <stdin>  (formatted)
+--- [Deterministic header]
++++ [Deterministic header]
 @@ -1,8 +1,8 @@
  ...
 -'some_string'
diff --git a/tests/test_black.py b/tests/test_black.py
index 0645525..f6952c7 100644
--- a/tests/test_black.py
+++ b/tests/test_black.py
@@ -6,18 +6,19 @@ from functools import partial
 from io import BytesIO, TextIOWrapper
 import os
 from pathlib import Path
+import re
 import sys
 from tempfile import TemporaryDirectory
 from typing import Any, List, Tuple, Iterator
 import unittest
 from unittest.mock import patch
-import re
 
 from click import unstyle
 from click.testing import CliRunner
 
 import black
 
+
 ll = 88
 ff = partial(black.format_file_in_place, line_length=ll, fast=True)
 fs = partial(black.format_str, line_length=ll)
@@ -136,18 +137,22 @@ class BlackTestCase(unittest.TestCase):
         black.assert_stable(source, actual, line_length=ll)
 
     def test_piping_diff(self) -> None:
+        diff_header = re.compile(
+            rf"(STDIN|STDOUT)\t\d\d\d\d-\d\d-\d\d "
+            rf"\d\d:\d\d:\d\d\.\d\d\d\d\d\d \+\d\d\d\d"
+        )
         source, _ = read_data("expression.py")
         expected, _ = read_data("expression.diff")
         hold_stdin, hold_stdout = sys.stdin, sys.stdout
         try:
             sys.stdin = TextIOWrapper(BytesIO(source.encode("utf8")), encoding="utf8")
             sys.stdout = TextIOWrapper(BytesIO(), encoding="utf8")
-            sys.stdin.buffer.name = "<stdin>"  # type: ignore
             black.format_stdin_to_stdout(
                 line_length=ll, fast=True, write_back=black.WriteBack.DIFF
             )
             sys.stdout.seek(0)
             actual = sys.stdout.read()
+            actual = diff_header.sub("[Deterministic header]", actual)
         finally:
             sys.stdin, sys.stdout = hold_stdin, hold_stdout
         actual = actual.rstrip() + "\n"  # the diff output has a trailing space
@@ -204,13 +209,17 @@ class BlackTestCase(unittest.TestCase):
         source, _ = read_data("expression.py")
         expected, _ = read_data("expression.diff")
         tmp_file = Path(black.dump_to_file(source))
+        diff_header = re.compile(
+            rf"{re.escape(str(tmp_file))}\t\d\d\d\d-\d\d-\d\d "
+            rf"\d\d:\d\d:\d\d\.\d\d\d\d\d\d \+\d\d\d\d"
+        )
         hold_stdout = sys.stdout
         try:
             sys.stdout = TextIOWrapper(BytesIO(), encoding="utf8")
             self.assertTrue(ff(tmp_file, write_back=black.WriteBack.DIFF))
             sys.stdout.seek(0)
             actual = sys.stdout.read()
-            actual = actual.replace(str(tmp_file), "<stdin>")
+            actual = diff_header.sub("[Deterministic header]", actual)
         finally:
             sys.stdout = hold_stdout
             os.unlink(tmp_file)
-- 
2.39.5