% Test file for ShortTimeFourierTransformFrameComputer computer
%
% Copyright (c) 2018 Department of Computer Science,
%                    University of Toronto, Canada,
%                    Vector Institute, Canada
%
% License
% This file is under the LGPL license,  you can
%  redistribute it and/or modify it under the terms of the GNU Lesser General 
%  Public License as published by the Free Software Foundation, either version 3 
%  of the License, or (at your option) any later version. This file is
%  distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
%  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
%  PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
%  details.
% 
% This function is part of the Covarep project: http://covarep.github.io/covarep
%
% Author
%  Yingxue Wang <yingxue@cs.toronto.edu>
%  Sean Robertson <sdrobert@cs.toronto.edu>
%

classdef test_compute < matlab.unittest.TestCase
    properties
        computer
    end 
    
    properties (TestParameter)
        bank = {GaborFilterBank(MelScaling())}
        frame_length_ms = {25}
        frame_shift_ms = {10}
        frame_style = {'causal'} %{'causal', 'centered'}
        include_energy = {true}  %{true, false} 
        pad_to_nearest_power_of_two = {true} % {true, false}
        use_log = {true} %{true, false}
        use_power = {true} %{true, false}
        buff_len = {0, 1, 2 ^ 8, 2^10} %{ 0, 1, 2 ^ 8, 2 ^ 10} % empty buffer', 'length 1 buffer', 'medium buffer', 'large buffer'
    end
    
    methods (Test)
        % Test validility of the function
        function test_validate(testCase,...
                bank, ...
                frame_length_ms, ...
                frame_shift_ms, ...
                frame_style, ...
                include_energy, ...
                pad_to_nearest_power_of_two, ...
                use_log, ...
                use_power)
            

            testCase.computer = ShortTimeFourierTransformFrameComputer(...
                                        bank, ...
                                        frame_length_ms, ...
                                        frame_shift_ms, ...
                                        frame_style, ...
                                        include_energy, ...
                                        pad_to_nearest_power_of_two, ...
                                        use_log, ...
                                        use_power);
            testCase.verifyTrue(testCase.computer.isvalid);
        end
        
        function test_framewise_matches_full(testCase,...
                bank, ...
                frame_length_ms, ...
                frame_shift_ms, ...
                frame_style, ...
                include_energy, ...
                pad_to_nearest_power_of_two, ...
                use_log, ...
                use_power,...
                buff_len)
            % This test might fail due to minor numerical error
            
            % Create buffer
            buff = rand(buff_len,1);

            % Create Computer
            testCase.computer = ShortTimeFourierTransformFrameComputer(...
                                        bank, ...
                                        frame_length_ms, ...
                                        frame_shift_ms, ...
                                        frame_style, ...
                                        include_energy, ...
                                        pad_to_nearest_power_of_two, ...
                                        use_log, ...
                                        use_power);
            
            feats_full = testCase.computer.compute_full(buff);
            feats_framewise = Util.frame_by_frame_calculation(testCase.computer, buff);
            testCase.verifyEqual(feats_full, feats_framewise, 'RelTol', 1); 
        end
        
        function test_zero_samples_generate_zero_features(testCase,...
                bank, ...
                frame_length_ms, ...
                frame_shift_ms, ...
                frame_style, ...
                include_energy, ...
                pad_to_nearest_power_of_two, ...
                use_log, ...
                use_power)
            % Create Computer
            testCase.computer = ShortTimeFourierTransformFrameComputer(...
                                        bank, ...
                                        frame_length_ms, ...
                                        frame_shift_ms, ...
                                        frame_style, ...
                                        include_energy, ...
                                        pad_to_nearest_power_of_two, ...
                                        use_log, ...
                                        use_power);
                                    
            testCase.verifyEqual(size(testCase.computer.compute_full(double.empty(0))), [0 testCase.computer.num_coeffs]);
            testCase.verifyEqual(size(testCase.computer.compute_chunk(double.empty(0))), [0  testCase.computer.num_coeffs]);
            testCase.verifyEqual(size(testCase.computer.finalize()), [0 testCase.computer.num_coeffs]);
        end
       
        function test_finalize_twice_generates_no_coefficients(testCase,...
                bank, ...
                frame_length_ms, ...
                frame_shift_ms, ...
                frame_style, ...
                include_energy, ...
                pad_to_nearest_power_of_two, ...
                use_log, ...
                use_power)
            % Create Computer
            testCase.computer = ShortTimeFourierTransformFrameComputer(...
                                        bank, ...
                                        frame_length_ms, ...
                                        frame_shift_ms, ...
                                        frame_style, ...
                                        include_energy, ...
                                        pad_to_nearest_power_of_two, ...
                                        use_log, ...
                                        use_power);
            buff = rand(testCase.computer.frame_length * 2, 1);
            coeffs = [...
                testCase.computer.compute_chunk(buff); ...
                testCase.computer.finalize()...
                ];
            
            shape_coeffs = size(coeffs);
            testCase.verifyGreaterThanOrEqual(shape_coeffs(1), 1);
            shape_finalize = size(testCase.computer.finalize());
            testCase.verifyEqual(shape_finalize, [0 testCase.computer.num_coeffs]);
        end
   
        function test_repeated_calls_generate_same_results(testCase,...
                bank, ...
                frame_length_ms, ...
                frame_shift_ms, ...
                frame_style, ...
                include_energy, ...
                pad_to_nearest_power_of_two, ...
                use_log, ...
                use_power, ...
                buff_len)
            
            % Create buffer
            buff = rand(buff_len,1);
            
            % Create Computer
            testCase.computer = ShortTimeFourierTransformFrameComputer(...
                                        bank, ...
                                        frame_length_ms, ...
                                        frame_shift_ms, ...
                                        frame_style, ...
                                        include_energy, ...
                                        pad_to_nearest_power_of_two, ...
                                        use_log, ...
                                        use_power);
            testCase.verifyEqual(testCase.computer.compute_full(buff), ...
                testCase.computer.compute_full(buff));
            testCase.verifyEqual(...
                Util.frame_by_frame_calculation(testCase.computer, buff), ...
                Util.frame_by_frame_calculation(testCase.computer, buff));
        end
         
    end
end