RegressionTests__NumberTest.st
author Claus Gittinger <cg@exept.de>
Tue, 25 Feb 2020 17:19:49 +0100
changeset 2586 7dc7be5a6f3d
parent 2496 568e830146a8
permissions -rw-r--r--
#OTHER by cg s

"{ Package: 'stx:goodies/regression' }"

"{ NameSpace: RegressionTests }"

TestCase subclass:#NumberTest
	instanceVariableNames:'a b'
	classVariableNames:''
	poolDictionaries:''
	category:'tests-Regression-Numbers'
!


!NumberTest methodsFor:'accessing'!

a
    ^ a
!

a:something
    a := something.
!

b
    ^ b
!

b:something
    b := something.
! !

!NumberTest methodsFor:'initialize / release'!

tearDown
    Class withoutUpdatingChangesDo:[
        self class removeSelector:#testEQ
    ].
! !

!NumberTest methodsFor:'tests-comparing'!

test_minMax
    self assert:(0.5 min:1) = 0.5.
    self assert:(1.5 min:1) = 1.
    self assert:(2 min:1) = 1.
    self assert:(-1 min:1) = -1.

    self assert:(0.5 max:1) = 1.
    self assert:(1.5 max:1) = 1.5.
    self assert:(1.5 max:2) = 2.
    self assert:(2 max:1) = 2.
    self assert:(-1 max:1) = 1.

    self assert:(0.5 min:1 max:0) = 0.5.
    self assert:(1 min:1 max:0) = 1.
    self assert:(1.5 min:1 max:0) = 1.
    self assert:(2 min:1 max:0) = 1.
    self assert:(0 min:1 max:0) = 0.
    self assert:(0.0 min:1 max:0) = 0.
    self assert:(-1 min:1 max:0) = 0.
! !

!NumberTest methodsFor:'tests-concrete bugs'!

test_eqNumberBug
    "reported 09-09-2004;
     stc generated wrong code for some inlined = - compare (shame)."

    self 
        skipIf:ExternalAddress pointerSize = 8 
        description:'Compile does not work under 64bit'.

    false "(Helper
        isStcCompiledMethod:#test_eqNumberBug
        in:self
    )" ifTrue:[
        self 
            skipIf:true
            description:'#compile is not available in stand alone apps'.
    ].            

    Class withoutUpdatingChangesDo:[
        self class
            compile:
'testEQ
    a = b ifTrue:[^ false].
    ^ true.
'
            classified:'temporary'.
    ].

    self assert: (
       (self
           a:0;
           b:0) testEQ ) == false.

    self assert: (
       (self
           a:0;
           b:0.0) testEQ ) == false.

    self assert: (
       (self
           a:0.0;
           b:0) testEQ ) == false.

    self assert: (
       (self
           a:0.0;
           b:0.0) testEQ ) == false.

    Class withoutUpdatingChangesDo:[
        Compiler stcCompileMethod:(self class compiledMethodAt:#testEQ).
    ].

    self assert: (
       (self
           a:0;
           b:0) testEQ ) == false.

    self assert: (
       (self
           a:0;
           b:0.0) testEQ ) == false.

    self assert: (
       (self
           a:0.0;
           b:0) testEQ ) == false.

    self assert: (
       (self
           a:0.0;
           b:0.0) testEQ ) == false.

    Class withoutUpdatingChangesDo:[
        self class removeSelector:#testEQ
    ].

    "
     self new test_eqNumberBug
    "

    "Modified (format): / 06-05-2019 / 14:12:55 / Claus Gittinger"
    "Modified: / 21-05-2019 / 16:20:50 / Stefan Reise"
! !

!NumberTest methodsFor:'tests-conversion-rounding'!

test_conversion
    "reported as Bug 388
     Current implementation neither truncate nor round to nearest Floating point
     value, it just accumulate round off errors."


    self assert: 16r1FFFFFFFFFFFF0801 asDouble ~= 16r1FFFFFFFFFFFF0800 asDouble.
    "this test is on 65 bits"

    self assert: 16r1FFFFFFFFFFFF0802 asDouble ~= 16r1FFFFFFFFFFFF0800 asDouble.
    "this test is on 64 bits"

    self assert: 16r1FFFFFFFFFFF1F800 asDouble = 16r1FFFFFFFFFFF20000 asDouble.
    "nearest even is higher"
    self assert: 16r1FFFFFFFFFFFF0800 asDouble = 16r1FFFFFFFFFFFF0000 asDouble.
    "nearest even is lower"

    self assert: 16r1FFFFFFFFFFF1F800 asLongFloat ~= 16r1FFFFFFFFFFF20000 asLongFloat.
    self assert: 16r1FFFFFFFFFFFF0800 asLongFloat ~= 16r1FFFFFFFFFFFF0000 asLongFloat.

    "Created: / 24-10-2006 / 15:31:20 / cg"
! !

!NumberTest methodsFor:'tests-printing'!

testPrintf_FixedPoint
    "/ FixedPoint
    
    |pi|

    pi := FixedPoint pi.

    self assert:( (PrintfScanf printf:'%.4f' argument:pi) = '3.1416' ).
    self assert:( (PrintfScanf printf:'%.8f' argument:pi)  = '3.14159265' ).
    self assert:( (PrintfScanf printf:'%f' argument:pi)    = '3.141593' ).

    "/ too small
    self assert:( (pi printfPrintString:'%4Lf') = '3.141593' ).
    self assert:( (pi printfPrintString:'%5Lf') = '3.141593' ).
    self assert:( (pi printfPrintString:'%6Lf') = '3.141593' ).
    self assert:( (pi printfPrintString:'%7Lf') = '3.141593' ).
    "/ fit
    self assert:( (pi printfPrintString:'%8Lf') = '3.141593' ).
    self assert:( (pi printfPrintString:'%4.2Lf') = '3.14' ).
    "/ left filled
    self assert:( (pi printfPrintString:'%9Lf') = ' 3.141593' ).
    "/ right filled
    self assert:( (pi printfPrintString:'%-9Lf') = '3.141593 ' ).

    "Created: / 10-10-2017 / 12:36:21 / cg"
    "Modified: / 10-10-2017 / 16:29:20 / cg"
!

testPrintf_Float
    "/ Float
    
    |pi|

    pi := Float pi.

    self assert:( (PrintfScanf printf:'%.0f' argument:pi)  = '3' ).
    self assert:( (PrintfScanf printf:'%#.0f' argument:pi) = '3.0' ).  "/ hash forces print of '.0'
    self assert:( (PrintfScanf printf:'%.1f' argument:pi)  = '3.1' ).
    self assert:( (PrintfScanf printf:'%#.1f' argument:pi) = '3.1' ).
    self assert:( (PrintfScanf printf:'%.2f' argument:pi)  = '3.14' ).
    self assert:( (PrintfScanf printf:'%.3f' argument:pi)  = '3.142' ).
    self assert:( (PrintfScanf printf:'%.4f' argument:pi)  = '3.1416' ).
    self assert:( (PrintfScanf printf:'%.8f' argument:pi)  = '3.14159265' ).
    self assert:( (PrintfScanf printf:'%f' argument:pi)    = '3.141593' ).
    self assert:( (PrintfScanf printf:'%4f' argument:pi)   = '3.141593' ).

    "/ too small
    self assert:( (pi printfPrintString:'%4f') = '3.141593' ).
    self assert:( (pi printfPrintString:'%5f') = '3.141593' ).
    self assert:( (pi printfPrintString:'%6f') = '3.141593' ).
    self assert:( (pi printfPrintString:'%7f') = '3.141593' ).
    "/ fit
    self assert:( (pi printfPrintString:'%8f')   = '3.141593' ).
    self assert:( (pi printfPrintString:'%4.2f') = '3.14' ).
    "/ left filled
    self assert:( (pi printfPrintString:'%9f')   = ' 3.141593' ).
    self assert:( (pi printfPrintString:'%8.4f') = '  3.1416' ).

    "/ right filled
    self assert:( (pi printfPrintString:'%-9f') = '3.141593 ' ).

false ifTrue:[
    #(
        '%.3f'       1.0      '1.0'  
    ) inGroupsOf:3 do:[:fmt :val :expected|
        |printfGenerated stxGenerated|

        printfGenerated := val printfPrintString:fmt.
        stxGenerated := PrintfScanf printf:fmt argument:val.
        self assert:(stxGenerated = printfGenerated).
        self assert:(printfGenerated = expected).
    ].
].

    self assert:( (1.0 printfPrintString:'%4f') = '1.000000' ).
    self assert:( (1.0 printfPrintString:'%5f') = '1.000000' ).
    self assert:( (1.0 printfPrintString:'%6f') = '1.000000' ).
    self assert:( (1.0 printfPrintString:'%7f') = '1.000000' ).

    self assert:( (1.0 printfPrintString:'%.0f') = '1' ).
    self assert:( (1.0 printfPrintString:'%#.0f') = '1.' ).
    self assert:( (1.0 printfPrintString:'%#.0g') = '1.' ).
    self assert:( (1.0 printfPrintString:'%#.1f') = '1.0' ).
    self assert:( (1.0 printfPrintString:'%#.1g') = '1.' ).
    self assert:( (1.0 printfPrintString:'%.1f') = '1.0' ).
    self assert:( (1.0 printfPrintString:'%.2f') = '1.00' ).
    self assert:( (1.0 printfPrintString:'%.3f') = '1.000' ).
    self assert:( (1.0 printfPrintString:'%.4f') = '1.0000' ).
    self assert:( (1.0 printfPrintString:'%.5f') = '1.00000' ).
    self assert:( (1.0 printfPrintString:'%.6f') = '1.000000' ).
    self assert:( (1.0 printfPrintString:'%.7f') = '1.0000000' ).

    self assert:( (PrintfScanf printf:'%.0f' argument:1.0)  = '1' ).
