function assertFilesEqual(filename1, filename2, user_message)
%assertFilesEqual Assert that files contain the same contents.
%   assertFilesEqual(filename1, filename2) throws an exception if the two
%   specified files do not contain the same contents.
%
%   assertFilesEqual(filename1, filename2, message) prepends the specified
%   message string to the assertion message.

%   Steven L. Eddins
%   Copyright 2009 The MathWorks, Inc.

if nargin < 3
    user_message = '';
end

fid1 = fopen(filename1, 'r');
if (fid1 < 0)
    message = sprintf('%s\nCould not open file for reading: %s', ...
        user_message, filename1);
    throwAsCaller(MException('assertFilesEqual:readFailure', message));
else
    c1 = onCleanup(@() fclose(fid1));
end

fid2 = fopen(filename2, 'r');
if (fid2 < 0)
    message = sprintf('%s\nCould not open file for reading: %s', ...
        user_message, filename2);
    throwAsCaller(MException('assertFilesEqual:readFailure', message));
else
    c2 = onCleanup(@() fclose(fid2));
end

block_size = 100000;
num_blocks = 0;
done = false;
while ~done
    block_from_file1 = fread(fid1, block_size, '*uint8');
    block_from_file2 = fread(fid2, block_size, '*uint8');
    
    if numel(block_from_file1) ~= numel(block_from_file2)
        fseek(fid1, 0, 'eof');
        fseek(fid2, 0, 'eof');
        message = sprintf('The two files are not the same size. File "%s" has %d bytes and file "%s" has %d bytes', ...
            filename1, ftell(fid1), filename2, ftell(fid2));
        if ~isempty(user_message)
            message = sprintf('%s\n%s', user_message, message);
        end
        throwAsCaller(MException('assertFilesEqual:sizeMismatch', message));
    end
    
    if ~isequal(block_from_file1, block_from_file2)
        first_difference_in_block = find(block_from_file1 ~= block_from_file2);
        first_difference = num_blocks * block_size + first_difference_in_block;
        
        message = sprintf('Files are not equal. First difference is at byte %d, where file "%s" contains 0x%X and file "%s" contains 0x%X', ...
            first_difference, filename1, block_from_file1(first_difference_in_block), ...
            filename2, block_from_file2(first_difference_in_block));
        if ~isempty(user_message)
            message = sprintf('%s\n%s', user_message, message);
        end
        throwAsCaller(MException('assertFilesEqual:valuesDiffer', message));
    end
    
    done = numel(block_from_file1) < block_size;
    num_blocks = num_blocks + 1;
end