Importlib was not matching import's handling of .pyc files where it had less
then 8 bytes total in the file.

Fixes issues 7361 & 7875.
diff --git a/Lib/importlib/test/source/test_file_loader.py b/Lib/importlib/test/source/test_file_loader.py
index 32a6955..ae4b185 100644
--- a/Lib/importlib/test/source/test_file_loader.py
+++ b/Lib/importlib/test/source/test_file_loader.py
@@ -113,42 +113,116 @@
 
 class BadBytecodeTest(unittest.TestCase):
 
-    """But there are several things about the bytecode which might lead to the
-    source being preferred. If the magic number differs from what the
-    interpreter uses, then the source is used with the bytecode regenerated.
-    If the timestamp is older than the modification time for the source then
-    the bytecode is not used [bad timestamp].
-
-    But if the marshal data is bad, even if the magic number and timestamp
-    work, a ValueError is raised and the source is not used [bad marshal].
-
-    The case of not being able to write out the bytecode must also be handled
-    as it's possible it was made read-only. In that instance the attempt to
-    write the bytecode should fail silently [bytecode read-only].
-
-    """
-
     def import_(self, file, module_name):
         loader = _bootstrap._PyPycFileLoader(module_name, file, False)
         module = loader.load_module(module_name)
         self.assertTrue(module_name in sys.modules)
 
-    # [bad magic]
+    def manipulate_bytecode(self, name, mapping, manipulator, *,
+                            del_source=False):
+        """Manipulate the bytecode of a module by passing it into a callable
+        that returns what to use as the new bytecode."""
+        try:
+            del sys.modules['_temp']
+        except KeyError:
+            pass
+        py_compile.compile(mapping[name])
+        bytecode_path = source_util.bytecode_path(mapping[name])
+        with open(bytecode_path, 'rb') as file:
+            bc = file.read()
+        new_bc = manipulator(bc)
+        with open(bytecode_path, 'wb') as file:
+            if new_bc:
+                file.write(new_bc)
+        if del_source:
+            os.unlink(mapping[name])
+        return bytecode_path
+
+    @source_util.writes_bytecode_files
+    def test_empty_file(self):
+        # When a .pyc is empty, regenerate it if possible, else raise
+        # ImportError.
+        with source_util.create_modules('_temp') as mapping:
+            bc_path = self.manipulate_bytecode('_temp', mapping,
+                                                lambda bc: None)
+            self.import_(mapping['_temp'], '_temp')
+            with open(bc_path, 'rb') as file:
+                self.assertGreater(len(file.read()), 8)
+            self.manipulate_bytecode('_temp', mapping, lambda bc: None,
+                                        del_source=True)
+            with self.assertRaises(ImportError):
+                self.import_(mapping['_temp'], '_temp')
+
+    @source_util.writes_bytecode_files
+    def test_partial_magic(self):
+        # When their are less than 4 bytes to a .pyc, regenerate it if
+        # possible, else raise ImportError.
+        with source_util.create_modules('_temp') as mapping:
+            bc_path = self.manipulate_bytecode('_temp', mapping,
+                                                lambda bc: bc[:3])
+            self.import_(mapping['_temp'], '_temp')
+            with open(bc_path, 'rb') as file:
+                self.assertGreater(len(file.read()), 8)
+            self.manipulate_bytecode('_temp', mapping, lambda bc: bc[:3],
+                                        del_source=True)
+            with self.assertRaises(ImportError):
+                self.import_(mapping['_temp'], '_temp')
+
+    @source_util.writes_bytecode_files
+    def test_magic_only(self):
+        # When there is only the magic number, regenerate the .pyc if possible,
+        # else raise EOFError.
+        with source_util.create_modules('_temp') as mapping:
+            bc_path = self.manipulate_bytecode('_temp', mapping,
+                                                lambda bc: bc[:4])
+            self.import_(mapping['_temp'], '_temp')
+            with open(bc_path, 'rb') as file:
+                self.assertGreater(len(file.read()), 8)
+            self.manipulate_bytecode('_temp', mapping, lambda bc: bc[:4],
+                                        del_source=True)
+            with self.assertRaises(EOFError):
+                self.import_(mapping['_temp'], '_temp')
+
+    @source_util.writes_bytecode_files
+    def test_partial_timestamp(self):
+        # When the timestamp is partial, regenerate the .pyc, else
+        # raise EOFError.
+        with source_util.create_modules('_temp') as mapping:
+            bc_path = self.manipulate_bytecode('_temp', mapping,
+                                                lambda bc: bc[:7])
+            self.import_(mapping['_temp'], '_temp')
+            with open(bc_path, 'rb') as file:
+                self.assertGreater(len(file.read()), 8)
+            self.manipulate_bytecode('_temp', mapping, lambda bc: bc[:7],
+                                        del_source=True)
+            with self.assertRaises(EOFError):
+                self.import_(mapping['_temp'], '_temp')
+
+    @source_util.writes_bytecode_files
+    def test_no_marshal(self):
+        # When there is only the magic number and timestamp, raise EOFError.
+        with source_util.create_modules('_temp') as mapping:
+            bc_path = self.manipulate_bytecode('_temp', mapping,
+                                                lambda bc: bc[:8])
+            with self.assertRaises(EOFError):
+                self.import_(mapping['_temp'], '_temp')
+
     @source_util.writes_bytecode_files
     def test_bad_magic(self):
+        # When the magic number is different, the bytecode should be
+        # regenerated.
         with source_util.create_modules('_temp') as mapping:
-            py_compile.compile(mapping['_temp'])
-            bytecode_path = source_util.bytecode_path(mapping['_temp'])
-            with open(bytecode_path, 'r+b') as bytecode_file:
-                bytecode_file.seek(0)
-                bytecode_file.write(b'\x00\x00\x00\x00')
+            bc_path = self.manipulate_bytecode('_temp', mapping,
+                                    lambda bc: b'\x00\x00\x00\x00' + bc[4:])
             self.import_(mapping['_temp'], '_temp')
-            with open(bytecode_path, 'rb') as bytecode_file:
+            with open(bc_path, 'rb') as bytecode_file:
                 self.assertEqual(bytecode_file.read(4), imp.get_magic())
 
     # [bad timestamp]
     @source_util.writes_bytecode_files
     def test_bad_bytecode(self):
+        # When the timestamp is older than the source, bytecode should be
+        # regenerated.
         zeros = b'\x00\x00\x00\x00'
         with source_util.create_modules('_temp') as mapping:
             py_compile.compile(mapping['_temp'])
@@ -166,6 +240,7 @@
     # [bad marshal]
     @source_util.writes_bytecode_files
     def test_bad_marshal(self):
+        # Bad marshal data should raise a ValueError.
         with source_util.create_modules('_temp') as mapping:
             bytecode_path = source_util.bytecode_path(mapping['_temp'])
             source_mtime = os.path.getmtime(mapping['_temp'])
@@ -181,6 +256,7 @@
     # [bytecode read-only]
     @source_util.writes_bytecode_files
     def test_read_only_bytecode(self):
+        # When bytecode is read-only but should be rewritten, fail silently.
         with source_util.create_modules('_temp') as mapping:
             # Create bytecode that will need to be re-created.
             py_compile.compile(mapping['_temp'])
@@ -201,8 +277,7 @@
 
 def test_main():
     from test.support import run_unittest
-    run_unittest(SimpleTest, DontWriteBytecodeTest, BadDataTest,
-                 SourceBytecodeInteraction, BadBytecodeTest)
+    run_unittest(SimpleTest, BadBytecodeTest)
 
 
 if __name__ == '__main__':