false ifTrue:[
    self assert:( (PrintfScanf printf:'%#.0f' argument:1.0) = '3.0' ).  "/ hash forces print of '.0'
].
    self assert:( (PrintfScanf printf:'%.1f' argument:1.0)  = '1.0' ).
    self assert:( (PrintfScanf printf:'%#.1f' argument:1.0) = '1.0' ).
    self assert:( (PrintfScanf printf:'%.2f' argument:1.0)  = '1.0' ).
    self assert:( (PrintfScanf printf:'%.3f' argument:1.0)  = '1.0' ).
    self assert:( (PrintfScanf printf:'%.4f' argument:1.0)  = '1.0' ).
    self assert:( (PrintfScanf printf:'%.8f' argument:1.0)  = '1.0' ).
    self assert:( (PrintfScanf printf:'%f' argument:1.0)    = '1.0' ).
    self assert:( (PrintfScanf printf:'%4f' argument:1.0)   = ' 1.0' ).

    "Created: / 10-10-2017 / 12:34:51 / cg"
    "Modified: / 10-10-2017 / 16:32:01 / cg"
!

testPrintf_Fraction
    "/ Fraction
    |pi|

    pi := Fraction pi.

self assert:( (PrintfScanf printf:'%.4f' argument:pi) = '3.1416' ).
    self assert:( (PrintfScanf printf:'%.8f' argument:pi)  = '3.14159265' ).
    self assert:( (PrintfScanf printf:'%f' argument:pi)    = '3.141593' ).

    "/ too small
    self assert:( (pi printfPrintString:'%4Lf') = '3.141593' ).
    self assert:( (pi printfPrintString:'%5Lf') = '3.141593' ).
    self assert:( (pi printfPrintString:'%6Lf') = '3.141593' ).
    self assert:( (pi printfPrintString:'%7Lf') = '3.141593' ).
    "/ fit
    self assert:( (pi printfPrintString:'%8Lf') = '3.141593' ).
    self assert:( (pi printfPrintString:'%4.2Lf') = '3.14' ).
    "/ left filled
    self assert:( (pi printfPrintString:'%9Lf') = ' 3.141593' ).
    "/ right filled
    self assert:( (pi printfPrintString:'%-9Lf') = '3.141593 ' ).

    "Created: / 10-10-2017 / 12:37:25 / cg"
    "Modified: / 10-10-2017 / 16:29:27 / cg"
