[Reproducible-commits] [diffoscope] 03/03: Add --new-file to treat absent files as empty

Jérémy Bobbio lunar at moszumanska.debian.org
Thu Sep 3 14:08:27 UTC 2015


This is an automated email from the git hooks/post-receive script.

lunar pushed a commit to branch master
in repository diffoscope.

commit d6fcb8618d8b68887284733a9792adf84a9588e2
Author: Jérémy Bobbio <lunar at debian.org>
Date:   Wed Sep 2 20:52:56 2015 +0000

    Add --new-file to treat absent files as empty
    
    When specifying --new-file, diffoscope will treat non-existing files
    (which also applies to containers) as empty.
    
    We had to change perform_fuzzy_matching to return names so we can
    pop them out the dictionaries with the set of files that have not
    been compared.
    
    Thanks Jakub Wilk for the suggestion.
    
    Closes: #797560
---
 diffoscope/__main__.py             |   3 ++
 diffoscope/changes.py              |   3 ++
 diffoscope/comparators/__init__.py |  48 ++++++++++++++--------
 diffoscope/comparators/binary.py   |  78 ++++++++++++++++++++++++++++++++++++
 diffoscope/comparators/deb.py      |   2 +-
 diffoscope/comparators/debian.py   |  16 ++++++--
 diffoscope/comparators/utils.py    |  60 ++++++++++++++++++++++++++--
 diffoscope/config.py               |   9 +++++
 diffoscope/difference.py           |  79 ++++++++++++++++++++++++++++++-------
 tests/comparators/test_binary.py   |  12 +++++-
 tests/comparators/test_bzip2.py    |   8 +++-
 tests/comparators/test_cpio.py     |   9 ++++-
 tests/comparators/test_deb.py      |   9 ++++-
 tests/comparators/test_debian.py   |  10 ++++-
 tests/comparators/test_elf.py      |  13 +++++-
 tests/comparators/test_fonts.py    |   8 +++-
 tests/comparators/test_gettext.py  |   8 +++-
 tests/comparators/test_gzip.py     |   9 ++++-
 tests/comparators/test_ipk.py      |   9 ++++-
 tests/comparators/test_iso9660.py  |   9 ++++-
 tests/comparators/test_java.py     |   8 +++-
 tests/comparators/test_mono.py     |   8 +++-
 tests/comparators/test_pdf.py      |   8 +++-
 tests/comparators/test_png.py      |   8 +++-
 tests/comparators/test_rpm.py      |   9 ++++-
 tests/comparators/test_sqlite.py   |   8 +++-
 tests/comparators/test_squashfs.py |   9 ++++-
 tests/comparators/test_tar.py      |   9 ++++-
 tests/comparators/test_text.py     |   8 +++-
 tests/comparators/test_utils.py    |  23 +++++++++++
 tests/comparators/test_xz.py       |   9 ++++-
 tests/comparators/test_zip.py      |   9 ++++-
 tests/data/fuzzy-tar-in-tar1.tar   | Bin 0 -> 20480 bytes
 tests/data/fuzzy-tar-in-tar2.tar   | Bin 0 -> 20480 bytes
 tests/test_main.py                 |  28 +++++++++++++
 35 files changed, 484 insertions(+), 62 deletions(-)

diff --git a/diffoscope/__main__.py b/diffoscope/__main__.py
index bccc80c..e53a1db 100644
--- a/diffoscope/__main__.py
+++ b/diffoscope/__main__.py
@@ -68,6 +68,8 @@ def create_parser():
                              '(0 to disable, %d is default, 400 is high fuzziness)' %
                              (Config.general.fuzzy_threshold),
                         default=Config.general.fuzzy_threshold)
+    parser.add_argument('--new-file', dest='new_file', action='store_true',
+                        help='treat absent files as empty')
     parser.add_argument('--css', metavar='url', dest='css_url',
                         help='link to an extra CSS for the HTML report')
     parser.add_argument('file1', help='first file to compare')
@@ -107,6 +109,7 @@ def run_diffoscope(parsed_args):
     Config.general.max_diff_input_lines = parsed_args.max_diff_input_lines
     Config.general.max_report_size = parsed_args.max_report_size
     Config.general.fuzzy_threshold = parsed_args.fuzzy_threshold
+    Config.general.new_file = parsed_args.new_file
     if parsed_args.debug:
         logger.setLevel(logging.DEBUG)
     set_locale()
diff --git a/diffoscope/changes.py b/diffoscope/changes.py
index 0189dc4..e9afa7d 100644
--- a/diffoscope/changes.py
+++ b/diffoscope/changes.py
@@ -127,6 +127,9 @@ class Changes(object):
         return [os.path.join(self._directory, z['name'])
                 for z in self._data['Files']]
 
