def test_main(self, mock_stdout, mock_resolve):
     """Test demo main function."""
     # Mock output of abspath to avoid FileNotFoundError.
     mock_resolve.return_value = os.path.normpath('src/ch06/c1files')
     current_dir = os.getcwd()
     # Test using test files.
     fakefile = os.path.join(current_dir, 'tests/data/ch06/fake_mono.docx')
     cipherfile = os.path.join(current_dir,
                               'tests/data/ch06/cipher_mono.docx')
     output_file = os.path.join(current_dir, 'tests/data/ch06/output.docx')
     invisible_ink_mono.main(fakefile, cipherfile, output_file)
     self.assertTrue(os.path.exists(output_file))
     output_text = invisible_ink.get_text(output_file)
     self.assertEqual(constants.MAIN_TEST_MONO, output_text)
     os.remove(output_file)
     # Test printed output.
     with open(
             os.path.normpath(
                 'tests/data/ch06/main/invisible_ink_mono.txt'),
             'r') as file:
         file_data = ''.join(file.readlines())
     self.assertEqual(mock_stdout.getvalue(), file_data)
     # Test using default files.
     invisible_ink_mono.main()
     output_file = os.path.normpath('src/ch06/c1files/DearInternet.docx')
     self.assertTrue(os.path.exists(output_file))
     output_text = invisible_ink.get_text(output_file)
     self.assertEqual(constants.MAIN_DEFAULT_MONO, output_text)
     os.remove(output_file)
 def test_check_fit(self):
     """Test check_fit."""
     fakefile = os.path.normpath('tests/data/ch06/fake_mono.docx')
     cipherfile = os.path.normpath('tests/data/ch06/cipher_mono.docx')
     # Test that it doesn't need extra blanks.
     faketext = invisible_ink.get_text(fakefile, False)
     ciphertext = invisible_ink.get_text(cipherfile)
     blanks_needed = invisible_ink_mono.check_fit(faketext, ciphertext)
     self.assertEqual(blanks_needed, 0)
     # Test that it does need extra blanks.
     faketext = ['This is too short.']
     blanks_needed = invisible_ink_mono.check_fit(faketext, ciphertext)
     self.assertEqual(blanks_needed, 49)
     faketext.append('You would have to write a small novel to get it to '
                     'fit.')
     blanks_needed = invisible_ink_mono.check_fit(faketext, ciphertext)
     self.assertEqual(blanks_needed, 37)
     faketext.append('Filling in blanks is not as easy as it seems because '
                     'so few are in every sentence.')
     blanks_needed = invisible_ink_mono.check_fit(faketext, ciphertext)
     self.assertEqual(blanks_needed, 21)
     faketext.append('The use of small words helps, but it is not a good '
                     'way to go about being a super secret spy person.')
     blanks_needed = invisible_ink_mono.check_fit(faketext, ciphertext)
     self.assertEqual(blanks_needed, 0)
 def test_get_text(self):
     """Test get_text."""
     testfile = os.path.normpath('tests/data/ch06/fake.docx')
     # Test that it doesn't skip blanks.
     paragraphs = invisible_ink.get_text(testfile, skip_blank=False)
     self.assertEqual(paragraphs.count(''), 4)
     # Test that it does skip blanks.
     paragraphs = invisible_ink.get_text(testfile)
     self.assertEqual(paragraphs.count(''), 0)
     # Test that it read contents.
     self.assertEqual(constants.GET_TEST, paragraphs)
 def test_write_invisible(self):
     """Test write_invisible."""
     fakefile = os.path.normpath('tests/data/ch06/fake.docx')
     cipherfile = os.path.normpath('tests/data/ch06/cipher.docx')
     faketext = invisible_ink.get_text(fakefile, False)
     ciphertext = invisible_ink.get_text(cipherfile)
     current_dir = os.path.curdir
     # Test default template and filename.
     invisible_ink.write_invisible(faketext, ciphertext)
     output_file = os.path.join(current_dir, 'output.docx')
     self.assertTrue(os.path.exists(output_file))
     output_text = invisible_ink.get_text(output_file)
     all_text = [element for element in faketext if element != ''] + \
         ciphertext
     self.assertEqual(len(all_text), len(output_text))
     for line in output_text:
         self.assertIn(line, all_text)
     # Check color
     doc = Document(output_file)
     for paragraph in doc.paragraphs:
         if paragraph.text in ciphertext:
             for run in paragraph.runs:
                 self.assertEqual(run.font.color.rgb,
                                  RGBColor(255, 255, 255))
     os.remove(output_file)
     # Test custom template and filename.
     template_file = os.path.normpath('tests/data/ch06/template.docx')
     output_file = os.path.join(current_dir, 'letter.docx')
     invisible_ink.write_invisible(faketext, ciphertext, template_file,
                                   'letter.docx')
     self.assertTrue(os.path.exists(output_file))
     output_text = invisible_ink.get_text(output_file)
     all_text = [element for element in faketext if element != ''] + \
         ciphertext
     self.assertEqual(len(all_text), len(output_text))
     for line in output_text:
         self.assertIn(line, all_text)
     # Check color
     doc = Document(output_file)
     for paragraph in doc.paragraphs:
         if paragraph.text in ciphertext:
             for run in paragraph.runs:
                 self.assertEqual(run.font.color.rgb,
                                  RGBColor(255, 255, 255))
     os.remove(output_file)
     # Test error.
     faketext = invisible_ink.get_text(fakefile)
     error = ('3 more blanks are needed in the '
              'plaintext (fake) message.')
     with self.assertRaises(ValueError) as err:
         invisible_ink.write_invisible(faketext, ciphertext)
     self.assertEqual(error, str(err.exception))
 def test_check_blanks(self):
     """Test check_blanks."""
     fakefile = os.path.normpath('tests/data/ch06/fake.docx')
     cipherfile = os.path.normpath('tests/data/ch06/cipher.docx')
     # Test that it doesn't need extra blanks.
     faketext = invisible_ink.get_text(fakefile, False)
     ciphertext = invisible_ink.get_text(cipherfile)
     blanks_needed = invisible_ink.check_blanks(faketext, ciphertext)
     self.assertEqual(blanks_needed, 0)
     # Test that it does need extra blanks.
     faketext = invisible_ink.get_text(fakefile)
     blanks_needed = invisible_ink.check_blanks(faketext, ciphertext)
     self.assertEqual(blanks_needed, 3)
     faketext.append('')
     blanks_needed = invisible_ink.check_blanks(faketext, ciphertext)
     self.assertEqual(blanks_needed, 2)
     faketext.append('')
     blanks_needed = invisible_ink.check_blanks(faketext, ciphertext)
     self.assertEqual(blanks_needed, 1)
     faketext.append('')
     blanks_needed = invisible_ink.check_blanks(faketext, ciphertext)
     self.assertEqual(blanks_needed, 0)