!

testPrintf_Integer
    |skipB systemIsWin32Bit|

    systemIsWin32Bit := OperatingSystem isMSWINDOWSlike and:[ ExternalAddress pointerSize == 4 ].

    "/ Integers

    "/ verify that our printf generates the same string as the system-printf.
    "/ Checks of printfPrintString: are here to make sure, that the system's printf is doing it right...)
    self assert:( (20 printfPrintString:'%d') = '20' ).
    self assert:( (20 printfPrintString:'% d') = ' 20' ).
    self assert:( (-20 printfPrintString:'% d') = '-20' ).
    self assert:( (20 printfPrintString:'%#d') = '20' ).
    self assert:( (20 printfPrintString:'%#5d') = '   20' ).
    self assert:( (20 printfPrintString:'% -#5d') = ' 20  ' ).
    self assert:( (20 printfPrintString:'%- #5d') = ' 20  ' ).
    self assert:( (20 printfPrintString:'%-# 5d') = ' 20  ' ).
    self assert:( (20 printfPrintString:'%-#5d') = '20   ' ).
    self assert:( (20 printfPrintString:'%-#05d') = '20   ' ).   "/ NOTICE
    self assert:( (20 printfPrintString:'%-0#5d') = '20   ' ).   "/ NOTICE
    "/ borland printf is wrong here
    (OperatingSystem isMSWINDOWSlike and:[ ExternalAddress pointerSize == 4]) ifTrue:[
        "/ skip
    ] ifFalse:[
        self assert:( (20 printfPrintString:'%0-#5d') = '20   ' ).   "/ NOTICE - some printf's dont do this correctly
        self assert:( (20 printfPrintString:'%0#-5d') = '20   ' ).   "/ NOTICE
    ].
    self assert:( (20 printfPrintString:'%#05d') = '00020' ).
    self assert:( (20 printfPrintString:'%+ 5d') = '  +20' ).
    self assert:( (20 printfPrintString:'%- 5d') = ' 20  ' ).     
    self assert:( (-20 printfPrintString:'%- 5d') = '-20  ' ).     
    self assert:( ( 20 printfPrintString:'%-+ 5d') = '+20  ' ).     
    self assert:( (-20 printfPrintString:'%-+ 5d') = '-20  ' ).     
    self assert:( ( 20 printfPrintString:'%+ 5d') = '  +20' ).     
    self assert:( (-20 printfPrintString:'%+ 5d') = '  -20' ).     
    self assert:( ( 0 printfPrintString:'%+ 5d') = '   +0' ).     
    self assert:( ( 0 printfPrintString:'%-+ 5d') = '+0   ' ).     

    self assert:( (20 printfPrintString:'%# 5d') = '   20' ).

    "/ skip with borland (that printf is wrong):
    skipB := #( 
                ('%D'  nil)     "/ not supported at all
                ('%#x' 0  )     "/ printf is wrong: always prepending 0x - even for 0 value
                ('%#o' 0  )     "/ printf is wrong: always prepending 0 - even for 0 value
             ).

    #(
        '%d'         20      '20'  
        '%d'        -20      '-20'  
        "/ '%D'         20      '20'      "/ works in ST/X and OSX-print, but not Win32-printf
        "/ '%D'        -20      '-20'     "/ works in ST/X and OSX-print, but not Win32-printf
        '%ld'        20      '20'  
        '%ld'       -20      '-20'  
        '%lld'       20      '20'  
        '%lld'      -20      '-20'  
        '%hd'        20      '20'  
        '%hd'       -20      '-20'  
        '%hhd'       20      '20'  
        '%hhd'      -20      '-20'  
        '%lhd'       20      '20'  
        '%hld'      -20      '-20'  
        '% d'        20      ' 20'  
        '% d'       -20      '-20'  
        '%#d'        20      '20'  
        '%#d'       -20      '-20'  
        '%5d'        20      '   20'  
        '%5d'       -20      '  -20'  
        '%-5d'       20      '20   '  
        '%-5d'      -20      '-20  '  
        '%05d'       20      '00020'  
        '%05d'      -20      '-0020'  
        '%-05d'      20      '20   '  
        '%-05d'     -20      '-20  '  
        '% 5d'       20      '   20'  
        '% 5d'      -20      '  -20'  
        '%- 5d'      20      ' 20  '  
        '%- 5d'     -20      '-20  '  
        '%.0d'       20      '20'  
        '%.0d'      -20      '-20'  
        '%.0d'        0      ''  
        '%x'         20      '14'  
        '%x'        255      'ff'  
        '%X'        255      'FF'  
        '%#x'       255      '0xff'  
        '%#X'       255      '0XFF'   "/ printf also uppercases the 'x'
        '%x'          0      '0'  
        '%#x'         0      '0'      "/ with zero, no 0x should be prepended
        '%#x'        20      '0x14'  
        '%5x'        20      '   14'  
        '%-5x'       20      '14   '  
        '%#5x'       20      ' 0x14'  
        '%-#5x'      20      '0x14 '  
        '%#-5x'      20      '0x14 '  
        '%#-5X'      20      '0X14 '  
     "/   '%x'   -20      '-14'  
        '%o'         20      '24'  
        '%o'          0      '0'  
        '%#o'        20      '024'  
        '%#o'         0      '0'        "/ with zero, no 0 should be prepended
        '%5o'        20      '   24'  
        '%-5o'       20      '24   '  
        '%#5o'       20      '  024'  
        '%-#5o'      20      '024  '  
        '%#-5o'      20      '024  '  
        '%-#05o'     20      '024  '  
        '%#05o'      20      '00024'  

        '%2d'      1234      '1234'  
     "/   '%2.2d'    1234      '1234'  
        '%2x'        10      ' a'  
        '%2X'        10      ' A'  
        '%02x'       10      '0a'  
        '%02X'       10      '0A'  
     "/   '%o'   -20      '-24'  
        '%#5d'       20      '   20'
        '%-#5d'     -20      '-20  '
        '%-#5d'     -20      '-20  '
        '%-#05d'    -20      '-20  '
        '%#05d'     -20      '-0020'
        '%-#5d'      20      '20   '
        '%-#5d'      20      '20   '
        '%-#05d'     20      '20   '
        '%-#05x'     20      '0x14 '
        '%#05x'      20      '0x014'

        '%.3x'   0xAFFE      'affe'      "/ max length ignored for numbers
    ) inGroupsOf:3 do:[:fmt :val :expected|
        |skip printfGenerated stxGenerated|

        skip := false.
        systemIsWin32Bit ifTrue:[
            skip := skipB contains:[:pair | (pair first = fmt) and:[(pair second ? val) = val]].
        ].
        skip ifTrue:[
            Transcript showCR:'skipped check for %1 (borland printf does not handle it correctly)' with:fmt
        ] ifFalse:[
            printfGenerated := val printfPrintString:fmt.
            stxGenerated := PrintfScanf printf:fmt argument:val.
            self assert:(stxGenerated = printfGenerated).
            self assert:(printfGenerated = expected).
        ]
    ].

    "/ hex

    self assert:( (PrintfScanf printf:'%x' argument:-20) = '-14' ).
    self assert:( (PrintfScanf printf:'%#x' argument:-20) = '-0x14' ).
    self assert:( (PrintfScanf printf:'%#7x' argument:-20) = '  -0x14' ).
    self assert:( (PrintfScanf printf:'%-#7x' argument:-20) = '-0x14  ' ).
    self assert:( (PrintfScanf printf:'%-#07x' argument:-20) = '-0x14  ' ).
    self assert:( (PrintfScanf printf:'%#07x' argument:-20) = '-0x0014' ).

    "/ octal

    self assert:( (PrintfScanf printf:'%o' argument:-20) = '-24' ).
    self assert:( (PrintfScanf printf:'%#o' argument:-20) = '-024' ).
    self assert:( (PrintfScanf printf:'%#5o' argument:-20) = ' -024' ).
    self assert:( (PrintfScanf printf:'%-#5o' argument:-20) = '-024 ' ).
    self assert:( (PrintfScanf printf:'%-#05o' argument:-20) = '-024 ' ).
    self assert:( (PrintfScanf printf:'%#05o' argument:-20) = '-0024' ).
