def test_steganogrified_name():
    """Data will be hidden in a file with steganogrified at the end, when no output file name is provided."""
    clean_message_image = copy2(
        CLEAN_PNG_LOCATION,
        CLEAN_PNG_LOCATION[:-4] + "_test_message_steganogrified_name.png")
    clean_file_image = copy2(
        CLEAN_PNG_LOCATION,
        CLEAN_PNG_LOCATION[:-4] + "_test_file_steganogrified_name.png")
    hidden_message = "Hidden text from test_steganogrified_name."
    file_to_hide = "tests/FileToHide.zip"

    stegs = Steganographer()
    hidden_message_fname = stegs.steganographer_hide(clean_message_image,
                                                     hidden_message)
    steganogrified_message_fname = clean_message_image[:-4] + "Steganogrified.png"
    hidden_file_fname = stegs.steganographer_hide_file(clean_file_image,
                                                       file_to_hide)
    steganogrified_file_fname = clean_file_image[:-4] + "Steganogrified.png"

    assert hidden_message_fname == steganogrified_message_fname
    assert os.path.isfile(steganogrified_message_fname)
    assert hidden_file_fname == steganogrified_file_fname
    assert os.path.isfile(steganogrified_file_fname)

    os.remove(clean_message_image)
    os.remove(hidden_message_fname)
    os.remove(clean_file_image)
    os.remove(hidden_file_fname)
def test_write_image_diff_size_pil():
    """Writing out an image creates a file of a different size, if the file was generated by PIL originally."""
    clean_file = CLEAN_PNG_LOCATION
    dirty_file = "tests/dirtyImage_test_write_image_file_diff_size_pil.png"
    clean_file_pil = "tests/cleanImagePIL.png"
    with Image.open(clean_file) as pil_image:
        pil_image.save(clean_file_pil)

    stegs = Steganographer()
    clean_data = _open_image_file(clean_file_pil)
    dirty_data = clean_data[0], stegs._hide_string(
        clean_data[1], "Hidden text from test_write_image_diff_size_pil.")
    output_file = _write_image_file(dirty_file, clean_file_pil, dirty_data)

    # Getting the file sizes for the clean and dirty files.
    with open(clean_file_pil, 'rb') as clean:
        clean.seek(0, 2)
        clean_file_size = clean.tell()

    with open(output_file, 'rb') as dirty:
        dirty.seek(0, 2)
        dirty_file_size = dirty.tell()

    assert clean_file_size != dirty_file_size

    os.remove(output_file)
def test_hide_reveal_string_inverse(string_to_hide):
    """Anything hidden by _hide_string is revealed by _reveal_string."""
    clean_data = bytes(b'\x01' * 5000)
    stegs = Steganographer()
    stegs._header.data_len = len(string_to_hide.encode('utf-8'))
    revealed_string = stegs._reveal_string(
        stegs._hide_string(clean_data, string_to_hide))
    assert revealed_string == string_to_hide
def test_unicode_inverse():
    """Unicode characters are hidden and revealed."""
    message = "test_unicode hidden message. Some random unicode characters: ­ЊЂѕ рЙе нЁ н╣ п╗ яЌ ▀џ ЯцЎ рЃџ рїЕ рЈю"

    stegs = Steganographer()
    assert message == stegs.steganographer_reveal(
        stegs.steganographer_hide(CLEAN_PNG_LOCATION, message,
                                  "tests/dirtyImage.png"))[0].decode('utf-8')
def test_hide_reveal_byte_inverse(data_to_hide):
    """Anything hidden by _hide_byte is revealed by _reveal_byte."""
    clean_data = bytes(b'\x01' * 8)

    stegs = Steganographer()
    revealed_byte = stegs._reveal_byte(
        stegs._hide_byte(clean_data, data_to_hide[0]))
    assert revealed_byte == data_to_hide