+    def keys(self):
+        return self._data.keys()
+
     def __getitem__(self, key):
         """
         Returns the value of the rfc822 key specified.
diff --git a/diffoscope/comparators/__init__.py b/diffoscope/comparators/__init__.py
index 6027462..118ad3e 100644
--- a/diffoscope/comparators/__init__.py
+++ b/diffoscope/comparators/__init__.py
@@ -28,7 +28,7 @@ from diffoscope import logger, tool_required
 from diffoscope.config import Config
 from diffoscope.difference import Difference
 from diffoscope.comparators.binary import \
-    File, FilesystemFile, compare_binary_files
+    File, FilesystemFile, NonExistingFile, compare_binary_files
 from diffoscope.comparators.bzip2 import Bzip2File
 from diffoscope.comparators.java import ClassFile
 from diffoscope.comparators.cpio import CpioFile
@@ -61,15 +61,22 @@ from diffoscope.comparators.xz import XzFile
 from diffoscope.comparators.zip import ZipFile
 
 
-def compare_root_paths(path1, path2):
-    if not all(map(os.path.lexists, (path1, path2))):
-        for path in (path1, path2):
+def bail_if_non_existing(*paths):
+    if not all(map(os.path.lexists, paths)):
+        for path in paths:
             if not os.path.lexists(path):
                 sys.stderr.write('%s: %s: No such file or directory\n' % (sys.argv[0], path))
         sys.exit(2)
+
+
+def compare_root_paths(path1, path2):
+    if not Config.general.new_file:
+        bail_if_non_existing(path1, path2)
     if os.path.isdir(path1) and os.path.isdir(path2):
         return compare_directories(path1, path2)
-    return compare_files(specialize(FilesystemFile(path1)), specialize(FilesystemFile(path2)))
+    file1 = specialize(FilesystemFile(path1))
+    file2 = specialize(FilesystemFile(path2))
+    return compare_files(file1, file2)
 
 
 def compare_files(file1, file2, source=None):
@@ -80,7 +87,11 @@ def compare_files(file1, file2, source=None):
             return None
         specialize(file1)
         specialize(file2)
-        if file1.__class__.__name__ != file2.__class__.__name__:
+        if isinstance(file1, NonExistingFile):
+            file1.other_file = file2
+        elif isinstance(file2, NonExistingFile):
+            file2.other_file = file1
+        elif file1.__class__.__name__ != file2.__class__.__name__:
             return file1.compare_bytes(file2, source)
         return file1.compare(file2, source)
 
@@ -88,6 +99,7 @@ def compare_files(file1, file2, source=None):
 # The order matters! They will be tried in turns.
 FILE_CLASSES = (
     Directory,
+    NonExistingFile,
     Symlink,
     Device,
     DotChangesFile,
@@ -132,23 +144,25 @@ def specialize(file):
     return file
 
 
-def perform_fuzzy_matching(files1, files2):
+def perform_fuzzy_matching(members1, members2):
     if Config.general.fuzzy_threshold == 0:
         return
-    files2 = set(files2)
     already_compared = set()
-    for file1 in filter(lambda f: not f.is_directory(), files1):
-        if not file1.fuzzy_hash:
+    # Perform local copies because they will be modified by consumer
+    members1 = dict(members1)
+    members2 = dict(members2)
+    for name1, file1 in members1.iteritems():
+        if file1.is_directory() or not file1.fuzzy_hash:
             continue
         comparisons = []
-        for file2 in files2 - already_compared:
-            if file2.is_directory() or not file2.fuzzy_hash:
+        for name2, file2 in members2.iteritems():
+            if name2 in already_compared or file2.is_directory() or not file2.fuzzy_hash:
                 continue
-            comparisons.append((tlsh.diff(file1.fuzzy_hash, file2.fuzzy_hash), file2))
+            comparisons.append((tlsh.diff(file1.fuzzy_hash, file2.fuzzy_hash), name2))
         if comparisons:
             comparisons.sort(key=operator.itemgetter(0))
-            score, file2 = comparisons[0]
-            logger.debug('fuzzy top match %s %s: %d difference score', file1.name, file2.name, score)
+            score, name2 = comparisons[0]
+            logger.debug('fuzzy top match %s %s: %d difference score', name1, name2, score)
             if score < Config.general.fuzzy_threshold:
-                yield file1, file2, score
-                already_compared.add(file2)
+                yield name1, name2, score
+                already_compared.add(name2)
diff --git a/diffoscope/comparators/binary.py b/diffoscope/comparators/binary.py
index 8060a17..3c8844a 100644
--- a/diffoscope/comparators/binary.py
+++ b/diffoscope/comparators/binary.py
@@ -26,8 +26,10 @@ import os.path
 import re
 from stat import S_ISCHR, S_ISBLK
 import subprocess
+import tempfile
 import tlsh
 import magic
+from diffoscope.config import Config
 from diffoscope.difference import Difference
 from diffoscope import tool_required, RequiredToolNotFound, logger
 
@@ -197,6 +199,7 @@ class File(object):
             return difference
         return self.compare_bytes(other, source)
 
+
 class FilesystemFile(File):
     def __init__(self, path):
         self._path = None
@@ -220,3 +223,78 @@ class FilesystemFile(File):
     def is_device(self):
         mode = os.lstat(self._name).st_mode
         return S_ISCHR(mode) or S_ISBLK(mode)
+
+
+class NonExistingFile(File):
+    """Represents a missing file when comparing containers"""
+
+    @staticmethod
+    def recognizes(file):
+        if isinstance(file, FilesystemFile) and not os.path.lexists(file.name):
+            assert Config.general.new_file, '%s does not exist' % file.name
+            return True
+        return False
+
+    def __init__(self, path, other_file=None):
+        self._path = None
+        self._name = path
+        self._other_file = other_file
+
+    @property
+    def other_file(self):
+        return self._other_file
+
+    @other_file.setter
+    def other_file(self, value):
+        self._other_file = value
+
+    def has_same_content_as(self, other):
+        return False
+
+    @contextmanager
+    def get_content(self):
+        self._path = '/dev/null'
+        yield
+        self._path = None
+
+    def is_directory(self):
+        return False
+
+    def is_symlink(self):
+        return False
+
+    def is_device(self):
+        return False
+
+    def compare(self, other, source=None):
+        # So now that comparators are all object-oriented, we don't have any clue on how to
+        # perform a meaningful comparison right here. So we are good do the comparison backward
+        # (where knowledge of the file format lies) and and then reverse it.
+        if isinstance(other, NonExistingFile):
+            return Difference(None, self.name, other.name, comment='Trying to compare two non-existing files.')
+        logger.debug('Performing backward comparison')
+        backward_diff = other.compare(self, source)
+        if not backward_diff:
+            return None
+        return backward_diff.get_reverse()
+
+    # Be nice to text comparisons
+    @property
+    def encoding(self):
+        return self._other_file.encoding
+
+    # Be nice to device comparisons
+    def get_device(self):
+        return ''
+
+    # Be nice to metadata comparisons
+    @property
+    def magic_file_type(self):
+        return self._other_file.magic_file_type
+
+    # Be nice to .changes comparisons
+    @property
+    def changes(self):
+        class DummyChanges(dict):
+            get_as_string = lambda self, _: ''
+        return DummyChanges(Files=[], Version='')
diff --git a/diffoscope/comparators/deb.py b/diffoscope/comparators/deb.py
index 9cab27e..daf5315 100644
--- a/diffoscope/comparators/deb.py
+++ b/diffoscope/comparators/deb.py
@@ -108,7 +108,7 @@ class Md5sumsFile(File):
 
     @needs_content
     def compare(self, other, source=None):
-        if self.has_same_content_as(other):
+        if self.has_same_content_as(other) or other.path is None:
             return None
         try:
             my_md5sums = Md5sumsFile.parse_md5sums(self.path)
diff --git a/diffoscope/comparators/debian.py b/diffoscope/comparators/debian.py
index af5b714..734577b 100644
--- a/diffoscope/comparators/debian.py
+++ b/diffoscope/comparators/debian.py
@@ -22,8 +22,9 @@ import os.path
 import re
 from diffoscope.changes import Changes
 import diffoscope.comparators
-from diffoscope.comparators.binary import File, needs_content
+from diffoscope.comparators.binary import File, NonExistingFile, needs_content
 from diffoscope.comparators.utils import Container, NO_COMMENT
+from diffoscope.config import Config
 from diffoscope.difference import Difference
 
 
@@ -121,10 +122,17 @@ class DotChangesFile(File):
     def compare_details(self, other, source=None):
         differences = []
 
-        for field in DOT_CHANGES_FIELDS:
+        for field in sorted(set(self.changes.keys()).union(set(other.changes.keys()))):
+            if field.startswith('Checksums-') or field == 'Files':
+                continue
+            my_value = ''
+            if field in self.changes:
+                my_value = self.changes.get_as_string(field).lstrip()
+            other_value = ''
+            if field in other.changes:
+                other_value = other.changes.get_as_string(field).lstrip()
             differences.append(Difference.from_unicode(
-                                   self.changes[field].lstrip(),
-                                   other.changes[field].lstrip(),
+                                   my_value, other_value,
                                    self.path, other.path, source=field))
         # compare Files as string
         differences.append(Difference.from_unicode(self.changes.get_as_string('Files'),
diff --git a/diffoscope/comparators/utils.py b/diffoscope/comparators/utils.py
index dd40310..6ff1162 100644
--- a/diffoscope/comparators/utils.py
+++ b/diffoscope/comparators/utils.py
@@ -28,7 +28,8 @@ import subprocess
 import tempfile
 from threading import Thread
 import diffoscope.comparators
-from diffoscope.comparators.binary import File
+from diffoscope.comparators.binary import File, NonExistingFile
+from diffoscope.config import Config
 from diffoscope.difference import Difference
 from diffoscope import logger, tool_required
 
@@ -44,6 +45,8 @@ def make_temp_directory():
 
 @tool_required('ar')
 def get_ar_content(path):
+    if path == '/dev/null':
+        return ''
     return subprocess.check_output(
         ['ar', 'tv', path], stderr=subprocess.STDOUT, shell=False).decode('utf-8')
 
@@ -177,9 +180,16 @@ class Container(object):
         other_members = other.get_members()
         for name in sorted(set(my_members.iterkeys()).intersection(set(other_members.iterkeys()))):
             yield my_members.pop(name), other_members.pop(name), NO_COMMENT
-        for my_file, other_file, score in diffoscope.comparators.perform_fuzzy_matching(my_members.values(), other_members.values()):
+        for my_name, other_name, score in diffoscope.comparators.perform_fuzzy_matching(my_members, other_members):
             comment = 'Files similar despite different names (difference score: %d)' % score
-            yield my_file, other_file, comment
+            yield my_members.pop(my_name), other_members.pop(other_name), comment
+        if Config.general.new_file:
+            for my_name in set(my_members.iterkeys()) - set(other_members.iterkeys()):
+                my_file = my_members[my_name]
+                yield my_file, NonExistingFile('/dev/null', my_file), NO_COMMENT
+            for other_name in set(other_members.iterkeys()) - set(my_members.iterkeys()):
+                other_file = other_members[other_name]
+                yield NonExistingFile('/dev/null', other_file), other_file, NO_COMMENT
 
     def compare(self, other, source=None):
         differences = []
@@ -238,7 +248,9 @@ class Archive(Container):
 
     @contextmanager
     def open(self):
-        if self._archive is not None:
+        if isinstance(self.source, NonExistingFile):
+            yield NonExistingArchive(self.source)
+        elif self._archive is not None:
             yield self
         else:
             with self.source.get_content():
@@ -271,3 +283,43 @@ class Archive(Container):
 
     def get_member(self, member_name):
         return ArchiveMember(self, member_name)
+
+
+class NonExistingArchiveLikeObject(object):
+    def getnames(self):
+        return []
+
+    def list(self, *args, **kwargs):
+        return ''
+
+    def close(self):
+        pass
+
+
+class NonExistingArchive(Archive):
+    @property
+    def archive(self):
+        return NonExistingArchiveLikeObject()
+
+    def open_archive(self):
+        # should never be called
+        raise NotImplemented
+
+    def close_archive(self):
+        # should never be called
+        raise NotImplemented
+
+    def get_member_names(self):
+        return []
+
+    def extract(self, member_name, dest_dir):
+        # should never be called
+        raise NotImplemented
+
+    def get_member(self, member_name):
+        return NonExistingFile('/dev/null')
+
+    # Be nice to gzip and the likes
+    @property
+    def path(self):
+        return '/dev/null'
diff --git a/diffoscope/config.py b/diffoscope/config.py
index 4468fc8..5087306 100644
--- a/diffoscope/config.py
+++ b/diffoscope/config.py
@@ -31,6 +31,7 @@ class Config(object):
         self._max_diff_input_lines = 100000 # GNU diff cannot process arbitrary large files :(
         self._max_report_size = 2000 * 2 ** 10 # 2000 kB
         self._fuzzy_threshold = 60
+        self._new_file = False
 
     @classproperty
     def general(cls):
@@ -69,3 +70,11 @@ class Config(object):
     @fuzzy_threshold.setter
     def fuzzy_threshold(self, value):
         self._fuzzy_threshold = value
+
+    @property
+    def new_file(self):
+        return self._new_file
+
+    @new_file.setter
+    def new_file(self, value):
+        self._new_file = value
diff --git a/diffoscope/difference.py b/diffoscope/difference.py
index 26996ce..e1b2a9a 100644
--- a/diffoscope/difference.py
+++ b/diffoscope/difference.py
@@ -220,6 +220,12 @@ def make_feeder_from_unicode(content):
     return feeder
 
 
+def empty_file_feeder():
+    def feeder(f):
+        return False
+    return feeder
+
+
 def make_feeder_from_file(in_file, filter=lambda buf: buf.encode('utf-8')):
     def feeder(out_file):
         line_count = 0
@@ -236,6 +242,7 @@ def make_feeder_from_file(in_file, filter=lambda buf: buf.encode('utf-8')):
         return end_nl
     return feeder
 
+
 def make_feeder_from_command(command):
     def feeder(out_file):
         end_nl = make_feeder_from_file(command.stdout, command.filter)(out_file)
@@ -264,7 +271,10 @@ class Difference(object):
     def __init__(self, unified_diff, path1, path2, source=None, comment=None):
         self._comments = []
         if comment:
-            self._comments.append(comment)
+            if type(comment) is list:
+                self._comments.extend(comment)
+            else:
+                self._comments.append(comment)
         self._unified_diff = unified_diff
         # allow to override declared file paths, useful when comparing
         # tempfiles
@@ -314,22 +324,30 @@ class Difference(object):
         if 'command_args' in kwargs:
             command_args = kwargs['command_args']
             del kwargs['command_args']
-        command1 = cls(path1, *command_args)
-        command2 = cls(path2, *command_args)
+        command1 = None
+        if path1 == '/dev/null':
+            feeder1 = empty_file_feeder()
+        else:
+            command1 = cls(path1, *command_args)
+            feeder1 = make_feeder_from_command(command1)
+        command2 = None
+        if path2 == '/dev/null':
+            feeder2 = empty_file_feeder()
+        else:
+            command2 = cls(path2, *command_args)
+            feeder2 = make_feeder_from_command(command2)
         if 'source' not in kwargs:
-            kwargs['source'] = ' '.join(map(lambda x: '{}' if x == command1.path else x, command1.cmdline()))
-        difference = Difference.from_feeder(make_feeder_from_command(command1),
-                                            make_feeder_from_command(command2),
-                                            path1, path2, *args, **kwargs)
+            source_cmd = command1 or command2
+            kwargs['source'] = ' '.join(map(lambda x: '{}' if x == source_cmd.path else x, source_cmd.cmdline()))
+        difference = Difference.from_feeder(feeder1, feeder2, path1, path2, *args, **kwargs)
         if not difference:
             return None
-        if command1.stderr_content or command2.stderr_content:
-            if command1.stderr_content:
-                difference.add_comment('stderr from `%s`:' % ' '.join(command1.cmdline()))
-                difference.add_comment(command1.stderr_content)
-            if command2.stderr_content:
-                difference.add_comment('stderr from `%s`:' % ' '.join(command2.cmdline()))
-                difference.add_comment(command2.stderr_content)
+        if command1 and command1.stderr_content:
+            difference.add_comment('stderr from `%s`:' % ' '.join(command1.cmdline()))
+            difference.add_comment(command1.stderr_content)
+        if command2 and command2.stderr_content:
+            difference.add_comment('stderr from `%s`:' % ' '.join(command2.cmdline()))
+            difference.add_comment(command2.stderr_content)
         return difference
 
     @property
@@ -364,8 +382,41 @@ class Difference(object):
             raise TypeError("'differences' must contains Difference objects'")
         self._details.extend(differences)
 
+    def get_reverse(self):
+        if self._unified_diff is None:
+            unified_diff = None
+        else:
+            unified_diff = reverse_unified_diff(self._unified_diff)
+        logger.debug('reverse orig %s %s', self._source1, self._source2)
+        difference = Difference(unified_diff, None, None, source=[self._source2, self._source1], comment=self._comments)
+        difference.add_details([d.get_reverse() for d in self._details])
+        return difference
+
 
 def get_source(path1, path2):
     if os.path.basename(path1) == os.path.basename(path2):
         return os.path.basename(path1)
     return None
+
+
+def reverse_unified_diff(diff):
+    res = []
+    for line in diff.splitlines(True): # keepends=True
+        found = DiffParser.RANGE_RE.match(line)
+        if found:
+            before = found.group('start2')
+            if found.group('len2') is not None:
+                before += ',' + found.group('len2')
+            after = found.group('start1')
+            if found.group('len1') is not None:
+                after += ',' + found.group('len1')
+            res.append('@@ -%s +%s @@\n' % (before, after))
+        elif line.startswith('-'):
+            res.append('+')
+            res.append(line[1:])
+        elif line.startswith('+'):
+            res.append('-')
+            res.append(line[1:])
+        else:
+            res.append(line)
+    return ''.join(res)
diff --git a/tests/comparators/test_binary.py b/tests/comparators/test_binary.py
index 7ff1754..fb8b57d 100644
--- a/tests/comparators/test_binary.py
+++ b/tests/comparators/test_binary.py
@@ -23,7 +23,7 @@ import subprocess
 import pytest
 from diffoscope.comparators import specialize
 import diffoscope.comparators.binary
-from diffoscope.comparators.binary import File, FilesystemFile
+from diffoscope.comparators.binary import File, FilesystemFile, NonExistingFile
 from diffoscope.difference import Difference
 from diffoscope import RequiredToolNotFound, tool_required
 
@@ -71,6 +71,10 @@ def test_compare_with_xxd(binary1, binary2):
     expected_diff = open(os.path.join(os.path.dirname(__file__), '../data/binary_expected_diff')).read()
     assert difference.unified_diff == expected_diff
 
+def test_compare_non_existing_with_xxd(binary1):
+    difference = binary1.compare_bytes(NonExistingFile('/nonexisting', binary1))
+    assert difference.source2 == '/dev/null'
+
 @pytest.fixture
 def xxd_not_found(monkeypatch):
     def mock_xxd(path):
@@ -133,3 +137,9 @@ def test_with_compare_details_and_tool_not_found(monkeypatch):
     assert 'nonexistent' in difference.comment
     assert 'some-package' in difference.comment
     assert difference.unified_diff == expected_diff
+
+def test_compare_two_nonexisting_files():
+    file1 = NonExistingFile('/nonexisting1')
+    file2 = NonExistingFile('/nonexisting2')
+    difference = file1.compare(file2)
+    assert 'non-existing' in difference.comment
diff --git a/tests/comparators/test_bzip2.py b/tests/comparators/test_bzip2.py
index fe38502..77008ca 100644
--- a/tests/comparators/test_bzip2.py
+++ b/tests/comparators/test_bzip2.py
@@ -22,8 +22,9 @@ import os.path
 import shutil
 import pytest
 from diffoscope.comparators import specialize
-from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
 from diffoscope.comparators.bzip2 import Bzip2File
+from diffoscope.config import Config
 
 TEST_FILE1_PATH = os.path.join(os.path.dirname(__file__), '../data/test1.bz2')
 TEST_FILE2_PATH = os.path.join(os.path.dirname(__file__), '../data/test2.bz2')
@@ -67,3 +68,8 @@ def test_content_source_without_extension(tmpdir):
 def test_content_diff(differences):
     expected_diff = open(os.path.join(os.path.dirname(__file__), '../data/text_ascii_expected_diff')).read()
     assert differences[0].unified_diff == expected_diff
+
+def test_compare_non_existing(monkeypatch, bzip1):
+    monkeypatch.setattr(Config, 'new_file', True)
+    difference = bzip1.compare(NonExistingFile('/nonexisting', bzip1))
+    assert difference.source2 == '/nonexisting'
diff --git a/tests/comparators/test_cpio.py b/tests/comparators/test_cpio.py
index 12682e9..d9dd8da 100644
--- a/tests/comparators/test_cpio.py
+++ b/tests/comparators/test_cpio.py
@@ -21,8 +21,9 @@
 import os.path
 import pytest
 from diffoscope.comparators import specialize
-from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
 from diffoscope.comparators.cpio import CpioFile
+from diffoscope.config import Config
 
 TEST_FILE1_PATH = os.path.join(os.path.dirname(__file__), '../data/test1.cpio')
 TEST_FILE2_PATH = os.path.join(os.path.dirname(__file__), '../data/test2.cpio')
@@ -61,3 +62,9 @@ def test_compressed_files(differences):
     assert differences[2].source2 == 'dir/text'
     expected_diff = open(os.path.join(os.path.dirname(__file__), '../data/text_ascii_expected_diff')).read()
     assert differences[2].unified_diff == expected_diff
+
+def test_compare_non_existing(monkeypatch, cpio1):
+    monkeypatch.setattr(Config.general, 'new_file', True)
+    difference = cpio1.compare(NonExistingFile('/nonexisting', cpio1))
+    assert difference.source2 == '/nonexisting'
+    assert difference.details[-1].source2 == '/dev/null'
diff --git a/tests/comparators/test_deb.py b/tests/comparators/test_deb.py
index 7000521..63dbd94 100644
--- a/tests/comparators/test_deb.py
+++ b/tests/comparators/test_deb.py
@@ -22,8 +22,9 @@ import os.path
 import pytest
 import diffoscope.comparators
 from diffoscope.comparators import specialize
-from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
 from diffoscope.comparators.deb import DebFile, Md5sumsFile, DebDataTarFile
+from diffoscope.config import Config
 
 TEST_FILE1_PATH = os.path.join(os.path.dirname(__file__), '../data/test1.deb')
 TEST_FILE2_PATH = os.path.join(os.path.dirname(__file__), '../data/test2.deb')
@@ -104,3 +105,9 @@ def test_skip_comparison_of_known_identical_files(deb1, deb2, monkeypatch):
     monkeypatch.setattr(diffoscope.comparators, 'compare_files', probe)
     deb1.compare(deb2)
     assert './usr/share/doc/test/README.Debian' not in compared
+
+def test_compare_non_existing(monkeypatch, deb1):
+    monkeypatch.setattr(Config.general, 'new_file', True)
+    difference = deb1.compare(NonExistingFile('/nonexisting', deb1))
+    assert difference.source2 == '/nonexisting'
+    assert difference.details[-1].source2 == '/dev/null'
diff --git a/tests/comparators/test_debian.py b/tests/comparators/test_debian.py
index 215f7ed..a6adeb2 100644
--- a/tests/comparators/test_debian.py
+++ b/tests/comparators/test_debian.py
@@ -24,8 +24,9 @@ import os.path
 import shutil
 import pytest
 from diffoscope.comparators import specialize
-from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
 from diffoscope.comparators.debian import DotChangesFile
+from diffoscope.config import Config
 from diffoscope.presenters.text import output_text
 
 TEST_DOT_CHANGES_FILE1_PATH = os.path.join(os.path.dirname(__file__), '../data/test1.changes')
@@ -71,3 +72,10 @@ def test_description(differences):
 
 def test_internal_diff(differences):
     assert differences[2].source1 == 'test_1_all.deb'
+
+def test_compare_non_existing(monkeypatch, dot_changes1):
+    monkeypatch.setattr(Config.general, 'new_file', True)
+    difference = dot_changes1.compare(NonExistingFile('/nonexisting', dot_changes1))
+    output_text(difference, print_func=print)
+    assert difference.source2 == '/nonexisting'
+    assert difference.details[-1].source2 == '/dev/null'
diff --git a/tests/comparators/test_elf.py b/tests/comparators/test_elf.py
index fd38289..23e68f8 100644
--- a/tests/comparators/test_elf.py
+++ b/tests/comparators/test_elf.py
@@ -21,8 +21,9 @@
 import os.path
 import pytest
 from diffoscope.comparators import specialize
-from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
 from diffoscope.comparators.elf import ElfFile, StaticLibFile
+from diffoscope.config import Config
 
 TEST_OBJ1_PATH = os.path.join(os.path.dirname(__file__), '../data/test1.o')
 TEST_OBJ2_PATH = os.path.join(os.path.dirname(__file__), '../data/test2.o')
@@ -46,6 +47,11 @@ def test_obj_no_differences(obj1):
 def obj_differences(obj1, obj2):
     return obj1.compare(obj2).details
 
+def test_obj_compare_non_existing(monkeypatch, obj1):
+    monkeypatch.setattr(Config, 'new_file', True)
+    difference = obj1.compare(NonExistingFile('/nonexisting', obj1))
+    assert difference.source2 == '/nonexisting'
+
 def test_diff(obj_differences):
     assert len(obj_differences) == 1
     expected_diff = open(os.path.join(os.path.dirname(__file__), '../data/elf_obj_expected_diff')).read()
@@ -81,3 +87,8 @@ def test_lib_differences(lib_differences):
     assert 'objdump' in lib_differences[1].source1
     expected_objdump_diff = open(os.path.join(os.path.dirname(__file__), '../data/elf_lib_objdump_expected_diff')).read()
     assert lib_differences[1].unified_diff == expected_objdump_diff
+
+def test_lib_compare_non_existing(monkeypatch, lib1):
+    monkeypatch.setattr(Config, 'new_file', True)
+    difference = lib1.compare(NonExistingFile('/nonexisting', lib1))
+    assert difference.source2 == '/nonexisting'
diff --git a/tests/comparators/test_fonts.py b/tests/comparators/test_fonts.py
index 763670b..6d4ea09 100644
--- a/tests/comparators/test_fonts.py
+++ b/tests/comparators/test_fonts.py
@@ -21,8 +21,9 @@
 import os.path
 import pytest
 from diffoscope.comparators import specialize
-from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
 from diffoscope.comparators.fonts import TtfFile
+from diffoscope.config import Config
 from conftest import tool_missing
 
 TEST_FILE1_PATH = os.path.join(os.path.dirname(__file__), '../data/Samyak-Malayalam1.ttf')
@@ -51,3 +52,8 @@ def differences(ttf1, ttf2):
 def test_diff(differences):
     expected_diff = open(os.path.join(os.path.dirname(__file__), '../data/ttf_expected_diff')).read()
     assert differences[0].unified_diff == expected_diff
+
+def test_compare_non_existing(monkeypatch, ttf1):
+    monkeypatch.setattr(Config, 'new_file', True)
+    difference = ttf1.compare(NonExistingFile('/nonexisting', ttf1))
+    assert difference.source2 == '/nonexisting'
diff --git a/tests/comparators/test_gettext.py b/tests/comparators/test_gettext.py
index f7e9f20..1ea2cb5 100644
--- a/tests/comparators/test_gettext.py
+++ b/tests/comparators/test_gettext.py
@@ -22,8 +22,9 @@ import codecs
 import os.path
 import pytest
 from diffoscope.comparators import specialize
-from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
 from diffoscope.comparators.gettext import MoFile
+from diffoscope.config import Config
 
 TEST_FILE1_PATH = os.path.join(os.path.dirname(__file__), '../data/test1.mo')
 TEST_FILE2_PATH = os.path.join(os.path.dirname(__file__), '../data/test2.mo')
@@ -63,3 +64,8 @@ def test_charsets(mo_no_charset, mo_iso8859_1):
     difference = mo_no_charset.compare(mo_iso8859_1)
     expected_diff = codecs.open(os.path.join(os.path.dirname(__file__), '../data/mo_charsets_expected_diff'), encoding='utf-8').read()
     assert difference.details[0].unified_diff == expected_diff
+
+def test_compare_non_existing(monkeypatch, mo1):
+    monkeypatch.setattr(Config, 'new_file', True)
+    difference = mo1.compare(NonExistingFile('/nonexisting', mo1))
+    assert difference.source2 == '/nonexisting'
diff --git a/tests/comparators/test_gzip.py b/tests/comparators/test_gzip.py
index fdde2ca..a094663 100644
--- a/tests/comparators/test_gzip.py
+++ b/tests/comparators/test_gzip.py
@@ -22,8 +22,9 @@ import os.path
 import shutil
 import pytest
 from diffoscope.comparators import specialize
-from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
 from diffoscope.comparators.gzip import GzipFile
+from diffoscope.config import Config
 
 TEST_FILE1_PATH = os.path.join(os.path.dirname(__file__), '../data/test1.gz')
 TEST_FILE2_PATH = os.path.join(os.path.dirname(__file__), '../data/test2.gz')
@@ -71,3 +72,9 @@ def test_content_source_without_extension(tmpdir):
 def test_content_diff(differences):
     expected_diff = open(os.path.join(os.path.dirname(__file__), '../data/text_ascii_expected_diff')).read()
     assert differences[1].unified_diff == expected_diff
+
+def test_compare_non_existing(monkeypatch, gzip1):
+    monkeypatch.setattr(Config.general, 'new_file', True)
+    difference = gzip1.compare(NonExistingFile('/nonexisting', gzip1))
+    assert difference.source2 == '/nonexisting'
+    assert difference.details[-1].source2 == '/dev/null'
diff --git a/tests/comparators/test_ipk.py b/tests/comparators/test_ipk.py
index ac14747..03882d9 100644
--- a/tests/comparators/test_ipk.py
+++ b/tests/comparators/test_ipk.py
@@ -21,8 +21,9 @@
 import os.path
 import pytest
 from diffoscope.comparators import specialize
-from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
 from diffoscope.comparators.ipk import IpkFile
+from diffoscope.config import Config
 
 TEST_FILE1_PATH = os.path.join(os.path.dirname(__file__), '../data/base-files_157-r45695_ar71xx.ipk')
 TEST_FILE2_PATH = os.path.join(os.path.dirname(__file__), '../data/base-files_157-r45918_ar71xx.ipk')
@@ -54,3 +55,9 @@ def test_metadata(differences):
 def test_compressed_files(differences):
     assert differences[1].details[1].source1 == './control.tar.gz'
     assert differences[1].details[2].source1 == './data.tar.gz'
+
+def test_compare_non_existing(monkeypatch, ipk1):
+    monkeypatch.setattr(Config.general, 'new_file', True)
+    difference = ipk1.compare(NonExistingFile('/nonexisting', ipk1))
+    assert difference.source2 == '/nonexisting'
+    assert difference.details[-1].source2 == '/dev/null'
diff --git a/tests/comparators/test_iso9660.py b/tests/comparators/test_iso9660.py
index b0ed74a..00f68b2 100644
--- a/tests/comparators/test_iso9660.py
+++ b/tests/comparators/test_iso9660.py
@@ -21,8 +21,9 @@
 import os.path
 import pytest
 from diffoscope.comparators import specialize
-from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
 from diffoscope.comparators.iso9660 import Iso9660File
+from diffoscope.config import Config
 from conftest import tool_missing
 
 TEST_FILE1_PATH = os.path.join(os.path.dirname(__file__), '../data/test1.iso')
@@ -69,3 +70,9 @@ def test_compressed_files(differences):
     assert differences[3].source2 == 'text'
     expected_diff = open(os.path.join(os.path.dirname(__file__), '../data/text_ascii_expected_diff')).read()
     assert differences[3].unified_diff == expected_diff
+
+def test_compare_non_existing(monkeypatch, iso1):
+    monkeypatch.setattr(Config.general, 'new_file', True)
+    difference = iso1.compare(NonExistingFile('/nonexisting', iso1))
+    assert difference.source2 == '/nonexisting'
+    assert difference.details[-1].source2 == '/dev/null'
diff --git a/tests/comparators/test_java.py b/tests/comparators/test_java.py
index 967a6ea..fdbc2a7 100644
--- a/tests/comparators/test_java.py
+++ b/tests/comparators/test_java.py
@@ -21,8 +21,9 @@
 import os.path
 import pytest
 from diffoscope.comparators import specialize
-from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
 from diffoscope.comparators.java import ClassFile
+from diffoscope.config import Config
 
 TEST_FILE1_PATH = os.path.join(os.path.dirname(__file__), '../data/Test1.class')
 TEST_FILE2_PATH = os.path.join(os.path.dirname(__file__), '../data/Test2.class')
@@ -49,3 +50,8 @@ def differences(class1, class2):
 def test_diff(differences):
     expected_diff = open(os.path.join(os.path.dirname(__file__), '../data/class_expected_diff')).read()
     assert differences[0].unified_diff == expected_diff
+
+def test_compare_non_existing(monkeypatch, class1):
+    monkeypatch.setattr(Config, 'new_file', True)
+    difference = class1.compare(NonExistingFile('/nonexisting', class1))
+    assert difference.source2 == '/nonexisting'
diff --git a/tests/comparators/test_mono.py b/tests/comparators/test_mono.py
index da87f3d..62d5b57 100644
--- a/tests/comparators/test_mono.py
+++ b/tests/comparators/test_mono.py
@@ -21,8 +21,9 @@
 import os.path
 import pytest
 from diffoscope.comparators import specialize
-from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
 from diffoscope.comparators.mono import MonoExeFile
+from diffoscope.config import Config
 from conftest import tool_missing
 
 # these were generated with:
@@ -56,3 +57,8 @@ def differences(exe1, exe2):
 def test_diff(differences):
     expected_diff = open(os.path.join(os.path.dirname(__file__), '../data/pe_expected_diff')).read()
     assert differences[0].unified_diff == expected_diff
+
+def test_compare_non_existing(monkeypatch, exe1):
+    monkeypatch.setattr(Config, 'new_file', True)
+    difference = exe1.compare(NonExistingFile('/nonexisting', exe1))
+    assert difference.source2 == '/nonexisting'
diff --git a/tests/comparators/test_pdf.py b/tests/comparators/test_pdf.py
index 734201d..2a5b269 100644
--- a/tests/comparators/test_pdf.py
+++ b/tests/comparators/test_pdf.py
@@ -21,8 +21,9 @@
 import os.path
 import pytest
 from diffoscope.comparators import specialize
-from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
 from diffoscope.comparators.pdf import PdfFile
+from diffoscope.config import Config
 from conftest import tool_missing
 
 TEST_FILE1_PATH = os.path.join(os.path.dirname(__file__), '../data/test1.pdf')
@@ -58,3 +59,8 @@ def test_text_diff(differences):
 def test_internal_diff(differences):
     expected_diff = open(os.path.join(os.path.dirname(__file__), '../data/pdf_internal_expected_diff')).read()
     assert differences[1].unified_diff == expected_diff
+
+def test_compare_non_existing(monkeypatch, pdf1):
+    monkeypatch.setattr(Config, 'new_file', True)
+    difference = pdf1.compare(NonExistingFile('/nonexisting', pdf1))
+    assert difference.source2 == '/nonexisting'
diff --git a/tests/comparators/test_png.py b/tests/comparators/test_png.py
index fcdb7f1..f157f1e 100644
--- a/tests/comparators/test_png.py
+++ b/tests/comparators/test_png.py
@@ -21,8 +21,9 @@
 import os.path
 import pytest
 from diffoscope.comparators import specialize
-from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
 from diffoscope.comparators.png import PngFile
+from diffoscope.config import Config
 from conftest import tool_missing
 
 TEST_FILE1_PATH = os.path.join(os.path.dirname(__file__), '../data/test1.png')
@@ -51,3 +52,8 @@ def differences(png1, png2):
 def test_diff(differences):
     expected_diff = open(os.path.join(os.path.dirname(__file__), '../data/png_expected_diff')).read()
     assert differences[0].unified_diff == expected_diff
+
+def test_compare_non_existing(monkeypatch, png1):
+    monkeypatch.setattr(Config, 'new_file', True)
+    difference = png1.compare(NonExistingFile('/nonexisting', png1))
+    assert difference.source2 == '/nonexisting'
diff --git a/tests/comparators/test_rpm.py b/tests/comparators/test_rpm.py
index 80b8b26..b75a6ff 100644
--- a/tests/comparators/test_rpm.py
+++ b/tests/comparators/test_rpm.py
@@ -21,8 +21,9 @@
 import os.path
 import pytest
 from diffoscope.comparators import specialize
-from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
 from diffoscope.comparators.rpm import RpmFile
+from diffoscope.config import Config
 from conftest import tool_missing
 
 TEST_FILE1_PATH = os.path.join(os.path.dirname(__file__), '../data/test1.rpm')
@@ -66,3 +67,9 @@ def test_content(differences):
     assert differences[1].details[1].source1 == './dir/text'
     expected_diff = open(os.path.join(os.path.dirname(__file__), '../data/text_ascii_expected_diff')).read()
     assert differences[1].details[1].unified_diff == expected_diff
+
+def test_compare_non_existing(monkeypatch, rpm1):
+    monkeypatch.setattr(Config.general, 'new_file', True)
+    difference = rpm1.compare(NonExistingFile('/nonexisting', rpm1))
+    assert difference.source2 == '/nonexisting'
+    assert difference.details[-1].source2 == '/dev/null'
diff --git a/tests/comparators/test_sqlite.py b/tests/comparators/test_sqlite.py
index 6083fac..fa7207e 100644
--- a/tests/comparators/test_sqlite.py
+++ b/tests/comparators/test_sqlite.py
@@ -21,8 +21,9 @@
 import os.path
 import pytest
 from diffoscope.comparators import specialize
-from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
 from diffoscope.comparators.sqlite import Sqlite3Database
+from diffoscope.config import Config
 from conftest import tool_missing
 
 TEST_FILE1_PATH = os.path.join(os.path.dirname(__file__), '../data/test1.sqlite3')
@@ -51,3 +52,8 @@ def differences(sqlite3db1, sqlite3db2):
 def test_diff(differences):
     expected_diff = open(os.path.join(os.path.dirname(__file__), '../data/sqlite3_expected_diff')).read()
     assert differences[0].unified_diff == expected_diff
+
+def test_compare_non_existing(monkeypatch, sqlite3db1):
+    monkeypatch.setattr(Config.general, 'new_file', True)
+    difference = sqlite3db1.compare(NonExistingFile('/nonexisting', sqlite3db1))
+    assert difference.source2 == '/nonexisting'
diff --git a/tests/comparators/test_squashfs.py b/tests/comparators/test_squashfs.py
index d5f43e9..ce10acb 100644
--- a/tests/comparators/test_squashfs.py
+++ b/tests/comparators/test_squashfs.py
@@ -22,8 +22,9 @@ import os.path
 import pwd
 import pytest
 from diffoscope.comparators import specialize
-from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
 from diffoscope.comparators.squashfs import SquashfsFile
+from diffoscope.config import Config
 from conftest import tool_missing, try_except
 
 TEST_FILE1_PATH = os.path.join(os.path.dirname(__file__), '../data/test1.squashfs')
@@ -77,3 +78,9 @@ def test_compressed_files(differences):
     assert differences[3].source2 == '/text'
     expected_diff = open(os.path.join(os.path.dirname(__file__), '../data/text_ascii_expected_diff')).read()
     assert differences[3].unified_diff == expected_diff
+
+def test_compare_non_existing(monkeypatch, squashfs1):
+    monkeypatch.setattr(Config.general, 'new_file', True)
+    difference = squashfs1.compare(NonExistingFile('/nonexisting', squashfs1))
+    assert difference.source2 == '/nonexisting'
+    assert difference.details[-1].source2 == '/dev/null'
diff --git a/tests/comparators/test_tar.py b/tests/comparators/test_tar.py
index ea765a7..b68af14 100644
--- a/tests/comparators/test_tar.py
+++ b/tests/comparators/test_tar.py
@@ -21,8 +21,9 @@
 import os.path
 import pytest
 from diffoscope.comparators import specialize
-from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
 from diffoscope.comparators.tar import TarFile
+from diffoscope.config import Config
 
 TEST_FILE1_PATH = os.path.join(os.path.dirname(__file__), '../data/test1.tar')
 TEST_FILE2_PATH = os.path.join(os.path.dirname(__file__), '../data/test2.tar')
@@ -62,3 +63,9 @@ def test_text_file(differences):
     assert differences[2].source2 == 'dir/text'
     expected_diff = open(os.path.join(os.path.dirname(__file__), '../data/text_ascii_expected_diff')).read()
     assert differences[2].unified_diff == expected_diff
+
+def test_compare_non_existing(monkeypatch, tar1):
+    monkeypatch.setattr(Config.general, 'new_file', True)
+    difference = tar1.compare(NonExistingFile('/nonexisting', tar1))
+    assert difference.source2 == '/nonexisting'
+    assert difference.details[-1].source2 == '/dev/null'
diff --git a/tests/comparators/test_text.py b/tests/comparators/test_text.py
index 98a7528..cf71108 100644
--- a/tests/comparators/test_text.py
+++ b/tests/comparators/test_text.py
@@ -22,7 +22,8 @@ import codecs
 import os.path
 import pytest
 from diffoscope.comparators import specialize
-from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
+from diffoscope.config import Config
 
 @pytest.fixture
 def ascii1():
@@ -74,3 +75,8 @@ def test_difference_between_iso88591_and_unicode_only(iso8859, tmpdir):
     difference = iso8859.compare(utf8)
     assert difference.unified_diff is None
     assert difference.details[0].source1 == 'encoding'
+
+def test_compare_non_existing(monkeypatch, ascii1):
+    monkeypatch.setattr(Config.general, 'new_file', True)
+    difference = ascii1.compare(NonExistingFile('/nonexisting', ascii1))
+    assert difference.source2 == '/nonexisting'
diff --git a/tests/comparators/test_utils.py b/tests/comparators/test_utils.py
index 68b51f0..da70510 100644
--- a/tests/comparators/test_utils.py
+++ b/tests/comparators/test_utils.py
@@ -23,6 +23,7 @@ import os.path
 import pytest
 from diffoscope.comparators import specialize
 from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.config import Config
 
 @pytest.fixture
 def fuzzy_tar1():
@@ -48,3 +49,25 @@ def test_fuzzy_matching_only_once(fuzzy_tar1, fuzzy_tar3):
     differences = fuzzy_tar1.compare(fuzzy_tar3).details
     assert len(differences) == 2
     expected_diff = codecs.open(os.path.join(os.path.dirname(__file__), '../data/text_iso8859_expected_diff'), encoding='utf-8').read()
+
+ at pytest.fixture
+def fuzzy_tar_in_tar1():
+    return specialize(FilesystemFile(os.path.join(os.path.dirname(__file__), '../data/fuzzy-tar-in-tar1.tar')))
+
+ at pytest.fixture
+def fuzzy_tar_in_tar2():
+    return specialize(FilesystemFile(os.path.join(os.path.dirname(__file__), '../data/fuzzy-tar-in-tar2.tar')))
+
+def test_no_fuzzy_matching(monkeypatch, fuzzy_tar_in_tar1, fuzzy_tar_in_tar2):
+    monkeypatch.setattr(Config, 'fuzzy_threshold', 0)
+    difference = fuzzy_tar_in_tar1.compare(fuzzy_tar_in_tar2)
+    assert len(difference.details) == 1
+    assert difference.details[0].source1 == 'metadata'
+
+def test_no_fuzzy_matching_new_file(monkeypatch, fuzzy_tar_in_tar1, fuzzy_tar_in_tar2):
+    monkeypatch.setattr(Config, 'fuzzy_threshold', 0)
+    monkeypatch.setattr(Config, 'new_file', True)
+    difference = fuzzy_tar_in_tar1.compare(fuzzy_tar_in_tar2)
+    assert len(difference.details) == 3
+    assert difference.details[1].source2 == '/dev/null'
+    assert difference.details[2].source1 == '/dev/null'
diff --git a/tests/comparators/test_xz.py b/tests/comparators/test_xz.py
index fde39f6..1d26a06 100644
--- a/tests/comparators/test_xz.py
+++ b/tests/comparators/test_xz.py
@@ -22,8 +22,9 @@ import os.path
 import shutil
 import pytest
 from diffoscope.comparators import specialize
-from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
 from diffoscope.comparators.xz import XzFile
+from diffoscope.config import Config
 
 TEST_FILE1_PATH = os.path.join(os.path.dirname(__file__), '../data/test1.xz')
 TEST_FILE2_PATH = os.path.join(os.path.dirname(__file__), '../data/test2.xz')
@@ -65,3 +66,9 @@ def test_content_source_without_extension(tmpdir):
 def test_content_diff(differences):
     expected_diff = open(os.path.join(os.path.dirname(__file__), '../data/text_ascii_expected_diff')).read()
     assert differences[0].unified_diff == expected_diff
+
+def test_compare_non_existing(monkeypatch, xz1):
+    monkeypatch.setattr(Config.general, 'new_file', True)
+    difference = xz1.compare(NonExistingFile('/nonexisting', xz1))
+    assert difference.source2 == '/nonexisting'
+    assert difference.details[-1].source2 == '/dev/null'
diff --git a/tests/comparators/test_zip.py b/tests/comparators/test_zip.py
index 356e6bd..4be581a 100644
--- a/tests/comparators/test_zip.py
+++ b/tests/comparators/test_zip.py
@@ -21,8 +21,9 @@
 import os.path
 import pytest
 from diffoscope.comparators import specialize
-from diffoscope.comparators.binary import FilesystemFile
+from diffoscope.comparators.binary import FilesystemFile, NonExistingFile
 from diffoscope.comparators.zip import ZipFile
+from diffoscope.config import Config
 from conftest import tool_missing
 
 TEST_FILE1_PATH = os.path.join(os.path.dirname(__file__), '../data/test1.zip')
@@ -58,3 +59,9 @@ def test_compressed_files(differences):
     assert differences[1].source2 == 'dir/text'
     expected_diff = open(os.path.join(os.path.dirname(__file__), '../data/text_ascii_expected_diff')).read()
     assert differences[1].unified_diff == expected_diff
+
+def test_compare_non_existing(monkeypatch, zip1):
+    monkeypatch.setattr(Config.general, 'new_file', True)
+    difference = zip1.compare(NonExistingFile('/nonexisting', zip1))
+    assert difference.source2 == '/nonexisting'
+    assert difference.details[-1].source2 == '/dev/null'
diff --git a/tests/data/fuzzy-tar-in-tar1.tar b/tests/data/fuzzy-tar-in-tar1.tar
new file mode 100644
index 0000000..ca9fc33
Binary files /dev/null and b/tests/data/fuzzy-tar-in-tar1.tar differ
diff --git a/tests/data/fuzzy-tar-in-tar2.tar b/tests/data/fuzzy-tar-in-tar2.tar
new file mode 100644
index 0000000..f243632
Binary files /dev/null and b/tests/data/fuzzy-tar-in-tar2.tar differ
diff --git a/tests/test_main.py b/tests/test_main.py
index acc963f..2509190 100644
--- a/tests/test_main.py
+++ b/tests/test_main.py
@@ -29,3 +29,31 @@ def test_non_existing_files(capsys):
     out, err = capsys.readouterr()
     assert '/nonexisting1: No such file or directory' in err
     assert '/nonexisting2: No such file or directory' in err
+
+def test_non_existing_left_with_new_file(capsys):
+    args = ['--new-file', '/nonexisting1', __file__]
+    with pytest.raises(SystemExit) as excinfo:
+        main(args)
+    assert excinfo.value.code == 1
+    out, err = capsys.readouterr()
+    assert '--- /nonexisting1' in out
+    assert ('+++ %s' % __file__) in out
+
+def test_non_existing_right_with_new_file(capsys):
+    args = ['--new-file', __file__, '/nonexisting2']
+    with pytest.raises(SystemExit) as excinfo:
+        main(args)
+    assert excinfo.value.code == 1
+    out, err = capsys.readouterr()
+    assert ('--- %s' % __file__) in out
+    assert '+++ /nonexisting2' in out
+
+def test_non_existing_files_with_new_file(capsys):
+    args = ['--new-file', '/nonexisting1', '/nonexisting2']
+    with pytest.raises(SystemExit) as excinfo:
+        main(args)
+    assert excinfo.value.code == 1
+    out, err = capsys.readouterr()
+    assert '--- /nonexisting1' in out
+    assert '+++ /nonexisting2' in out
+    assert 'Trying to compare two non-existing files.' in out

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/reproducible/diffoscope.git



More information about the Reproducible-commits mailing list