!

testPrintf_LargeFloat
    "/ LargeFloat- unfinished

    |lf pi|

    pi := LargeFloat pi.

    self 
        skipIf:(Smalltalk isSmalltalkDevelopmentSystem not)
        description:'work in progress'.

    self 
        skipIf:(Smalltalk at:#LargeFloat) isNil  
        description:'LargeFloat is not loaded'.

    self assert:(pi printString) = '3.141592653590' "'3.141592653589793238462643383280'".
    self assert:( (PrintfScanf printf:'%.4f' argument:pi)  = '3.1416' ).
    self assert:( (PrintfScanf printf:'%.8f' argument:pi)  = '3.14159265' ).
    "/ disabled, as we currently get different results on different machines
    "/                                                                                                         0.0000000000000000000000033832795028841888829163053742377087
    "/ self assert:( (PrintfScanf printf:'%f' argument:pi-(LargeFloat readFrom:'3.14159265358979323846264')) = '0.0000000000000000000000033832795028841973206112925254274159' "'0.00000000000000000000000338328'" ).
    self assert:( (PrintfScanf printf:'%f' argument:pi)    = '3.14159265359' "'3.141592653589793238462643383280'" ).

    "/ too small                                              
    self assert:( (pi printfPrintString:'%4Lf') = '3.14159265359' "'3.141592653589793238462643383280'" ).
    self assert:( (pi printfPrintString:'%5Lf') = '3.14159265359' "'3.141592653589793238462643383280'" ).
    self assert:( (pi printfPrintString:'%6Lf') = '3.14159265359' "'3.141592653589793238462643383280'" ).
    self assert:( (pi printfPrintString:'%7Lf') = '3.14159265359' "'3.141592653589793238462643383280'" ).
    "/ fit
    self assert:( (pi printfPrintString:'%8Lf') = '3.14159265359' "'3.141592653589793238462643383280'" ).
    self assert:( (pi printfPrintString:'%4.2Lf') = '3.14' ).
    self assert:( (pi printfPrintString:'%4.3Lf') = '3.142' ).
    self assert:( (pi printfPrintString:'%4.4Lf') = '3.1416' ).
    self assert:( (pi printfPrintString:'%4.5Lf') = '3.14159' ).
    self assert:( (pi printfPrintString:'%4.6Lf') = '3.141593' ).
    
    "/ left filled                                               
    self assert:( (pi printfPrintString:'%9Lf') = '3.14159265359' "' 3.141593'" ).
    "/ right filled
    self assert:( (pi printfPrintString:'%-9Lf') = '3.14159265359' "'3.141593 '" ).

    "/ exact (to 130 digits)  value is:
    "/ 3.1415926535 8979323846 2643383279 5028841971 6939937510 5820974944 5923078164 0628620899 8628034825 3421170679 8214808651 3282306647 
    "/ ((LargeFloat fromString:'3.141592653589793238462643383279') printfPrintString:'%4.20Lf')

    lf := 1 asLargeFloat.
    self assert:( (lf printfPrintString:'%4.20Lf') = ' 1.0' ).
    lf := lf / 10.
    self assert:( (lf printfPrintString:'%4.20Lf') = ' 0.1' ).
    lf := lf / 10.
    self assert:( (lf printfPrintString:'%4.20Lf') = '0.01' ).
    lf := lf / 10.
    self assert:( (lf printfPrintString:'%4.20Lf') = '0.001' ).
    lf := lf / 10.
    self assert:( (lf printfPrintString:'%4.20Lf') = '0.0001' ).
    lf := lf / 10.
    self assert:( (lf printfPrintString:'%4.20Lf') = '0.00001' ).
    lf := lf / 10.
    self assert:( (lf printfPrintString:'%4.20Lf') = '0.000001' ).
    lf := lf / 10.
    self assert:( (lf printfPrintString:'%4.20Lf') = '0.0000001' ).
    lf := lf / 10.
    self assert:( (lf printfPrintString:'%4.20Lf') = '0.00000001' ).
    lf := lf / 10.
    self assert:( (lf printfPrintString:'%4.20Lf') = '0.000000001' ).
    lf := lf / 10.
    self assert:( (lf printfPrintString:'%4.20Lf') = '0.0000000001' ).
    lf := lf / 10.
    self assert:( (lf printfPrintString:'%4.20Lf') = '0.00000000001' ).
    lf := lf / 10.
    self assert:( (lf printfPrintString:'%4.20Lf') = '0.000000000001' ).
    lf := lf / 10.
    self assert:( (lf printfPrintString:'%4.20Lf') = '0.0000000000001' ).
    lf := lf / 10.
    self assert:( (lf printfPrintString:'%4.20Lf') = '0.00000000000001' ).
    lf := lf / 10.
    self assert:( (lf printfPrintString:'%4.20Lf') = '0.000000000000001' ).
    lf := lf / 10.
    self assert:( (lf printfPrintString:'%4.20Lf') = '0.0000000000000001' ).
    lf := lf / 10.
    self assert:( (lf printfPrintString:'%4.20Lf') = '0.00000000000000001' ).
    lf := lf / 10.
    self assert:( (lf printfPrintString:'%4.20Lf') = '0.000000000000000001' ).
    lf := lf / 10.
    self assert:( (lf printfPrintString:'%4.20Lf') = '0.0000000000000000001' ).
    lf := lf / 10.
    self assert:( (lf printfPrintString:'%4.21Lf') = '0.00000000000000000001' ).
    lf := lf / 10.
    self assert:( (lf printfPrintString:'%4.22Lf') = '0.000000000000000000001' ).
    lf := pi.
    self assert:( (lf printString) = '3.141592653590' ).
    self assert:( (lf printfPrintString:'%4.20Lf') = '3.14159265358979323846' ).
    lf := lf - 3.
    self assert:( (lf printfPrintString:'%4.20Lf') = '0.14159265358979323846' ).

    "Created: / 10-10-2017 / 16:25:25 / cg"
    "Modified: / 05-06-2019 / 20:15:13 / Claus Gittinger"
    "Modified (comment): / 22-07-2019 / 19:40:10 / Claus Gittinger"
!

testPrintf_LongFloat
    "/ LongFloat
    
    |pi|

    pi := LongFloat pi.

    self assert:( (PrintfScanf printf:'%.4f' argument:pi)  = '3.1416' ).
    self assert:( (PrintfScanf printf:'%.8f' argument:pi)  = '3.14159265' ).
    self assert:( (PrintfScanf printf:'%f' argument:pi)  = '3.14159265' ).

    "/ LongFloat

    "/ too small
    self assert:( (pi printfPrintString:'%4Lf') = '3.141593' ).
    self assert:( (pi printfPrintString:'%5Lf') = '3.141593' ).
    self assert:( (pi printfPrintString:'%6Lf') = '3.141593' ).
    self assert:( (pi printfPrintString:'%7Lf') = '3.141593' ).
    "/ fit
    self assert:( (pi printfPrintString:'%8Lf') = '3.141593' ).
    self assert:( (pi printfPrintString:'%4.2Lf') = '3.14' ).
    "/ left filled
    self assert:( (pi printfPrintString:'%9Lf') = ' 3.141593' ).
    "/ right filled
    self assert:( (pi printfPrintString:'%-9Lf') = '3.141593 ' ).

    "Created: / 10-10-2017 / 12:35:40 / cg"
    "Modified: / 10-10-2017 / 16:29:56 / cg"
!

testPrintf_Misc

    "/ verify that our printf generates the same string as the system-printf.
    "/ Checks of printfPrintString: are here to make sure, that the system's printf is doing it right...)
    self assert:( (20 printfPrintString:'%%%d') = '%20' ).
    self assert:( (20 printfPrintString:'%d%%') = '20%' ).
    "/ borland is wrong here
    (OperatingSystem isMSWINDOWSlike and:[ExternalAddress pointerSize == 4]) ifFalse:[
        self assert:( (20 printfPrintString:'%d%') = '20' ).
    ].
    self assert:( PrintfScanf printf:'%d%' argument:20 ) = '20' .

    self assert:( (20 printfPrintString:'%%') = '%' ).
    "/ nobody knows what should happen...
    "/ self assert:( (20 printfPrintString:'\%\') = '\' ).
    "/ self assert:( (20 printfPrintString:'\%') = '%' ).
    
    {
        '%f'   .   Float NaN                .  'nan'  .
        '%F'   .   Float NaN                .  'NAN'  .
        '%f'   .   Float infinity           .  'inf'  .
        '%F'   .   Float infinity           .  'INF'  .
        '%f'   .   Float negativeInfinity   .  '-inf'  .
        '%F'   .   Float negativeInfinity   .  '-INF'  .

        '%+f'  .   Float NaN                .  'nan'  .    
        '%+F'  .   Float NaN                .  'NAN'  .    
        '%+f'  .   Float NaN negated        .  'nan'  .    
        '%+F'  .   Float NaN negated        .  'NAN'  .    
        '%+f'  .   Float infinity           .  '+inf'  .
        '%+F'  .   Float infinity           .  '+INF'  .
        '%+f'  .   Float negativeInfinity   .  '-inf'  .
        '%+F'  .   Float negativeInfinity   .  '-INF'  .

        '% f'  .   Float NaN                .  'nan'  .    "/ not sure if that is reasonable (but printf does the same) 
        '% F'  .   Float NaN                .  'NAN'  .    "/ not sure if that is reasonable (but printf does the same)
        '% f'  .   Float infinity           .  ' inf'  .
        '% F'  .   Float infinity           .  ' INF'  .
        '% f'  .   Float negativeInfinity   .  '-inf'  .
        '% F'  .   Float negativeInfinity   .  '-INF'  .
    } inGroupsOf:3 do:[:fmt :val :expected|
        |printfGenerated stxGenerated|

        printfGenerated := val printfPrintString:fmt.
        stxGenerated := PrintfScanf printf:fmt argument:val.

        self assert:(stxGenerated = expected).

        "/ borland printf generates uppercase 'NAN' for %f
        ((fmt = '%f') and:[ stxGenerated = printfGenerated asLowercase]) ifFalse:[
            "/ borland printf does not handle %F
            ((fmt = '%F') and:[ printfGenerated = '%F']) ifFalse:[
                "/ borland printf is completely wrong with %+f
                ((fmt = '%+f') and:[ printfGenerated = '++NAN']) ifFalse:[
                    self assert:(stxGenerated = printfGenerated).
                ].
            ].
        ].
    ].

    #(
        '%r'       1234      'r'  
        '%3r'      1234      '  r'  
        '%-3r'      1234     'r  '  
        '%#r'      1234      'r'  
      "/  '%v'       1234      'v'  
        '%Id'      1234      'Id'  
        '%%%d'         20      '%20'  
        '%d%%'         20      '20%'  
        '%d%'          20      '20'  
        '%%a%%'        20      '%a%'  
    ) inGroupsOf:3 do:[:fmt :val :expected|
        |printfGenerated stxGenerated|

        printfGenerated := val printfPrintString:fmt.
        stxGenerated := PrintfScanf printf:fmt argument:val.
        self assert:(stxGenerated = printfGenerated).
        self assert:(printfGenerated = expected).
    ].

    "/ more examples from "Secretes of printf"
    self assert:( (0 printfPrintString:'%d') = '0' ).
    self assert:( (-7 printfPrintString:'%d') = '-7' ).
    self assert:( (1560133635 printfPrintString:'%d') = '1560133635' ).
    self assert:( (-2035065302 printfPrintString:'%d') = '-2035065302' ).