Example #6
0
def main(fakefile: str = None,
         cipherfile: str = None,
         savepath: str = None) -> None:
    """Demonstrate the invisible ink writer.

    Demonstrate :func:`write_invisible`, but for testing,
    it is a basic wrapper function for :func:`write_invisible`.
    Embed **cipherfile** in **fakefile**'s whitespace.

    Args:
        fakefile (str): Path to .docx file with fake message.
            Defaults to ``./c1files/fake.docx``.
        cipherfile (str): Path to .docx file with real message.
            Defaults to ``./c1files/real.docx``.
        savepath (str): Path to .docx file for output.
            Defaults to ``./c1files/DearInternet.docx``.

    Returns:
         :py:obj:`None`. The contents of **cipherfile**'s text is embedded
         in **fakefile**'s whitespace and saved to **savepath**.

    """
    print('I can embed a hidden message in a .docx file\'s white space '
          'between letters by making the font\ncolor white. It\'s far less '
          'bulletproof than it sounds.\n')
    current_dir = Path('./c1files').resolve()
    if fakefile is None or cipherfile is None:
        fakefile = PurePath(current_dir).joinpath('fake.docx')
        cipherfile = PurePath(current_dir).joinpath('real.docx')
    if savepath is None:
        savepath = PurePath(current_dir).joinpath('DearInternet.docx')
    faketext = get_text(fakefile, False)
    ciphertext = get_text(cipherfile)
    write_invisible(faketext, ciphertext, None, savepath)
    print('Fin.\n')
    print('To read the hidden message, select the entire document and\n'
          'highlight it a darkish gray.')
    def test_main(self, mock_stdout, mock_abspath):
        """Test demo main function."""
        # FIXME: Why doesn't current_dir = os.path.abspath('./p1files') and
        #   fakefile = os.path.join(current_dir, 'fake.docx') used in
        #   src/ch06.p1_invisible_ink.main work with
        #   @unittest.mock.patch('src.ch06.p1_invisible_ink.os.path.abspath')
        #   and mock_abspath.return_value = os.path.normpath('src/ch06/p1files')
        #   used here?
        #   Using Python 3.6.8 and python-docx 0.8.10, fails with:
        #   ValueError: PackURI must begin with slash, got 'src/ch06/p1files'
        #   Had to use pathlib's Path and PurePath in p1_invisible_ink.main

        # Mock output of abspath to avoid FileNotFoundError.
        mock_abspath.return_value = os.path.normpath('src/ch06/p1files')
        current_dir = os.getcwd()
        # Test using test files.
        fakefile = os.path.join(current_dir, 'tests/data/ch06/fake.docx')
        cipherfile = os.path.join(current_dir, 'tests/data/ch06/cipher.docx')
        output_file = os.path.join(current_dir, 'tests/data/ch06/output.docx')
        faketext = invisible_ink.get_text(fakefile, False)
        ciphertext = invisible_ink.get_text(cipherfile)
        invisible_ink.main(fakefile, cipherfile, output_file)
        self.assertTrue(os.path.exists(output_file))
        output_text = invisible_ink.get_text(output_file)
        all_text = ([element
                     for element in faketext if element != ''] + ciphertext)
        self.assertEqual(len(all_text), len(output_text))
        for line in output_text:
            self.assertIn(line, all_text)
        os.remove(output_file)
        # Test printed output.
        with open(os.path.normpath('tests/data/ch06/main/invisible_ink.txt'),
                  'r') as file:
            file_data = ''.join(file.readlines())
        self.assertEqual(mock_stdout.getvalue(), file_data)
        # Test using default files.
        invisible_ink.main()
        fakefile = os.path.join(current_dir, 'src/ch06/p1files/fake.docx')
        cipherfile = os.path.join(current_dir, 'src/ch06/p1files/real.docx')
        output_file = os.path.normpath('src/ch06/p1files/LetterToUSDA.docx')
        faketext = invisible_ink.get_text(fakefile, False)
        ciphertext = invisible_ink.get_text(cipherfile)
        self.assertTrue(os.path.exists(output_file))
        output_text = invisible_ink.get_text(output_file)
        all_text = ([element
                     for element in faketext if element != ''] + ciphertext)
        self.assertEqual(len(all_text), len(output_text))
        for line in output_text:
            self.assertIn(line, all_text)
        os.remove(output_file)
 def test_write_invisible(self):
     """Test write_invisible."""
     fakefile = os.path.normpath('tests/data/ch06/fake_mono.docx')
     cipherfile = os.path.normpath('tests/data/ch06/cipher_mono.docx')
     faketext = invisible_ink.get_text(fakefile, False)
     ciphertext = invisible_ink.get_text(cipherfile)
     current_dir = os.path.curdir
     # Test default template and filename.
     invisible_ink_mono.write_invisible(faketext, ciphertext)
     output_file = os.path.join(current_dir, 'output.docx')
     self.assertTrue(os.path.exists(output_file))
     output_text = invisible_ink.get_text(output_file)
     self.assertListEqual(constants.WRITE_DEFAULT_MONO, output_text)
     # Check color
     paragraph_index, count = 0, 0
     cipher_len = sum(len(line) for line in ciphertext)
     doc = Document(output_file)
     while count < cipher_len:
         for line in faketext:
             paragraph = doc.paragraphs[paragraph_index]
             if line == '':
                 # Skip blanks in faketext and output_file.
                 paragraph_index += 1
                 continue
             letter_index = 0
             for word in line.split():
                 # Check color of each letter after word.
                 letter_index += len(word)
                 if letter_index >= len(line):
                     # Stop checking at the end of the line.
                     break
                 run = paragraph.runs[letter_index]
                 if all([len(run.text) == 1, run.text != ' ']):
                     self.assertEqual(run.font.color.rgb,
                                      RGBColor(255, 255, 255))
                 count += 1
                 letter_index += 1
             paragraph_index += 1
     os.remove(output_file)
     # Test custom template and filename.
     template_file = os.path.normpath('tests/data/ch06/template_mono.docx')
     output_file = os.path.join(current_dir, 'letter.docx')
     invisible_ink_mono.write_invisible(faketext, ciphertext, template_file,
                                        'letter.docx')
     self.assertTrue(os.path.exists(output_file))
     output_text = invisible_ink.get_text(output_file)
     self.assertListEqual(constants.WRITE_DEFAULT_MONO, output_text)
     # Check color
     paragraph_index, count = 0, 0
     cipher_len = sum(len(line) for line in ciphertext)
     doc = Document(output_file)
     while count < cipher_len:
         for line in faketext:
             paragraph = doc.paragraphs[paragraph_index]
             if line == '':
                 # Skip blanks in faketext and output_file.
                 paragraph_index += 1
                 continue
             if paragraph.text == '':
                 # FIXME: template_file always has a blank paragraph.
                 paragraph_index += 1
                 paragraph = doc.paragraphs[paragraph_index]
             letter_index = 0
             for word in line.split():
                 # Check color of each letter after word.
                 letter_index += len(word)
                 if letter_index >= len(line):
                     # Stop checking at the end of the line.
                     break
                 run = paragraph.runs[letter_index]
                 if all([len(run.text) == 1, run.text != ' ']):
                     self.assertEqual(run.font.color.rgb,
                                      RGBColor(255, 255, 255))
                 count += 1
                 letter_index += 1
             paragraph_index += 1
     os.remove(output_file)
     # Test font name.
     invisible_ink_mono.write_invisible(faketext, ciphertext, None,
                                        'letter.docx')
     doc = Document(output_file)
     if system().lower().startswith('windows'):
         for paragraph in doc.paragraphs:
             if paragraph.text == '':
                 continue
             self.assertEqual(paragraph.style.font.name, "Courier New")
     else:
         for paragraph in doc.paragraphs:
             if paragraph.text == '':
                 continue
             self.assertEqual(paragraph.style.font.name, "Liberation Mono")
     os.remove(output_file)
     # Test multi-line ciphertext.
     ciphertext.append('Hi')
     invisible_ink_mono.write_invisible(faketext, ciphertext)
     output_file = os.path.join(current_dir, 'output.docx')
     self.assertTrue(os.path.exists(output_file))
     output_text = invisible_ink.get_text(output_file)
     self.assertListEqual(constants.WRITE_TEST_MONO, output_text)
     # Check color
     paragraph_index, count = 0, 0
     cipher_len = sum(len(line) for line in ciphertext)
     doc = Document(output_file)
     while count < cipher_len:
         for line in faketext:
             paragraph = doc.paragraphs[paragraph_index]
             if line == '':
                 # Skip blanks in faketext and output_file.
                 paragraph_index += 1
                 continue
             letter_index = 0
             for word in line.split():
                 # Check color of each letter after word.
                 letter_index += len(word)
                 if letter_index >= len(line):
                     # Stop checking at the end of the line.
                     break
                 run = paragraph.runs[letter_index]
                 if all([len(run.text) == 1, run.text != ' ']):
                     self.assertEqual(run.font.color.rgb,
                                      RGBColor(255, 255, 255))
                 count += 1
                 letter_index += 1
             paragraph_index += 1
     os.remove(output_file)
     # Test error.
     ciphertext = ciphertext[:-1]
     faketext = invisible_ink.get_text(fakefile)[2:]
     error = 'Need 25 more spaces in the plaintext (fake) message.'
     with self.assertRaises(ValueError) as err:
         invisible_ink_mono.write_invisible(faketext, ciphertext)
     self.assertEqual(error, str(err.exception))