def test_reveal_byte():
    """The _reveal_byte function returns a bytes object of the hidden byte."""
    stegs = Steganographer()
    test_data = bytearray(stegs._BYTELEN)
    test_data[1] = 1
    test_data[7] = 1
    solution_data = bytes('A', 'utf-8')

    assert stegs._reveal_byte(test_data) == solution_data
def test_hide_byte():
    """The _hide_byte function does hide a byte and returns the test_data with that byte hidden."""
    stegs = Steganographer()
    test_data = bytes(b'\x01' * stegs._BYTELEN)
    data_to_hide = bytes('A', 'utf-8')
    solution_data = bytearray(stegs._BYTELEN)
    solution_data[1] = 1
    solution_data[7] = 1

    assert stegs._hide_byte(test_data, data_to_hide[0]) == solution_data
def test_generate_header():
    """The header is generated as expected"""
    stegs = Steganographer()
    header = bytes(stegs._header._HEADER_TITLE, 'utf-8') + \
        bytes(stegs._header.data_len.to_bytes(stegs._header._HEADER_DATA_SIZE, "little")) + \
        bytes(stegs._header.bits_used.to_bytes(stegs._header._HEADER_BITS_SIZE, "little")) + \
        bytes(stegs._header.file_name_len.to_bytes(stegs._header._HEADER_FILE_LENGTH_SIZE, "little"))

    assert header == stegs._generate_header(stegs._header.data_len,
                                            stegs._header.bits_used, "")
def test_exact_data_with_data_inverse():
    """The data entered is the data returned. The storing data is the exact length needed."""
    test_string = "This is a test String"
    test_data = bytes(test_string, 'utf-8')
    stegs = Steganographer()
    stegs._header.data_len = len(test_string)
    blank_data = bytes(b'\x01' * len(test_string) * stegs._BYTELEN)

    revealed_data = stegs._reveal_data(stegs._hide_data(blank_data, test_data))

    assert test_data == revealed_data
def test_hide_reveal_data_inverse(string_to_hide):
    """Anything hidden by _hide_data is revealed by _reveal_data."""
    clean_data = bytes(b'\x01' * 5000)
    data_to_hide = bytes(string_to_hide, 'utf-8')

    stegs = Steganographer()
    stegs._header.data_len = len(string_to_hide.encode('utf-8'))
    revealed_data = stegs._reveal_data(
        stegs._hide_data(clean_data, data_to_hide))

    assert revealed_data == data_to_hide
def test_steganographer_inverse(hidden_message):
    """Steganographer_reveal reveals what was hidden by steganographer_hide."""
    clean_image = CLEAN_PNG_LOCATION
    dirty_image = "tests/dirtyImage_test_steganographer_inverse.png"

    stegs = Steganographer()
    revealed_message = stegs.steganographer_reveal(
        stegs.steganographer_hide(clean_image, hidden_message,
                                  dirty_image))[0].decode('utf-8')
    assert revealed_message == hidden_message

    os.remove(dirty_image)
def test_short_data_with_data_inverse():
    """When the data is too small, by a full byte, everything that can be returned is returned."""
    test_string = "This is a test String"
    test_data = bytes(test_string, 'utf-8')
    stegs = Steganographer()
    stegs._header.data_len = len(test_string)
    blank_data = bytes(b'\x01' *
                       (len(test_string) * stegs._BYTELEN - stegs._BYTELEN))

    revealed_data = stegs._reveal_data(stegs._hide_data(blank_data, test_data))

    assert test_data[:-1] == revealed_data
def test_steganographer_hide_name():
    """The image a string is hidden in is the correct one."""
    clean_image = CLEAN_PNG_LOCATION
    dirty_image = "tests/dirtyImage_test_steganographer_hide_name.png"
    hidden_message = "Hidden text from test_steganographer_hide_name."

    stegs = Steganographer()
    hidden_fname = stegs.steganographer_hide(clean_image, hidden_message,
                                             dirty_image)

    assert hidden_fname == dirty_image

    os.remove(dirty_image)