!

testPrintf_More2
    "/ additional test patterns from secrets of printf
    "/ https://www.cypress.com/file/54441/download

    {
        '%d'  .            0       . '0'     .
        '%d'  .           -7       . '-7'     .
        '%d'  .   1560133635       . '1560133635'     .
        '%d'  .  -2035065302       . '-2035065302'     .

        '%5d'  .           0       . '    0'     .
        '%5d'  .          -7       . '   -7'     .
        '%5d'  .  1560133635       . '1560133635'     .
        '%5d'  . -2035065302       . '-2035065302'     .

        '%-5d'  .           0       . '0    '     .
        '%-5d'  .          -7       . '-7   '     .
        '%-5d'  .  1560133635       . '1560133635'     .
        '%-5d'  . -2035065302       . '-2035065302'     .

        '%05d'  .           0       . '00000'     .
        '%05d'  .          -7       . '-0007'     .
        '%05d'  .  1560133635       . '1560133635'     .
        '%05d'  . -2035065302       . '-2035065302'     .

        '%+5d'  .           0       . '   +0'     .
        '%+5d'  .          -7       . '   -7'     .
        '%+5d'  .  1560133635       . '+1560133635'     .
        '%+5d'  . -2035065302       . '-2035065302'     .

        '%+-5d'  .           0       . '+0   '     .
        '%+-5d'  .          -7       . '-7   '     .
        '%+-5d'  .  1560133635       . '+1560133635'     .
        '%+-5d'  . -2035065302       . '-2035065302'     .

        '% -5d'  .           0       . ' 0   '     .
        '% -5d'  .          -7       . '-7   '     .
        '% -5d'  .  1560133635       . ' 1560133635'     .
        '% -5d'  . -2035065302       . '-2035065302'     .

        '% 05d'  .           0       . ' 0000'     .
        '% 05d'  .          -7       . '-0007'     .
        '% 05d'  .  1560133635       . ' 1560133635'     .
        '% 05d'  . -2035065302       . '-2035065302'     .

        '%+05d'  .           0       . '+0000'     .
        '%+05d'  .          -7       . '-0007'     .
        '%+05d'  .  1560133635       . '+1560133635'     .
        '%+05d'  . -2035065302       . '-2035065302'     .

    } inGroupsOf:3 do:[:fmt :val :expected|
        |printfGenerated stxGenerated|

        printfGenerated := val printfPrintString:fmt.
        stxGenerated := PrintfScanf printf:fmt argument:val.
        self assert:(stxGenerated = printfGenerated).
        self assert:(printfGenerated = expected).
    ].
