# Path: vasppy/utils.py
# def md5sum( string ):
#     """
#     Generate the md5 checksum for a string
# 
#     Args:
#         string (Str): The string to be checksummed.
# 
#     Returns:
#         (Str): The hex checksum.
#     """
#     h = hashlib.new( 'md5' )
#     h.update( string.encode( 'utf-8' ) )
#     return h.hexdigest()
# 
# def file_md5( filename ):
#     """
#     Generate the md5 checksum for a file
# 
#     Args:
#         filename (Str): The file to be checksummed.
# 
#     Returns:
#         (Str): The hex checksum
# 
#     Notes:
#         If the file is gzipped, the md5 checksum returned is
#         for the uncompressed ASCII file.
#     """
#     with zopen( filename, 'r' ) as f:
#         file_string = f.read()
#     try: # attempt to decode byte object
#         file_string = file_string.decode()
#     except AttributeError:
#         pass
#     return( md5sum( file_string ) )
# 
# def validate_checksum( filename, md5sum ):
#     """
#     Compares the md5 checksum of a file with an expected value.
#     If the calculated and expected checksum values are not equal, 
#     ValueError is raised.
#     If the filename `foo` is not found, will try to read a gzipped file named
#     `foo.gz`. In this case, the checksum is calculated for the unzipped file.
# 
#     Args:
#         filename (str): Path for the file to be checksummed.
#         md5sum (str):  The expected hex checksum.
# 
#     Returns:
#         None
#     """
#     filename = match_filename( filename )
#     md5_hash = file_md5( filename=filename )
#     if md5_hash != md5sum:
#         raise ValueError('md5 checksums are inconsistent: {}'.format( filename ))


import unittest
import hashlib
from vasppy.utils import md5sum, file_md5, validate_checksum
from unittest.mock import patch, mock_open

class UtilsTestCase( unittest.TestCase ):

    def test_md5sum( self ):
        string = 'abcdefg'
        h = hashlib.new( 'md5' )
        h.update( string.encode( 'utf-8' ) )
        self.assertEqual( md5sum( string ), h.hexdigest() )

    def test_file_md5( self ):
        example_file = "abc\nabc\n"
        with patch( 'vasppy.utils.md5sum' ) as mock_md5sum:
            mock_md5sum.return_value = 'foo'
            with patch( 'vasppy.utils.zopen', mock_open( read_data=example_file ), create=True ) as m:
                self.assertEqual( file_md5( m ), 'foo' )
                mock_md5sum.assert_called_with( example_file )

    def test_validate_checksum( self ):
        with patch( 'vasppy.utils.match_filename' ) as mock_match_filename:
            with patch( 'vasppy.utils.file_md5' ) as mock_file_md5:
                mock_file_md5.return_value='abcdef'
                validate_checksum( filename='foo', md5sum='abcdef' )                

    def test_validate_checksum_raises_ValueError_if_not_matched( self ):
        with patch( 'vasppy.utils.match_filename' ) as mock_match_filename:
            mock_match_filename.return_value='bar'
            with patch( 'vasppy.utils.file_md5' ) as mock_file_md5:
                mock_file_md5.return_value='bcdefg'
                with self.assertRaises( ValueError ):

# Path: vasppy/utils.py
# def md5sum( string ):
#     """
#     Generate the md5 checksum for a string
# 
#     Args:
#         string (Str): The string to be checksummed.
# 
#     Returns:
#         (Str): The hex checksum.
#     """
#     h = hashlib.new( 'md5' )
#     h.update( string.encode( 'utf-8' ) )
#     return h.hexdigest()
# 
# def file_md5( filename ):
#     """
#     Generate the md5 checksum for a file
# 
#     Args:
#         filename (Str): The file to be checksummed.
# 
#     Returns:
#         (Str): The hex checksum
# 
#     Notes:
#         If the file is gzipped, the md5 checksum returned is
#         for the uncompressed ASCII file.
#     """
#     with zopen( filename, 'r' ) as f:
#         file_string = f.read()
#     try: # attempt to decode byte object
#         file_string = file_string.decode()
#     except AttributeError:
#         pass
#     return( md5sum( file_string ) )
# 
# def validate_checksum( filename, md5sum ):
#     """
#     Compares the md5 checksum of a file with an expected value.
#     If the calculated and expected checksum values are not equal, 
#     ValueError is raised.
#     If the filename `foo` is not found, will try to read a gzipped file named
#     `foo.gz`. In this case, the checksum is calculated for the unzipped file.
# 
#     Args:
#         filename (str): Path for the file to be checksummed.
#         md5sum (str):  The expected hex checksum.
# 
#     Returns:
#         None
#     """
#     filename = match_filename( filename )
#     md5_hash = file_md5( filename=filename )
#     if md5_hash != md5sum:
#         raise ValueError('md5 checksums are inconsistent: {}'.format( filename ))


# Path: tests/test_utils.py
import unittest
import hashlib
from vasppy.utils import md5sum, file_md5, validate_checksum
from unittest.mock import patch, mock_open


class UtilsTestCase( unittest.TestCase ):

    def test_md5sum( self ):
        string = 'abcdefg'
        h = hashlib.new( 'md5' )
        h.update( string.encode( 'utf-8' ) )
        self.assertEqual( md5sum( string ), h.hexdigest() )

    def test_file_md5( self ):
        example_file = "abc\nabc\n"
        with patch( 'vasppy.utils.md5sum' ) as mock_md5sum:
            mock_md5sum.return_value = 'foo'
            with patch( 'vasppy.utils.zopen', mock_open( read_data=example_file ), create=True ) as m:
                self.assertEqual( file_md5( m ), 'foo' )
                mock_md5sum.assert_called_with( example_file )

    def test_validate_checksum( self ):
        with patch( 'vasppy.utils.match_filename' ) as mock_match_filename:
            with patch( 'vasppy.utils.file_md5' ) as mock_file_md5:
                mock_file_md5.return_value='abcdef'
                validate_checksum( filename='foo', md5sum='abcdef' )                

    def test_validate_checksum_raises_ValueError_if_not_matched( self ):
        with patch( 'vasppy.utils.match_filename' ) as mock_match_filename:
            mock_match_filename.return_value='bar'
            with patch( 'vasppy.utils.file_md5' ) as mock_file_md5:
                mock_file_md5.return_value='bcdefg'
                with self.assertRaises( ValueError ):

                    validate_checksum( filename='foo', md5sum='abcdef' )                