assertEquals( 'en_US', substr( TTi18n::getLocale(), 0, 5 ) ); $this->assertEquals( 'en', TTi18n::getLanguage() ); $this->assertEquals( 'US', TTi18n::getCountry() ); $this->assertEquals( '$', TTi18n::getCurrencySymbol( 'USD' ) ); $this->assertEquals( 'en_CA.UTF-8', TTi18n::tryLocale( 'en_CA.UTF-8' ) ); $this->assertEquals( 'en_US.utf-8', TTi18n::tryLocale( 'en_US.utf-8' ) ); $this->assertEquals( 'en_US.utf8', TTi18n::tryLocale( 'en_US.utf8' ) ); $this->assertEquals( 'en_US.uTf-8', TTi18n::tryLocale( 'en_US.uTf-8' ) ); $this->assertEquals( false, TTi18n::tryLocale( 'NOT REAL' ) ); //$this->assertEquals( TTi18n::tryLocale( 'en_CA' ), FALSE ); //Some installs may have this locale. } /** * @noinspection PhpInconsistentReturnPointsInspection */ function testMisc() { if ( extension_loaded( 'intl' ) == false ) { return true; } //$expected_lang_arr = array('en' => 'English', 'da' => 'Danish (UO)', 'de' => 'German (UO)', 'es' => 'Spanish (UO)', 'id' => 'Indonesian (UO)', 'it' => 'Italian (UO)', 'fr' => 'French (UO)', 'pt' => 'Portuguese (UO)', 'ar' => 'Arabic (UO)', 'zh' => 'Chinese (UO)', 'yi' => 'Yiddish (UO)'); //$expected_lang_arr = array('en' => 'English', 'da' => 'Dansk (UO)', 'de' => 'Deutsch (UO)', 'es' => 'Español (UO)', 'id' => 'Bahasa Indonesia (UO)', 'it' => 'Italiano (UO)', 'fr' => 'Français (UO)', 'pt' => 'Português (UO)', 'ar' => 'العربية (UO)', 'zh' => '中文 (UO)', 'yi' => 'ייִדיש (UO)'); //$expected_lang_arr = array('en' => 'English', 'da' => 'Dansk (UO)', 'de' => 'Deutsch (UO)', 'es' => 'Español (UO)', 'id' => 'Indonesia (UO)', 'it' => 'Italiano (UO)', 'fr' => 'Français (UO)', 'pt' => 'Português (UO)', 'ar' => 'العربية (UO)', 'zh' => '中文 (UO)' ); $expected_lang_arr = [ 'en' => 'English', 'de' => 'Deutsch (UO)', 'es' => 'Español (UO)', 'id' => 'Indonesia (UO)', 'fr' => 'Français (UO)', 'hu' => 'Magyar (UO)', 'ro' => 'Română (UO)' ]; unset( $expected_lang_arr['id'] ); //It seems Indonesian changes depending on the Ubuntu version, so just ignore it. TTi18n::setLocale( 'en_CA' ); $lang_arr = TTi18n::getLanguageArray(); unset( $lang_arr['id'] ); //It seems Indonesian changes depending on the Ubuntu version, so just ignore it. array_pop( $lang_arr ); //Pop off Yiddish as it may not be installed everywhere. $this->assertEquals( $lang_arr, $expected_lang_arr ); TTi18n::setLocale( 'es_ES' ); $lang_arr = TTi18n::getLanguageArray(); unset( $lang_arr['id'] ); //It seems Indonesian changes depending on the Ubuntu version, so just ignore it. array_pop( $lang_arr ); //Pop off Yiddish as it may not be installed everywhere. $this->assertEquals( $lang_arr, $expected_lang_arr ); TTi18n::setLocale( 'en_CA' ); $this->assertEquals( 'en_US', TTi18n::getNormalizedLocale() ); $this->assertEquals( false, TTi18n::getLocaleCookie() ); $this->assertEquals( 'en', TTi18n::getLanguageFromLocale() ); $this->assertEquals( 'fr', TTi18n::getLanguageFromLocale( 'fr_CH.utf8' ) ); } /** @noinspection PhpInconsistentReturnPointsInspection */ function testFormatCurrency() { if ( extension_loaded( 'intl' ) == false ) { return true; } //Canadian Dollars - INTL wants to us CA$ rather than just $. TTi18n::setLocale( 'en_CA' ); $this->assertEquals( '$8.99', TTi18n::formatCurrency( 8.9901 ) ); $this->assertEquals( '-$87.99', TTi18n::formatCurrency( -87.9901 ) ); $this->assertEquals( '¥8,799', TTi18n::formatCurrency( 8799.012345, 'JPY', 0 ) ); //US Dollars TTi18n::setLocale( 'en_US' ); $this->assertEquals( '$8.99', TTi18n::formatCurrency( 8.9901 ) ); $this->assertEquals( '-$87.99', TTi18n::formatCurrency( -87.9901 ) ); $this->assertEquals( '¥8,799', TTi18n::formatCurrency( 8799.012345, 'JPY', 0 ) ); //test euros TTi18n::setLocale( 'it_IT' ); if ( TTi18n::getThousandsSymbol() == '.' && TTi18n::getDecimalSymbol() == ',' ) { $this->assertEquals( '8,99 €', TTi18n::formatCurrency( 8.9901 ) ); $this->assertEquals( '-87,99 €', TTi18n::formatCurrency( -87.9901 ) ); $this->assertEquals( '1.888.799,01 €', TTi18n::formatCurrency( 1888799.012345 ) ); $this->assertEquals( 'EUR 8.799,01 €', TTi18n::formatCurrency( 8799.012345, 'EUR', 1 ) ); $this->assertEquals( '8.799,01 €', TTi18n::formatCurrency( 8799.012345, 'EUR', 0 ) ); } else { Debug::Text( 'ERROR: Locale differs, skipping unit tests...', __FILE__, __LINE__, __METHOD__, 1 ); } TTi18n::setLocale( 'es_ES' ); if ( TTi18n::getThousandsSymbol() == '.' && TTi18n::getDecimalSymbol() == ',' ) { //NBS = Non-Blocking Space. This requires PDF's (ie: Pay Stubs) to use UTF-8 encoding, even if they are English language. So we are removing NBS to avoid that. //$this->assertEquals( '8,99 €', TTi18n::formatCurrency( 8.9901 ) ); $this->assertEquals( '8,99 €', TTi18n::formatCurrency( 8.9901 ) ); $this->assertEquals( '-87,99 €', TTi18n::formatCurrency( -87.9901 ) ); $this->assertEquals( '1.888.799,01 €', TTi18n::formatCurrency( 1888799.012345 ) ); $this->assertEquals( 'EUR 8.799,01 €', TTi18n::formatCurrency( 8799.012345, 'EUR', 1 ) ); $this->assertEquals( '8.799,01 €', TTi18n::formatCurrency( 8799.012345, 'EUR', 0 ) ); } else { Debug::Text( 'ERROR: Locale differs, skipping unit tests...', __FILE__, __LINE__, __METHOD__, 1 ); } } function testNumberFormat() { //english locales use #,###.## TTi18n::setLocale( 'en_CA' ); $this->assertEquals( '8.99', TTi18n::formatNumber( 8.9901 ) ); $this->assertEquals( '-87.99', TTi18n::formatNumber( -87.9901 ) ); $this->assertEquals( '-88', TTi18n::formatNumber( -87.9991 ) ); $this->assertEquals( '8,987.99', TTi18n::formatNumber( 8987.990122 ) ); $this->assertEquals( '1,234.99', TTi18n::formatNumber( 1234.990122 ) ); $this->assertEquals( '123,456.99', TTi18n::formatNumber( 123456.990122 ) ); $this->assertEquals( '123,456,789.99', TTi18n::formatNumber( 123456789.990122 ) ); $this->assertEquals( '12,345.12', TTi18n::formatNumber( 12345.12345 ) ); $this->assertEquals( '-12,345.12', TTi18n::formatNumber( -12345.12345 ) ); $this->assertEquals( '123.12', TTi18n::formatNumber( 123.12345 ) ); $this->assertEquals( '-123.12', TTi18n::formatNumber( -123.12345 ) ); $this->assertEquals( '-87.990122', TTi18n::formatNumber( -87.990122, true, 2, 6 ) ); $this->assertEquals( '-87.90', TTi18n::formatNumber( -87.9000, true, 2, 4 ) ); $this->assertEquals( '-87.9901', TTi18n::formatNumber( -87.9901, true, 2, 4 ) ); $this->assertEquals( '1,234.9901', TTi18n::formatNumber( 1234.990122, true, 2, 4 ) ); $this->assertEquals( '123,456.99012', TTi18n::formatNumber( 123456.990122, true, 3, 5 ) ); $this->assertEquals( '123,456,789.9901', TTi18n::formatNumber( 123456789.990122, true, 2, 4 ) ); //spanish locales show numbers as # ###,## TTi18n::setLocale( 'es_ES' ); if ( TTi18n::getThousandsSymbol() == '.' && TTi18n::getDecimalSymbol() == ',' ) { $this->assertEquals( '8,99', TTi18n::formatNumber( 8.9901 ) ); $this->assertEquals( '-87,99', TTi18n::formatNumber( -87.9901 ) ); $this->assertEquals( '-87,99', TTi18n::formatNumber( -87.9901 ) ); $this->assertEquals( '8.987,99', TTi18n::formatNumber( 8987.990122 ) ); $this->assertEquals( '1.234,99', TTi18n::formatNumber( 1234.990122 ) ); $this->assertEquals( '123.456.789,99', TTi18n::formatNumber( 123456789.990122 ) ); $this->assertEquals( '-87,990156', TTi18n::formatNumber( -87.99015555, true, 2, 6 ) ); //rounding $this->assertEquals( '-87,90', TTi18n::formatNumber( -87.9000, true, 2, 4 ) ); $this->assertEquals( '-87,9902', TTi18n::formatNumber( -87.990155, true, 2, 4 ) ); //rounding $this->assertEquals( '1.234,9901', TTi18n::formatNumber( 1234.990122, true, 2, 4 ) ); $this->assertEquals( '123.456.789,9901', TTi18n::formatNumber( 123456789.990122, true, 2, 4 ) ); } else { Debug::Text( 'ERROR: Locale differs, skipping unit tests...', __FILE__, __LINE__, __METHOD__, 1 ); } //comparing TTi18n::formatNumber to Misc::MoneyFormat due to high usage of the MoneyFormat() in existing code. TTi18n::setLocale( 'en_CA' ); $this->assertEquals( '12,345.15', TTi18n::formatNumber( 12345.152, true, 2, 2 ) ); $this->assertEquals( '12,345.15', TTi18n::formatNumber( 12345.151, false ) ); $this->assertEquals( '12,345.15', TTi18n::formatNumber( 12345.15, true ) ); $this->assertEquals( '12,345.15', TTi18n::formatNumber( 12345.15, false ) ); $this->assertEquals( '12,345.10', TTi18n::formatNumber( 12345.1, true ) ); $this->assertEquals( '12,345.5', TTi18n::formatNumber( 12345.5, false ) ); $this->assertEquals( '12,345.12', TTi18n::formatNumber( 12345.12345 ) ); $this->assertEquals( '-12,345.12', TTi18n::formatNumber( -12345.12345 ) ); $this->assertEquals( '123.12', TTi18n::formatNumber( 123.12345 ) ); $this->assertEquals( '-123.12', TTi18n::formatNumber( -123.12345 ) ); $this->assertEquals( '123', TTi18n::formatNumber( 123 ) ); $this->assertEquals( '-123', TTi18n::formatNumber( -123 ) ); $this->assertEquals( '12,345.15', Misc::MoneyFormat( 12345.152, true ) ); $this->assertEquals( '12345.15', Misc::MoneyFormat( 12345.151, false ) ); $this->assertEquals( '12,345.15', Misc::MoneyFormat( 12345.15, true ) ); $this->assertEquals( '12345.15', Misc::MoneyFormat( 12345.15, false ) ); $this->assertEquals( '12,345.10', Misc::MoneyFormat( 12345.1, true ) ); $this->assertEquals( '12345.50', Misc::MoneyFormat( 12345.5, false ) ); $this->assertEquals( '12,345.12', Misc::MoneyFormat( 12345.12345 ) ); $this->assertEquals( '-12,345.12', Misc::MoneyFormat( -12345.12345 ) ); $this->assertEquals( '123.12', Misc::MoneyFormat( 123.12345 ) ); $this->assertEquals( '-123.12', Misc::MoneyFormat( -123.12345 ) ); } function testBeforeAndAfterDecimal() { $this->assertEquals( '12345', Misc::getBeforeDecimal( 12345.92345 ) ); $this->assertEquals( '-12345', Misc::getBeforeDecimal( -12345.92345 ) ); $this->assertEquals( '92345', Misc::getAfterDecimal( 12345.92345, false ) ); $this->assertEquals( '92345', Misc::getAfterDecimal( -12345.92345, false ) ); TTi18n::setLocale( 'es_ES' ); $this->assertEquals( '12345', Misc::getBeforeDecimal( 12345.92345 ) ); $this->assertEquals( '-12345', Misc::getBeforeDecimal( -12345.92345 ) ); $this->assertEquals( '92345', Misc::getAfterDecimal( 12345.92345, false ) ); $this->assertEquals( '92345', Misc::getAfterDecimal( -12345.92345, false ) ); } /* * @noinspection PhpInconsistentReturnPointsInspection */ /** @noinspection PhpInconsistentReturnPointsInspection */ function testParseFloatFunctions() { if ( extension_loaded( 'intl' ) == false ) { return true; } TTi18n::setLocale( 'en_US' ); $this->assertEquals( '1234.123', TTI18n::parseFloat( '1,234.123' ) ); $this->assertEquals( '1234.123', TTI18n::parseFloat( '1, 234.123' ) ); $this->assertEquals( '12.91', TTI18n::parseFloat( '12.91' ) ); $this->assertEquals( '-12.91', TTI18n::parseFloat( '-12.91' ) ); $this->assertEquals( '12.123', TTI18n::parseFloat( (float)12.123 ) ); $this->assertEquals( '0.00', TTI18n::parseFloat( '0.00' ) ); $this->assertEquals( '0', TTI18n::parseFloat( '0' ) ); $this->assertEquals( '0', TTI18n::parseFloat( 0 ) ); $this->assertEquals( '0', TTI18n::parseFloat( '' ) ); $this->assertEquals( '0', TTI18n::parseFloat( true ) ); $this->assertEquals( '0', TTI18n::parseFloat( false ) ); $this->assertEquals( '0', TTI18n::parseFloat( null ) ); $this->assertEquals( '0', TTI18n::parseFloat( INF ) ); $this->assertEquals( '0', TTI18n::parseFloat( -INF ) ); $this->assertEquals( '0', TTI18n::parseFloat( +INF ) ); $this->assertEquals( '0', TTI18n::parseFloat( acos( 8 ) ) ); //acos(8) = NaN // //Test parsing both comma and decimal separated in a locale that uses just decimal separator // $this->assertEquals( '1234.123', TTI18n::parseFloat( '1.234,123' ) ); $this->assertEquals( '1234.123', TTI18n::parseFloat( '1. 234,123' ) ); $this->assertEquals( '12.91', TTI18n::parseFloat( '12,91' ) ); $this->assertEquals( '.12', TTI18n::parseFloat( '.12' ) ); $this->assertEquals( '.12', TTI18n::parseFloat( ',12' ) ); $this->assertEquals( '-.12', TTI18n::parseFloat( '-.12' ) ); $this->assertEquals( '-.12', TTI18n::parseFloat( '-,12' ) ); $this->assertEquals( '0.12', TTI18n::parseFloat( '0.12' ) ); $this->assertEquals( '0.12', TTI18n::parseFloat( '0,12' ) ); $this->assertEquals( '-0.12', TTI18n::parseFloat( '-0.12' ) ); $this->assertEquals( '-0.12', TTI18n::parseFloat( '-0,12' ) ); $this->assertEquals( '12.9', TTI18n::parseFloat( '12.9', 1 ) ); //Ambiguous as it could be assumed to be 12.9, or 129 $this->assertEquals( '12.91', TTI18n::parseFloat( '12.91', 2 ) ); //Ambiguous as it could be assumed to be 12.91, or 12, 91 $this->assertEquals( '12.912', TTI18n::parseFloat( '12.912', 3 ) ); //Ambiguous as it could be assumed to be 12.912, or 12, 912 $this->assertEquals( '12.9123', TTI18n::parseFloat( '12.9123', 4 ) ); //Ambiguous as it could be assumed to be 12.9123, or 12, 9123 $this->assertEquals( '12.9', TTI18n::parseFloat( '12,9', 1 ) ); //Ambiguous as it could be assumed to be 12.9, or 129 $this->assertEquals( '12.91', TTI18n::parseFloat( '12,91', 2 ) ); //Ambiguous as it could be assumed to be 12.91, or 12, 91 $this->assertEquals( '12.912', TTI18n::parseFloat( '12,912', 3 ) ); //Ambiguous as it could be assumed to be 12.912, or 12, 912 $this->assertEquals( '12.9123', TTI18n::parseFloat( '12,9123', 4 ) ); //Ambiguous as it could be assumed to be 12.9123, or 12, 9123 $this->assertEquals( '12.9', TTI18n::parseFloat( '12.9' ) ); //Ambiguous as it could be assumed to be 12.9, or 129 -- However since there is only one separator and it matches the decimal separator in the locale we can be certain. $this->assertEquals( '12.91', TTI18n::parseFloat( '12.91' ) ); //Ambiguous as it could be assumed to be 12.91, or 12, 91 -- However since there is only one separator and it matches the decimal separator in the locale we can be certain. $this->assertEquals( '12.912', TTI18n::parseFloat( '12.912' ) ); //Ambiguous as it could be assumed to be 12.912, or 12, 912 -- However since there is only one separator and it matches the decimal separator in the locale we can be certain. $this->assertEquals( '12.9123', TTI18n::parseFloat( '12.9123' ) ); //Ambiguous as it could be assumed to be 12.9123, or 12, 9123 -- However since there is only one separator and it matches the decimal separator in the locale we can be certain. $this->assertEquals( '12.9', TTI18n::parseFloat( '12,9' ) ); //Ambiguous as it could be assumed to be 12.9, or 129 $this->assertEquals( '12.91', TTI18n::parseFloat( '12,91' ) ); //Ambiguous as it could be assumed to be 12.91, or 12, 91 $this->assertEquals( '12912', TTI18n::parseFloat( '12,912' ) ); //Ambiguous as it could be assumed to be 12.912, or 12, 912 $this->assertEquals( '12.9123', TTI18n::parseFloat( '12,9123' ) ); //Ambiguous as it could be assumed to be 12.9123, or 12, 9123 $this->assertEquals( '123', TTI18n::parseFloat( '123' ) ); $this->assertEquals( '1234', TTI18n::parseFloat( '1, 234' ) ); //Ambiguous as it could be assumed to be 1,234, or 1.234. $this->assertEquals( '1.234', TTI18n::parseFloat( '1. 234' ) ); //Ambiguous as it could be assumed to be 1,234, or 1.234 -- However since there is only one separator and it matches the decimal separator in the locale we can be certain. $this->assertEquals( '123.91', TTI18n::parseFloat( '123.91' ) ); $this->assertEquals( '123.91', TTI18n::parseFloat( '123,91' ) ); $this->assertEquals( '1234.91', TTI18n::parseFloat( '1, 234.91' ) ); $this->assertEquals( '1234.91', TTI18n::parseFloat( '1. 234,91' ) ); $this->assertEquals( '123456789.91', TTI18n::parseFloat( '123 456 789.91' ) ); $this->assertEquals( '123456789.91', TTI18n::parseFloat( '123 456 789,91' ) ); $this->assertEquals( '123456789.91', TTI18n::parseFloat( '123, 456, 789.91' ) ); $this->assertEquals( '123456789.91', TTI18n::parseFloat( '123. 456. 789,91' ) ); $this->assertEquals( '123456789.912', TTI18n::parseFloat( '123. 456. 789,912' ) ); $this->assertEquals( '123456789.912345678', TTI18n::parseFloat( '123. 456. 789,912345678' ) ); $this->assertEquals( '1234567890123456789000.123', TTI18n::parseFloat( '1,234,567,890,123,456,789,000.123' ) ); $this->assertEquals( '1234567890123456789123.123', TTI18n::parseFloat( '1,234,567,890,123,456,789,123.123' ) ); $this->assertEquals( '0.00', TTI18n::parseFloat( '0,00' ) ); $this->assertEquals( '0', TTI18n::parseFloat( '0' ) ); $this->assertEquals( '0', TTI18n::parseFloat( 0 ) ); //Test floats with other bogus characters. $this->assertEquals( '123.91', TTI18n::parseFloat( '$123.91ABC%' ) ); $this->assertEquals( '123.91', TTI18n::parseFloat( '$123,91ABC%' ) ); $this->assertEquals( '123.91', TTI18n::parseFloat( 'A123.91' ) ); $this->assertEquals( '123.91', TTI18n::parseFloat( 'A123.91B' ) ); $this->assertEquals( '123.91', TTI18n::parseFloat( '12A3.91' ) ); $this->assertEquals( '123.91', TTI18n::parseFloat( '123A.91' ) ); $this->assertEquals( '123.91', TTI18n::parseFloat( '123.A91' ) ); $this->assertEquals( '123.91', TTI18n::parseFloat( '*&#$#\'"123.JKLFDJFL91%' ) ); $this->assertEquals( '123.91', TTI18n::parseFloat( '$123.91-' ) ); $this->assertEquals( '123.91', TTI18n::parseFloat( '$123.91--' ) ); $this->assertEquals( '123.91', TTI18n::parseFloat( '$123.91+' ) ); $this->assertEquals( '123.91', TTI18n::parseFloat( '$123.91++' ) ); $this->assertEquals( '54333.12', TTI18n::parseFloat( '54333.12', 2 ) ); //Has only one separator, and input matches precision value. $this->assertEquals( '54333.12', TTI18n::parseFloat( '54333.12', 3 ) ); //Has only one separator, and input is 2 decimal places which DOES NOT match precision value. $this->assertEquals( '54333.123', TTI18n::parseFloat( '54333.123', 3 ) ); //Has only one separator, and input matches precision value. $this->assertEquals( '54333.1234', TTI18n::parseFloat( '54333.1234', 4 ) ); //Has only one separator, and input matches precision value. //Make sure parseFloat() can handle output from formatNumber() $this->assertEquals( '54333.12', TTI18n::parseFloat( TTi18n::formatNumber( '54333.1234' ) ) ); //Auto formatting decimals. $this->assertEquals( '54333.12', TTI18n::parseFloat( TTi18n::formatNumber( '54333.12' ) ) ); $this->assertEquals( '54333.123', TTI18n::parseFloat( TTi18n::formatNumber( '54333.123', true, 3, 3 ), 3 ) ); $this->assertEquals( '54333.1234', TTI18n::parseFloat( TTi18n::formatNumber( '54333.1234', true, 4, 4 ), 4 ) ); //Make sure parseFloat() can handle output from formatCurrency() $this->assertEquals( '54333.12', TTI18n::parseFloat( TTi18n::formatCurrency( '54333.1234' ) ) ); //Auto formatting decimals. $this->assertEquals( '54333.12', TTI18n::parseFloat( TTi18n::formatCurrency( '54333.12' ) ) ); $this->assertEquals( '54333.12', TTI18n::parseFloat( TTi18n::formatCurrency( '54333.123' ) ) ); $this->assertEquals( '54333.12', TTI18n::parseFloat( TTi18n::formatCurrency( '54333.1234' ) ) ); $this->assertEquals( '54333.12', TTI18n::parseFloat( TTi18n::formatCurrency( '54333.1234', 'EUR', true ) ) ); //Auto formatting decimals. $this->assertEquals( '54333.12', TTI18n::parseFloat( TTi18n::formatCurrency( '54333.12', 'EUR', true ) ) ); $this->assertEquals( '54333.12', TTI18n::parseFloat( TTi18n::formatCurrency( '54333.123', 'EUR', true ) ) ); $this->assertEquals( '54333.12', TTI18n::parseFloat( TTi18n::formatCurrency( '54333.1234', 'EUR', true ) ) ); TTi18n::setLocale( 'fr_CA' ); $this->assertEquals( '54333.12', TTI18n::parseFloat( '54333.12', 2 ) ); //Has only one separator, and input matches precision value. $this->assertEquals( '54333.12', TTI18n::parseFloat( '54333.12', 3 ) ); //Has only one separator, and input is 2 decimal places which DOES NOT match precision value. $this->assertEquals( '54333.123', TTI18n::parseFloat( '54333.123', 3 ) ); //Has only one separator, and input matches precision value. $this->assertEquals( '54333.1234', TTI18n::parseFloat( '54333.1234', 4 ) ); //Has only one separator, and input matches precision value. $this->assertEquals( '1234.123', TTI18n::parseFloat( '1.234,123' ) ); //Has both separators, so can be parsed properly. $this->assertEquals( '1234.123', TTI18n::parseFloat( '1. 234,123' ) ); //Has both separators, so can be parsed properly. $this->assertEquals( '1234.91', TTI18n::parseFloat( '1 234,91' ) ); $this->assertEquals( '12.91', TTI18n::parseFloat( '12,91' ) ); $this->assertEquals( '0.00', TTI18n::parseFloat( '0,00' ) ); $this->assertEquals( '12.123', TTI18n::parseFloat( (float)12.123 ) ); //If its input as an actual float value, it shouldn't be touched. TTi18n::setLocale( 'es_ES' ); if ( TTi18n::getThousandsSymbol() == '.' && TTi18n::getDecimalSymbol() == ',' ) { $this->assertEquals( '1234.123', TTI18n::parseFloat( '1.234,123' ) ); $this->assertEquals( '1234.123', TTI18n::parseFloat( '1. 234,123' ) ); $this->assertEquals( '12.91', TTI18n::parseFloat( '12,91' ) ); $this->assertEquals( '0.00', TTI18n::parseFloat( '0,00' ) ); $this->assertEquals( '12.123', TTI18n::parseFloat( (float)12.123 ) ); //If its input as an actual float value, it shouldn't be touched. $this->assertEquals( '12.9', TTI18n::parseFloat( '12.9', 1 ) ); //Ambiguous as it could be assumed to be 12.9, or 129 $this->assertEquals( '12.91', TTI18n::parseFloat( '12.91', 2 ) ); //Ambiguous as it could be assumed to be 12.91, or 12, 91 $this->assertEquals( '12.912', TTI18n::parseFloat( '12.912', 3 ) ); //Ambiguous as it could be assumed to be 12.912, or 12, 912 $this->assertEquals( '12.9123', TTI18n::parseFloat( '12.9123', 4 ) ); //Ambiguous as it could be assumed to be 12.9123, or 12, 9123 $this->assertEquals( '12.9', TTI18n::parseFloat( '12,9', 1 ) ); //Ambiguous as it could be assumed to be 12.9, or 129 $this->assertEquals( '12.91', TTI18n::parseFloat( '12,91', 2 ) ); //Ambiguous as it could be assumed to be 12.91, or 12, 91 $this->assertEquals( '12.912', TTI18n::parseFloat( '12,912', 3 ) ); //Ambiguous as it could be assumed to be 12.912, or 12, 912 $this->assertEquals( '12.9123', TTI18n::parseFloat( '12,9123', 4 ) ); //Ambiguous as it could be assumed to be 12.9123, or 12, 9123 $this->assertEquals( '12.9', TTI18n::parseFloat( '12,9' ) ); //Ambiguous as it could be assumed to be 12.9, or 129 -- However since there is only one separator and it matches the decimal separator in the locale we can be certain. $this->assertEquals( '12.91', TTI18n::parseFloat( '12,91' ) ); //Ambiguous as it could be assumed to be 12.91, or 12, 91 -- However since there is only one separator and it matches the decimal separator in the locale we can be certain. $this->assertEquals( '12.912', TTI18n::parseFloat( '12,912' ) ); //Ambiguous as it could be assumed to be 12.912, or 12, 912 -- However since there is only one separator and it matches the decimal separator in the locale we can be certain. $this->assertEquals( '12.9123', TTI18n::parseFloat( '12,9123' ) ); //Ambiguous as it could be assumed to be 12.9123, or 12, 9123 -- However since there is only one separator and it matches the decimal separator in the locale we can be certain. $this->assertEquals( '12.9', TTI18n::parseFloat( '12.9' ) ); //Ambiguous as it could be assumed to be 12.9, or 129 $this->assertEquals( '12.91', TTI18n::parseFloat( '12.91' ) ); //Ambiguous as it could be assumed to be 12.91, or 12, 91 $this->assertEquals( '12912', TTI18n::parseFloat( '12.912' ) ); //Ambiguous as it could be assumed to be 12.912, or 12, 912 $this->assertEquals( '12.9123', TTI18n::parseFloat( '12.9123' ) ); //Ambiguous as it could be assumed to be 12.9123, or 12, 9123 //Make sure parseFloat() can handle output from formatNumber() $this->assertEquals( '54333.12', TTI18n::parseFloat( TTi18n::formatNumber( '54333.1234' ) ) ); //Auto formatting decimals. $this->assertEquals( '54333.12', TTI18n::parseFloat( TTi18n::formatNumber( '54333.12' ) ) ); $this->assertEquals( '54333.123', TTI18n::parseFloat( TTi18n::formatNumber( '54333.123', true, 3, 3 ), 3 ) ); $this->assertEquals( '54333.1234', TTI18n::parseFloat( TTi18n::formatNumber( '54333.1234', true, 4, 4 ), 4 ) ); //Make sure parseFloat() can handle output from formatCurrency() $this->assertEquals( '54333.12', TTI18n::parseFloat( TTi18n::formatCurrency( '54333.1234' ) ) ); //Auto formatting decimals. $this->assertEquals( '54333.12', TTI18n::parseFloat( TTi18n::formatCurrency( '54333.12' ) ) ); $this->assertEquals( '54333.12', TTI18n::parseFloat( TTi18n::formatCurrency( '54333.123' ) ) ); $this->assertEquals( '54333.12', TTI18n::parseFloat( TTi18n::formatCurrency( '54333.1234' ) ) ); $this->assertEquals( '54333.12', TTI18n::parseFloat( TTi18n::formatCurrency( '54333.1234', 'EUR', true ) ) ); //Auto formatting decimals. $this->assertEquals( '54333.12', TTI18n::parseFloat( TTi18n::formatCurrency( '54333.12', 'EUR', true ) ) ); $this->assertEquals( '54333.12', TTI18n::parseFloat( TTi18n::formatCurrency( '54333.123', 'EUR', true ) ) ); $this->assertEquals( '54333.12', TTI18n::parseFloat( TTi18n::formatCurrency( '54333.1234', 'EUR', true ) ) ); } else { Debug::Text( 'ERROR: Locale differs, skipping unit tests...', __FILE__, __LINE__, __METHOD__, 1 ); } } /* * @noinspection PhpInconsistentReturnPointsInspection */ function testUserWage() { // //Test end-to-end setting of user wage and viewing it in a report. // TTDate::setTimeZone( 'America/Vancouver', true ); //Due to being a singleton and PHPUnit resetting the state, always force the timezone to be set. $dd = new DemoData(); $dd->setEnableQuickPunch( false ); //Helps prevent duplicate punch IDs and validation failures. $dd->setUserNamePostFix( '_' . uniqid( null, true ) ); //Needs to be super random to prevent conflicts and random failing tests. $company_id = $dd->createCompany(); $legal_entity_id = $dd->createLegalEntity( $company_id, 10 ); Debug::text( 'Company ID: ' . $company_id, __FILE__, __LINE__, __METHOD__, 10 ); $this->assertGreaterThan( 0, $company_id ); //Permissions are required so the user has permissions to run reports. $dd->createPermissionGroups( $company_id, 40 ); //Administrator only. $dd->createCurrency( $company_id, 10 ); $dd->createUserWageGroups( $company_id ); $user_id = $dd->createUser( $company_id, $legal_entity_id, 100 ); $user_idb = $dd->createUser( $company_id, $legal_entity_id, 10 ); //Delete all wages so we there is a clean slate and there are no random wages that might occur *after* the ones we create below, which would cause the report to be different. // Skip first wage on the employees hire date. $uwlf = TTnew('UserWageListFactory'); $uwlf->getByUserId( $user_id, [ 'effective_date' => 'asc', 'wage_group_id' => 'asc' ] ); if ( $uwlf->getRecordCount() > 0 ) { $i = 0; foreach( $uwlf as $uw_obj ) { if ( $i == 0 ) { //Skip first wage effective date. $i++; continue; } $uw_obj->setDeleted( true ); $uw_obj->Save(); $i++; } } $uwlf = TTnew('UserWageListFactory'); $uwlf->getByUserId( $user_idb, [ 'effective_date' => 'asc', 'wage_group_id' => 'asc' ] ); if ( $uwlf->getRecordCount() > 0 ) { $i = 0; foreach( $uwlf as $uw_obj ) { if ( $i == 0 ) { //Skip first wage effective date. $i++; continue; } $uw_obj->setDeleted( true ); $uw_obj->Save(); $i++; } } //Get User Object. $ulf = new UserListFactory(); $user_obj = $ulf->getById( $user_id )->getCurrent(); $this->assertGreaterThan( 0, $user_id ); TTi18n::setLocale( 'en_US' ); $uw = new UserWageFactory(); $data = [ 'user_id' => $user_id, 'type_id' => 20, //Salary Annual 'wage' => '54, 333.12', 'weekly_time' => ( 40 * 3600 ), 'hourly_rate' => '1, 123.98', 'labor_burden_percent' => '12.98%', 'effective_date' => strtotime( '01-Jan-2019' ), ]; $uw->setObjectFromArray( $data ); $insert_id = $uw->Save( false ); $uwlf = new UserWageListFactory(); $uwlf->getById( $insert_id ); $retarr = $uwlf->getCurrent()->getObjectAsArray(); //var_dump($retarr); $this->assertEquals( '54333.12', $retarr['wage'] ); $this->assertEquals( '1123.98', $retarr['hourly_rate'] ); $this->assertEquals( '12.98', $retarr['labor_burden_percent'] ); TTi18n::setLocale( 'fr_CA' ); $uw = new UserWageFactory(); $data = [ 'user_id' => $user_idb, 'type_id' => 20, //Salary Annual 'wage' => '54. 334,12', 'weekly_time' => ( 40 * 3600 ), 'hourly_rate' => '1. 124,98', 'labor_burden_percent' => '13,98%', 'effective_date' => strtotime( '01-Jan-2019' ), ]; $uw->setObjectFromArray( $data ); $insert_id = $uw->Save( false ); $uwlf = new UserWageListFactory(); $uwlf->getById( $insert_id ); $retarr = $uwlf->getCurrent()->getObjectAsArray(); //var_dump($retarr); $this->assertEquals( '54334.12', $retarr['wage'] ); $this->assertEquals( '1124.98', $retarr['hourly_rate'] ); $this->assertEquals( '13.98', $retarr['labor_burden_percent'] ); //Generate Report in en_US TTi18n::setLocale( 'en_US' ); $report_obj = new UserSummaryReport(); $report_obj->setUserObject( $user_obj ); $report_obj->setPermissionObject( new Permission() ); $report_config = Misc::trimSortPrefix( $report_obj->getTemplate( 'by_employee+wage' ) ); $report_config['columns'][] = 'labor_burden_percent'; $report_obj->setConfig( $report_config ); //var_dump($report_config); $report_output = $report_obj->getOutput( 'raw' ); //var_dump($report_output); $this->assertEquals( 54333.12, $report_output[0]['wage'] ); $this->assertEquals( 1123.98, $report_output[0]['hourly_rate'] ); $this->assertEquals( 12.98, $report_output[0]['labor_burden_percent'] ); $this->assertEquals( 54334.12, $report_output[1]['wage'] ); $this->assertEquals( 1124.98, $report_output[1]['hourly_rate'] ); $this->assertEquals( 13.98, $report_output[1]['labor_burden_percent'] ); //Generate Report in fr_CA TTi18n::setLocale( 'fr_CA' ); $report_obj = new UserSummaryReport(); $report_obj->setUserObject( $user_obj ); $report_obj->setPermissionObject( new Permission() ); $report_config = Misc::trimSortPrefix( $report_obj->getTemplate( 'by_employee+wage' ) ); $report_config['columns'][] = 'labor_burden_percent'; $report_obj->setConfig( $report_config ); //var_dump($report_config); $report_output = $report_obj->getOutput( 'raw' ); //var_dump($report_output); $this->assertEquals( 54333.12, $report_output[0]['wage'] ); $this->assertEquals( 1123.98, $report_output[0]['hourly_rate'] ); $this->assertEquals( 12.98, $report_output[0]['labor_burden_percent'] ); $this->assertEquals( 54334.12, $report_output[1]['wage'] ); $this->assertEquals( 1124.98, $report_output[1]['hourly_rate'] ); $this->assertEquals( 13.98, $report_output[1]['labor_burden_percent'] ); } function testRemoveTrailingZeros() { TTi18n::setLocale( 'en_US' ); $this->assertEquals( Misc::removeTrailingZeros( (float)123.45, 2 ), (float)123.45 ); $this->assertEquals( Misc::removeTrailingZeros( (float)123.45, 0 ), (float)123.45 ); $this->assertEquals( Misc::removeTrailingZeros( (float)123.450000, 2 ), (float)123.45 ); $this->assertEquals( Misc::removeTrailingZeros( '123.450000', 2 ), (float)123.45 ); $this->assertEquals( 'test', Misc::removeTrailingZeros( 'test', 2 ) ); //Make sure if it can't work with the input value, we just output it untouched. TTi18n::setLocale( 'fr_CA' ); $this->assertEquals( Misc::removeTrailingZeros( (float)123.45, 2 ), (float)123.45 ); $this->assertEquals( Misc::removeTrailingZeros( (float)123.45, 0 ), (float)123.45 ); $this->assertEquals( Misc::removeTrailingZeros( (float)123.450000, 2 ), (float)123.45 ); $this->assertEquals( Misc::removeTrailingZeros( '123.450000', 2 ), (float)123.45 ); $this->assertEquals( 'test', Misc::removeTrailingZeros( 'test', 2 ) ); //Make sure if it can't work with the input value, we just output it untouched. TTi18n::setLocale( 'es_ES' ); if ( TTi18n::getThousandsSymbol() == '.' && TTi18n::getDecimalSymbol() == ',' ) { $this->assertEquals( Misc::removeTrailingZeros( (float)123.45, 2 ), (float)123.45 ); $this->assertEquals( Misc::removeTrailingZeros( (float)123.45, 0 ), (float)123.45 ); $this->assertEquals( Misc::removeTrailingZeros( (float)123.450000, 2 ), (float)123.45 ); $this->assertEquals( Misc::removeTrailingZeros( '123.450000', 2 ), (float)123.45 ); $this->assertEquals( 'test', Misc::removeTrailingZeros( 'test', 2 ) ); //Make sure if it can't work with the input value, we just output it untouched. } else { Debug::Text( 'ERROR: Locale differs, skipping unit tests...', __FILE__, __LINE__, __METHOD__, 1 ); } } function testSetLocale() { $this->assertEquals( true, TTi18n::setLocale( 'en_GB' ) ); $this->assertEquals( 'en_GB.UTF-8', TTi18n::getLocale() ); $this->assertEquals( '€', TTi18n::getCurrencySymbol( 'EUR' ) ); $this->assertEquals( true, TTi18n::setLocale( 'en_CA' ) ); $this->assertEquals( 'en_CA.UTF-8', TTi18n::getLocale() ); $this->assertEquals( '$', TTi18n::getCurrencySymbol( 'CAD' ) ); } function testTranslations() { TTi18n::setLocale( 'es_ES' ); $this->assertEquals( 'Empleado', TTi18n::getText( 'Employee' ) ); TTi18n::setLocale( 'en_CA' ); $this->assertEquals( 'Employee', TTi18n::getText( 'Employee' ) ); TTi18n::setLocale( 'yi_US' ); $this->assertEquals( 'Z', TTi18n::getText( 'Employee' ) ); TTi18n::setLocale( 'fr_CA' ); //$this->assertEquals( TTi18n::getText( 'Saved Reports' ), 'Rapports sauvs' ); $this->assertEquals( 'Rapports enregistrés', TTi18n::getText( 'Saved Reports' ) ); TTi18n::setLocale( 'fr_FR' ); $this->assertEquals( 'Rapports enregistrés', TTi18n::getText( 'Saved Reports' ) ); TTi18n::setLocale( 'ar_EG' ); $this->assertEquals( 'Rapports enregistrés', TTi18n::getText( 'Saved Reports' ) ); //valid locale with no translations returns the original string. $this->assertEquals( 'Saved ReportsZZ', TTi18n::getText( 'Saved ReportsZZ' ) ); //valid locale with no translations returns the original string. TTi18n::setLocale( 'zz_ZZ' ); //Invalid locale gets ignored and uses the previous locale. //$this->assertEquals( 'Saved Reports', TTi18n::getText( 'Saved Reports' ) ); //invalid locale returns the original string. $this->assertEquals( 'Rapports enregistrés', TTi18n::getText( 'Saved Reports' ) ); //valid locale with no translations returns the original string. $this->assertEquals( false, TTi18n::detectUTF8( 'The quick brown fox jumped over the lazy dog 1234567890!@#$%^&*()_+' ) ); $this->assertEquals( true, TTi18n::detectUTF8( 'ᚠᛇᚻ᛫ᛒᛦᚦ᛫ᚠᚱᚩᚠᚢᚱ᛫ᚠᛁᚱᚪ᛫ᚷᛖᚻᚹᛦᛚᚳᚢᛗ' ) ); } function testStringFunctions() { TTi18n::setLanguage( 'en' ); $this->assertEquals( 'test', TTi18n::strtolower( 'TesT' ) ); TTi18n::setLanguage( 'fr' ); $this->assertEquals( 'cumulé', TTi18n::strtolower( 'Cumulé' ) ); TTi18n::setLanguage( 'cn' ); $this->assertEquals( '壹', TTi18n::strtolower( '壹' ) ); } //30,000 currrency formats on existing code took less than a second. //30,000 currrency formats on new code took 1.24 seconds //500,000 currrency formats on new code took 8.2 seconds //500,000 currrency formats on old code took 9.95 seconds // function testNumberFormatBenchmark() { // // TTi18n::setLocale('en_CA'); // $start_benchmark = time(); // for($i =0; $i<=500000; $i++){ // $n = TTi18n::formatCurrency($i.'.55555', 'CAD', true); // } // $end_benchmark = time(); // echo "time: " . ($end_benchmark - $start_benchmark); // } function testBCMath() { TTi18n::setLocale( 'en_US' ); $amount1 = 510.9; $amount2 = 90.9; $this->assertEquals( 601.80, bcadd( $amount1, $amount2, 2 ) ); $amount1 = '510.9'; $amount2 = '90.9'; $this->assertEquals( 601.80, bcadd( $amount1, $amount2, 2 ) ); //If we switch setLocale() back to setting LC_NUMERIC, need to make sure bcmath handles comma decimal separators correctly like in UserDateTotalFactory->calcTotalAmount() TTi18n::setLocale( 'es_ES' ); $amount1 = 510.9; $amount2 = 90.9; $this->assertEquals( 601.80, bcadd( $amount1, $amount2, 2 ) ); //BCMath fails handling floating point values with comma separator. $amount1 = '510.9'; $amount2 = '90.9'; $this->assertEquals( 601.80, bcadd( $amount1, $amount2, 2 ) ); //BCMath fails handling floating point values with comma separator. //This causes PHP fatal error on PHP v8.0.2: PHP ERROR - FATAL(1): Uncaught ValueError: bcadd(): Argument #1 ($num1) is not well-formed //$amount1 = '510,9'; //$amount2 = '90,9'; //@$this->assertEquals( 0.00, bcadd( $amount1, $amount2, 2 ) ); //BCMath fails handling floating point values with comma separator. // //Test to show that bcmath() breaks when using LC_NUMERIC locales. // TTi18n::setLocale( 'es_ES' ); $valid_locale = setlocale( LC_ALL, TTi18n::generateLocale( 'es_ES' ) ); //Could return 'es_ES' or 'es_ES.utf8' or 'es_ES.UTF-8' $normalized_locale = TTi18n::stripUTF8( $valid_locale ); $this->assertEquals( 'es_ES', $normalized_locale ); $amount1 = 510.9; $amount2 = 90.9; if ( version_compare( PHP_VERSION, '8.0', '>=' ) ) { //PHP v8.0 seems to handle comma separated floats. $this->assertEquals( 601.80, bcadd( $amount1, $amount2, 2 ) ); } else { @$this->assertEquals( 0.00, bcadd( $amount1, $amount2, 2 ) ); //BCMath fails handling floating point values with comma separator. } //This causes PHP fatal error on PHP v8.0.2: PHP ERROR - FATAL(1): Uncaught ValueError: bcadd(): Argument #1 ($num1) is not well-formed //$amount1 = '510,9'; //$amount2 = '90,9'; //@$this->assertEquals( 0.00, bcadd( $amount1, $amount2, 2 ) ); //BCMath fails handling floating point values with comma separator. //This causes PHP fatal error on PHP v8.0.2: PHP ERROR - FATAL(1): Uncaught ValueError: bcadd(): Argument #1 ($num1) is not well-formed //$amount1 = '123456710,9'; //$amount2 = '90,9'; //@$this->assertEquals( 0.00, bcadd( $amount1, $amount2, 2 ) ); //BCMath fails handling floating point values with comma separator. //Set locale back to the default so it doesn't affect other tests. setlocale( LC_ALL, TTi18n::generateLocale( 'en_US' ) ); TTi18n::setLocale( 'en_US' ); } }