!

testPrintf_QDouble
    "/ QDouble
    |pi|

    pi := QDouble pi.

    self 
        skipIf:(OperatingSystem isUNIXlike and:[ExternalAddress pointerSize = 4])
        description:'Fails under Linux32'.

    self assert:( (PrintfScanf printf:'%.4f' argument:pi)  = '3.1416' ).
    self assert:( (PrintfScanf printf:'%.8f' argument:pi)  = '3.14159265' ).
    self assert:( (PrintfScanf printf:'%f' argument:pi)    = '3.1415926536' ).

    self assert:( (pi printfPrintString:'%4Lf') = '3.1415926536' ).
    self assert:( (pi printfPrintString:'%5Lf') = '3.1415926536' ).
    self assert:( (pi printfPrintString:'%6Lf') = '3.1415926536' ).
    self assert:( (pi printfPrintString:'%7Lf') = '3.1415926536' ).
    self assert:( (pi printfPrintString:'%10Lf') = '3.1415926536' ).
    self assert:( (pi printfPrintString:'%11Lf') = '3.1415926536' ).
    self assert:( (pi printfPrintString:'%12Lf') = '3.1415926536' ).
    "/ left filled
    self assert:( (pi printfPrintString:'%13Lf') = ' 3.1415926536' ).
    self assert:( (pi printfPrintString:'%18Lf') = '      3.1415926536' ).
    self assert:( (pi printfPrintString:'%19Lf') = '       3.1415926536' ).
    self assert:( (pi printfPrintString:'%20Lf') = '        3.1415926536' ).
    self assert:( (pi printfPrintString:'%21Lf') = '         3.1415926536' ).
    self assert:( (pi printfPrintString:'%4.2Lf') = '3.14' ).
    "/ right filled
    self assert:( (pi printfPrintString:'%-20Lf') = '3.1415926536        ' ).

    "Created: / 10-10-2017 / 12:24:22 / cg"
    "Modified: / 10-10-2017 / 16:28:51 / cg"