def test_hide_string():
    """Takes in a string and a bytes object and hides the string in that bytes object."""
    stegs = Steganographer()
    test_data = bytes(b'\x01' * stegs._BYTELEN * 3)
    solution_data = bytearray(stegs._BYTELEN * 3)
    solution_data[1] = 1
    solution_data[7] = 1
    solution_data[9] = 1
    solution_data[14] = 1
    solution_data[17] = 1
    solution_data[22] = 1
    solution_data[23] = 1

    assert stegs._hide_string(test_data, 'ABC') == solution_data
def test_write_image_same_image():
    """Writing out an image creates the same image when viewed generally."""
    clean_file = CLEAN_PNG_LOCATION
    dirty_file = "tests/dirtyImage_test_write_image_file_same_image.png"

    stegs = Steganographer()
    clean_data = _open_image_file(clean_file)
    dirty_data = clean_data[0], stegs._hide_string(
        clean_data[1], "Hidden text from test_write_image_same_image.")
    output_file = _write_image_file(dirty_file, clean_file, dirty_data)

    assert compare_images(clean_file, output_file) < 500

    os.remove(output_file)
def test_short_partial_data_string_inverse():
    """When the data is too small, by a half byte, everything that can be returned is returned."""
    test_string = "This is a test String"
    stegs = Steganographer()
    stegs._header.data_len = len(test_string)
    solution_string = test_string[:-1] + chr(
        ord(test_string[-1]) >> stegs._BYTELEN // 2 << stegs._BYTELEN // 2)
    blank_data = bytes(
        b'\x01' * (len(test_string) * stegs._BYTELEN - stegs._BYTELEN // 2))

    revealed_string = stegs._reveal_string(
        stegs._hide_string(blank_data, test_string))

    assert solution_string == revealed_string
def test_write_bin_diff_content():
    """The file written is different from the one read, after hiding a message."""
    clean_file = CLEAN_PNG_LOCATION
    dirty_file = "tests/dirtyImage_test_write_bin_file_diff_content.png"

    stegs = Steganographer()
    data = stegs._hide_string(_open_bin_file(clean_file),
                              "Hidden text from test_write_bin_diff_content.")
    _write_bin_file(dirty_file, data)

    with open(clean_file, 'rb') as clean, open(dirty_file, 'rb') as dirty:
        assert clean.read() != dirty.read()

    os.remove(dirty_file)
def test_reveal_data():
    """Will return the correct data that is hidden inside the test_data."""
    solution_data = bytes('ABC', 'utf-8')
    stegs = Steganographer()
    stegs._header.data_len = len(solution_data)
    test_data = bytearray(stegs._BYTELEN * 3)
    test_data[1] = 1
    test_data[7] = 1
    test_data[9] = 1
    test_data[14] = 1
    test_data[17] = 1
    test_data[22] = 1
    test_data[23] = 1

    assert stegs._reveal_data(test_data) == solution_data
def test_short_partial_data_w_data_inverse():
    """When the data is too small, by a half byte, everything that can be returned is returned."""
    test_string = "This is a test String"
    test_data = bytes(test_string, 'utf-8')
    solution_data = bytearray(test_data)
    stegs = Steganographer()
    stegs._header.data_len = len(test_string)
    solution_data[
        -1] = solution_data[-1] >> stegs._BYTELEN // 2 << stegs._BYTELEN // 2
    blank_data = bytes(
        b'\x01' * (len(test_string) * stegs._BYTELEN - stegs._BYTELEN // 2))

    revealed_data = stegs._reveal_data(stegs._hide_data(blank_data, test_data))

    assert solution_data == revealed_data
def test_write_image_diff_content():
    """Writing out an image creates a different image at the bit level."""
    clean_file = CLEAN_PNG_LOCATION
    dirty_file = "tests/dirtyImage_test_write_image_file_diff_content.png"

    stegs = Steganographer()
    clean_data = _open_image_file(clean_file)
    dirty_data = clean_data[0], stegs._hide_string(
        clean_data[1], "Hidden text from test_write_image_diff_content.")
    output_file = _write_image_file(dirty_file, clean_file, dirty_data)

    with open(clean_file, 'rb') as clean, open(output_file, 'rb') as dirty:
        assert clean.read() != dirty.read()

    os.remove(output_file)
def test_reveal_string():
    """Returns a string representation of the data that was hidden in the test_data."""
    solution = 'ABC'
    stegs = Steganographer()
    stegs._header.data_len = len(solution)
    test_data = bytearray(stegs._BYTELEN * 4)
    test_data[1] = 1
    test_data[7] = 1
    test_data[9] = 1
    test_data[14] = 1
    test_data[17] = 1
    test_data[22] = 1
    test_data[23] = 1

    assert stegs._reveal_string(test_data) == solution
def test_hide_data_partial():
    """Will work when given a bytes object that is too short to contain the full data to be hidden."""
    stegs = Steganographer()
    test_data = bytes(b'\x01' * stegs._BYTELEN * 3)
    data_to_hide = bytes('ABC', 'utf-8')
    stegs._header.data_len = len(data_to_hide)
    solution_data = bytearray(stegs._BYTELEN * 3)
    solution_data[1] = 1
    solution_data[7] = 1
    solution_data[9] = 1
    solution_data[14] = 1
    solution_data[17] = 1
    solution_data[22] = 1
    solution_data[23] = 1

    # Testing when only half a byte is passed in for the data that contains the hidden text.
    assert stegs._hide_data(test_data[:4], data_to_hide) == solution_data[:4]
def test_hide_data():
    """Will hide one bytes object inside another."""
    stegs = Steganographer()
    test_data = bytes(b'\x01' * stegs._BYTELEN * 4)
    data_to_hide = bytes('ABC', 'utf-8')
    stegs._header.data_len = len(data_to_hide)
    solution_data = bytearray(stegs._BYTELEN * 4)
    solution_data[1] = 1
    solution_data[7] = 1
    solution_data[9] = 1
    solution_data[14] = 1
    solution_data[17] = 1
    solution_data[22] = 1
    solution_data[23] = 1
    solution_data[24:] = b'\x01' * stegs._BYTELEN

    assert stegs._hide_data(test_data, data_to_hide) == solution_data
def test_write_image_file_valid():
    """The image created is not corrupt."""
    clean_file = CLEAN_PNG_LOCATION
    dirty_file = "tests/dirtyImage_test_write_image_file_valid_image.png"

    stegs = Steganographer()
    clean_data = _open_image_file(clean_file)
    dirty_data = clean_data[0], stegs._hide_string(
        clean_data[1], "Hidden text from test_write_image_file_valid.")
    output_file = _write_image_file(dirty_file, clean_file, dirty_data)

    try:
        Image.open(output_file)
    except OSError:
        pytest.fail("Image is corrupt " + output_file)

    os.remove(output_file)
def test_steganographer_reveal_file():
    """A file that has been hidden can be revealed."""
    original_file = "tests/FileToHide.zip"
    dirty_image = "tests/dirtyImageWFile.png"
    revealed_file_name = "tests/test_steganographer_reveal_file.zip"

    stegs = Steganographer()
    revealed_file_data, _ = stegs.steganographer_reveal(dirty_image)

    with open(revealed_file_name, 'wb') as rev_file:
        rev_file.write(revealed_file_data)

    with open(original_file, 'rb') as original, open(revealed_file_name,
                                                     'rb') as revealed:
        assert original.read() == revealed.read()

    os.remove(revealed_file_name)
def test_steganographer_hide_string():
    """A string will correctly be hidden in a new image."""
    clean_image = CLEAN_PNG_LOCATION
    dirty_image = "tests/dirtyImage_test_steganographer_hide_string.png"
    hidden_message = "Hidden text from test_steganographer_hide_string."

    stegs = Steganographer()
    hidden_fname = stegs.steganographer_hide(clean_image, hidden_message,
                                             dirty_image)

    with open(clean_image, 'rb') as clean, open(hidden_fname, 'rb') as dirty:
        assert clean.read() != dirty.read()
    assert compare_images(clean_image, hidden_fname) < 500
    try:
        Image.open(hidden_fname)
    except OSError:
        pytest.fail("Image is corrupt " + hidden_fname)

    os.remove(dirty_image)
def test_steganographer_hide_file():
    """A file can be hidden inside of an image and the image created is not corrupt"""
    clean_image = CLEAN_PNG_LOCATION
    dirty_image = "tests/dirtyImage_test_steganographer_hide_file.png"
    file_to_hide = "tests/FileToHide.zip"

    stegs = Steganographer()
    hidden_fname = stegs.steganographer_hide_file(clean_image, file_to_hide,
                                                  dirty_image)

    with open(clean_image, 'rb') as clean, open(hidden_fname, 'rb') as dirty:
        assert clean.read() != dirty.read()
    assert compare_images(clean_image, hidden_fname) < 19000
    try:
        Image.open(hidden_fname)
    except OSError:
        pytest.fail("Image is corrupt " + hidden_fname)

    os.remove(hidden_fname)
def test_stegs_hide_string_nonsense():
    """A random string, that can cause a decode error, will correctly be hidden in a new image."""
    clean_image = CLEAN_PNG_LOCATION
    dirty_image = "tests/dirtyImage_test_steganographer_hide_string_nonsense.png"
    hidden_message = "─ю­љАЉ─ю─ю─ю─ю─ю─ю─ю─ю─юнг─ю\U000fc423─ю─ю─ю─юнг─ю─ю─юнгнг─юнг\U000fc423─юнг\U000fc423нгнг─ю\U000fc423нг─юнг­љАЋ­љАЋ­љАЉ­љАЋ­љАЋ­љАЋ­љАЉ­љАЋ­љАЉ­љАЋ­љАЉ"

    stegs = Steganographer()
    hidden_fname = stegs.steganographer_hide(clean_image, hidden_message,
                                             dirty_image)

    with open(clean_image, 'rb') as clean, open(hidden_fname, 'rb') as dirty:
        assert clean.read() != dirty.read()
    assert compare_images(clean_image, hidden_fname) < 650
    try:
        Image.open(hidden_fname)
    except OSError:
        pytest.fail("Image is corrupt " + hidden_fname)

    os.remove(dirty_image)
def test_reveal_data_partial():
    """
    Will return as much data as possible.

    When the container bytes object passed in is too small for all the data to be hidden.
    """
    stegs = Steganographer()
    solution_data = bytes('AB@', 'utf-8')
    test_data = bytearray(
        stegs._BYTELEN * 3
    )  # Will contain 'ABC' but will be truncated when passed to _reveal_data
    test_data[1] = 1
    test_data[7] = 1
    test_data[9] = 1
    test_data[14] = 1
    test_data[17] = 1
    test_data[22] = 1
    test_data[23] = 1
    stegs._data_len = len('ABC')

    assert stegs._reveal_data(test_data[:-stegs._BYTELEN //
                                        2]) == solution_data
def test_write_bin_file_size_same():
    """The file written is the same size as the one read, after hiding a message."""
    clean_file = CLEAN_PNG_LOCATION
    dirty_file = "tests/dirtyImage_test_write_bin_file_size_same.png"

    stegs = Steganographer()
    data = stegs._hide_string(
        _open_bin_file(clean_file),
        "Hidden text from test_write_bin_file_size_same.")
    _write_bin_file(dirty_file, data)

    # Getting the file sizes for the clean and dirty files.
    with open(clean_file, 'rb') as clean:
        clean.seek(0, 2)
        clean_file_size = clean.tell()

    with open(dirty_file, 'rb') as dirty:
        dirty.seek(0, 2)
        dirty_file_size = dirty.tell()

    assert clean_file_size == dirty_file_size

    os.remove(dirty_file)