!

testPrintf_ShortFloat
    |pi|

    pi := ShortFloat pi.
    self assert:( (PrintfScanf printf:'%.4f' argument:pi) = '3.1416' ).
    self assert:( (PrintfScanf printf:'%f' argument:pi) = '3.14159' ).

    "/ ShortFloat

    "/ too small
    self assert:( (pi printfPrintString:'%4f') = '3.141593' ).
    self assert:( (pi printfPrintString:'%5f') = '3.141593' ).
    self assert:( (pi printfPrintString:'%6f') = '3.141593' ).
    self assert:( (pi printfPrintString:'%7f') = '3.141593' ).
    "/ fit
    self assert:( (pi printfPrintString:'%8f') = '3.141593' ).
    self assert:( (pi printfPrintString:'%4.2f') = '3.14' ).

    "/ left filled
    self assert:( (pi printfPrintString:'%9f') = ' 3.141593' ).
    self assert:( (pi printfPrintString:'%8.4f') = '  3.1416' ).

    "/ right filled
    self assert:( (pi printfPrintString:'%-9f') = '3.141593 ' ).
    self assert:( (pi printfPrintString:'%-8.4f') = '3.1416  ' ).

    "Created: / 10-10-2017 / 12:35:12 / cg"
    "Modified: / 10-10-2017 / 16:32:31 / cg"
! !

!NumberTest methodsFor:'tests-reading'!

testReadFrom
    self assert: 1.0e-14    = (Number readFrom: '1.0e-14').

    #(
        '0.8'                 0.8                 '0.8' 
        '0'                   0                   '0' 
        '-0'                  0                   '0' 
        '00'                  0                   '0' 
        '000'                 0                   '0' 
        '0x0'                 0                   '0' 
        '0b0'                 0                   '0' 
        '16r0'                0                   '0' 
        '4865804016353280000' 4865804016353280000 '4865804016353280000'
    ) inGroupsOf:3 do:[:str :expected :expectedPrintString|
        |gotVal|

        self assert:(gotVal := Number readFrom:str) = expected.
        self assert:expected printString = expectedPrintString.
    ].

    self assert: ('1' asNumber = 1).
    self assert: ('10' asNumber = 10).

    self assert: ('-1' asNumber = -1).
    self assert: ('-10' asNumber = -10).

    self assert: ('1e' asNumber = 1).
    self assert: ('1e1' asNumber = 10).
    self assert: ('1e10' asNumber = 10000000000).

    self assert: ('-1e' asNumber = -1).
    self assert: ('-1e1' asNumber = -10).
    self assert: ('-1e10' asNumber = -10000000000).

    self assert: ('1.0e' asNumber = 1.0).
    self assert: ('1.0e1' asNumber = 10.0).
    self assert: ('1.0e10' asNumber = 10000000000.0).

    self assert: ('-1.0e' asNumber = -1.0).
    self assert: ('-1.0e1' asNumber = -10.0).
    self assert: ('-1.0e10' asNumber = -10000000000.0).

    self assert: ('22.2' asNumber = 22.2).
    self assert: ('-22.2' asNumber = -22.2).

    self assert: ((Number readFrom:'0xaffe') = 45054).
    self assert: ((Number readFrom:'0b1010') = 10).
    self assert: ((Number readFrom:'0o177') = 127).
    self assert: ((Number readFrom:'0Xaffe') = 45054).
    self assert: ((Number readFrom:'0B1010') = 10).
    self assert: ((Number readFrom:'0O177') = 127).

    self assert: ((Number readFrom:'-0xaffe') = -45054).
    self assert: ((Number readFrom:'-0b1010') = -10).
    self assert: ((Number readFrom:'-0o177') = -127).
    self assert: ((Number readFrom:'-0Xaffe') = -45054).
    self assert: ((Number readFrom:'-0B1010') = -10).
    self assert: ((Number readFrom:'-0O177') = -127).

    self assert: ((Integer readFrom:'0x-affe') = -45054).
    self should: [ Number readFrom:'0x-affe' ] raise:Error.
    self should: [ Number readFrom:'0b-1010' ] raise:Error.  
    self should: [ Number readFrom:'0o-177' ] raise:Error.  
    self should: [ Number readFrom:'0X-affe' ] raise:Error.  
    self should: [ Number readFrom:'0B-1010' ] raise:Error.  
    self should: [ Number readFrom:'0O-177' ] raise:Error.  

    Smalltalk isSmalltalkX ifTrue:[
        "/ st/x requires this:

        self assert: ((Number readSmalltalkSyntaxFrom:'10r5.5') = 5.5).
        self assert: ((Number readSmalltalkSyntaxFrom:'16r5.5') = 5.3125).
        self assert: ((Number readSmalltalkSyntaxFrom:'3r1.1e2') = 12).
        self assert: ((Number readSmalltalkSyntaxFrom:'3r1.1e10') = 78732.0).
        self assert: ((Number readSmalltalkSyntaxFrom:'16r10.1e10') = 16.117431640625).

        self assert: ((Number readSmalltalkSyntaxFrom:'10r22.2') = 22.2).
        self assert: ((Number readSmalltalkSyntaxFrom:'10r22.2s5') = 22.2).

        self assert: ((Number readSmalltalkSyntaxFrom:'10r-22.2') = -22.2).
        self assert: ((Number readSmalltalkSyntaxFrom:'10r-22.2s5') = -22.2).
        self assert: ((Number readSmalltalkSyntaxFrom:'0xaffe') = 45054).

        "/ test fails when stc code, byte code works
        (Helper 
            isStcCompiledMethod:#'testReadFrom'
            in:self) ifTrue:[ 
                self logSkipped:'2r1e26 is not valid in stc code -> debugger doesNotUnderstand: #e26'.
            ] ifFalse:[    
                self assert: 2r1e26     = (Number readSmalltalkSyntaxFrom: '2r1e26').
            ].

        self assert: ('-1q' asNumber = -1).
        self assert: ('-1q' asNumber class == LongFloat).

        self assert: ('-1q1' asNumber = -10).
        self assert: ('-1q10' asNumber = -10000000000).
    ] ifFalse:[
        "/ squeak allows this:
        self assert: 2r1e26     = (Number readFrom: '2r1e26').

        self assert: ('10r22.2' asNumber = 22.2).
        self assert: ('10r22.2s5' asNumber = 22.2).

        self assert: ('10r-22.2' asNumber = -22.2).
        self assert: ('10r-22.2s5' asNumber = -22.2).
    ].

    "Modified: / 20-06-2017 / 14:05:37 / cg"
    "Modified: / 17-12-2019 / 14:39:17 / Stefan Reise"
!

testReadFrom2
    |n|

     n := Number readFrom:(ReadStream on:'54.32e-01') decimalPointCharacters:'.' onError:[self halt].
     self assert:(n = 5.432).

     n := Number readFrom:(ReadStream on:'12345') decimalPointCharacters:'.' onError:[self halt].
     self assert:(n = 12345).

     n := Number readFrom:(ReadStream on:'12345.0') decimalPointCharacters:'.' onError:[self halt].
     self assert:(n = 12345.0).

     n := Number readFrom:(ReadStream on:'12345.0f') decimalPointCharacters:'.' onError:[self halt].
     self assert:(n = 12345.0).

     n := Number readFrom:(ReadStream on:'12345.0e') decimalPointCharacters:'.' onError:[self halt].
     self assert:(n = 12345.0).

     n := Number readFrom:(ReadStream on:'12345.0q') decimalPointCharacters:'.' onError:[self halt].
     self assert:(n = 12345.0).

     n := Number readFrom:(ReadStream on:'12345.0d') decimalPointCharacters:'.' onError:[self halt].
     self assert:(n = 12345.0).

     n := Number readFrom:(ReadStream on:'12345.0s') decimalPointCharacters:'.' onError:[self halt].
     self assert:(n = 12345.0).

     n := Number readFrom:(ReadStream on:'12345.01s') decimalPointCharacters:'.' onError:[self halt].
     self assert:(n = 12345.01).

     n := Float readFrom:(ReadStream on:'12345') decimalPointCharacters:'.' onError:[self halt].
     self assert:(n = 12345.0).

     n := Number readFrom:(ReadStream on:'12345678901234567890').
     self assert:(n = 12345678901234567890).
     n := Number readFrom:(ReadStream on:'12345678901234567890.0').
     self assert:(n = 12345678901234567890.0).

     n := Number readFrom:(ReadStream on:'12345678901234567890.012345678901234567890').
     self assert:(n closeTo: 12345678901234567890.012345678901234567890).

     n := Number readFrom:(ReadStream on:'16rAAAAFFFFAAAAFFFF').
     self assert:(n = 16rAAAAFFFFAAAAFFFF).

     n := Number readFrom:'16rAAAAFFFFAAAAFFFF'.
     self assert:(n = 16rAAAAFFFFAAAAFFFF).

     n := Number readFrom:'16r100A'.
     self assert:(n = 16r100A).

     n := Number readFrom:'16r100a'.  
     self assert:(n = 16r100A).

     n := Number readFrom:'16r-100A'.      
     self assert:(n = -16r100A).

     n := Number readFrom:'-16r100A'.      
     self assert:(n = -16r100A).

     n := Number readFrom:'0x100A'.      
     self assert:(n = 16r100A).

     n := Number readFrom:'-0x100A'.      
     self assert:(n = -16r100A).

     self should:[ n := Number readFrom:'0x-100A' ] raise:Error.      
     n := Number readFrom:'0.000001'.
     n := '+00000123.45' asNumber.
     n := Number readFrom:'(1/3)'.
     n := Number readFrom:'(-1/3)'.
     n := Number readFrom:'(1/-3)'.
     n := Number readFrom:'-(1/3)'.
     n := Number readFrom:'-(-1/3)'.
     self should:[ n := Number readFrom:'(-1/3' ] raise:Error. 
     n := Number readFrom:'99s'.
     n := Number readFrom:'99.00s'.
     n := Number readFrom:'99.0000000s'.
     n := Number readFrom:'.0000000s'.
     n := Number readFrom:'.0000000q'.
     n := Number readFrom:'.0000000f'.
     n := Number readFrom:'.0000000e'.
     n := Number readFrom:'.0000000s1'.
     n := Number readFrom:'.0000000q1'.
     n := Number readFrom:'.0000000f1'.
     n := Number readFrom:'.0000000e1'.
     n := LongFloat readFrom:'.00000001'.
     n := Number readFrom:'.00000000000001'.
     n := Number readFrom:'.001'.
     n := ShortFloat readFrom:'.001'.
     n := Number readFrom:'123garbage'. "/      -> returns 123
     self should:[ n := Number fromString:'123garbage'] raise:Error.

     n := Number readFrom:'99,00' decimalPointCharacters:#( $. $, ). 
     n := Number readFrom:'99,00' decimalPointCharacters:#( $. ).    
! !

!NumberTest class methodsFor:'documentation'!

version
    ^ '$Header$'
!

version_CVS
    ^ '$Header$'
! !