encoding-guesser: Avoid reading uninitialized data for zero-length files.
[pspp] / tests / language / expressions / evaluate.at
index 846eee482b858a3f359df1bfa9685fa7f2050080..cd574eb10f79eb8cea949a754d6b20ffc2947355 100644 (file)
@@ -1,5 +1,21 @@
+dnl PSPP - a program for statistical analysis.
+dnl Copyright (C) 2017 Free Software Foundation, Inc.
+dnl
+dnl This program is free software: you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation, either version 3 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program.  If not, see <http://www.gnu.org/licenses/>.
 m4_define([CHECK_EXPR_EVAL],
   [AT_SETUP([expressions - $1])
+   AT_KEYWORDS([expression])
    AT_DATA([evaluate.sps],
      [set mxwarn 1000.
 set mxerr 1000.
@@ -10,14 +26,10 @@ DEBUG EVALUATE m4_argn(4, check)/[]m4_car(check).
 ])])
    AT_CAPTURE_FILE([evaluate.sps])
    m4_pushdef([i], [3])
-   AT_CHECK([pspp --testing-mode --error-file=- --no-output evaluate.sps], 
-     [m4_if(m4_bregexp([m4_foreach([check], [m4_shift($@)], [m4_argn(3, check)])], [error:]), [-1], [0], [1])], 
+   AT_CHECK([pspp --testing-mode -O format=csv evaluate.sps],
+     [m4_if(m4_bregexp([m4_foreach([check], [m4_shift($@)], [m4_argn(3, check)])], [error:]), [-1], [0], [1])],
      [stdout])
-   # Use sed to transform "file:line.column:" into plain "file:line:",
-   # because column numbers change between opt and noopt versions.
-   AT_CHECK([[sed 's/\(evaluate.sps:[0-9]\{1,\}\)\.[0-9]\{1,\}:/\1:/' stdout]],
-     [0],
-     [m4_foreach([check], [m4_shift($@)],
+   AT_DATA([expout], [m4_foreach([check], [m4_shift($@)],
         [m4_define([i], m4_incr(i))dnl
 m4_if(m4_argn(3, check), [], [], [evaluate.sps:[]i[]: m4_argn(3, check)
 ])dnl
@@ -26,7 +38,21 @@ m4_define([i], m4_incr(i))dnl
 m4_if(m4_argn(3, check), [], [], [evaluate.sps:[]i[]: m4_argn(3, check)
 ])dnl
 m4_argn(2, check)
-])], [])
+])])
+   AT_CHECK([[sed '
+# Transform "file:line.column:" into plain "file:line:",
+# because column numbers change between opt and noopt versions.
+s/\(evaluate.sps:[0-9]\{1,\}\)\.[0-9]\{1,\}:/\1:/
+
+# Remove leading or trailing quotes and un-double CSV quotes.
+s/^"//
+s/"$//
+s/""/"/g
+# "
+
+# Delete blank lines
+/^$/d' stdout]],
+     [0], [expout], [])
    m4_popdef([i])
    AT_CLEANUP])
 
@@ -352,8 +378,19 @@ RND(number, number, number).]],
   [[trunc(1.9)], [1.00]],
   [[trunc(-1.2)], [-1.00]],
   [[trunc(-1.9)], [-1.00]],
+  [[trunc(5.06, .1)], [5.00]],
+  [[trunc(-5.06, .1)], [-5.00]],
+  [[trunc(1)], [1.00]],
+  [[trunc(1 - 2**-53)], [1.00]],
+  [[trunc(1 - 2**-52)], [1.00]],
+  [[trunc(1 - 2**-51)], [1.00]],
+  [[trunc(1 - 2**-45)], [0.00]],
+  [[trunc(1 - 2**-45, 1, 10)], [1.00]],
   [[trunc('x')], [error],
-   [error: DEBUG EVALUATE: Type mismatch invoking TRUNC(number) as trunc(string).]])
+   [error: DEBUG EVALUATE: Function invocation trunc(string) does not match any known function.  Candidates are:
+TRUNC(number)
+TRUNC(number, number)
+TRUNC(number, number, number).]])
 
 CHECK_EXPR_EVAL([acos arsin artan cos sin tan],
   [[acos(.5) / 3.14159 * 180], [60.00]],
@@ -536,11 +573,11 @@ ANY(string, string[, string]...).]],
 RANGE(number, number, number[, number, number]...)
 RANGE(string, string, string[, string, string]...).]],
   [[range(1, 2)], [error],
-   [error: DEBUG EVALUATE: RANGE(number, number, number[, number, number]...) must have an even number of arguments in list.]],
+   [error: DEBUG EVALUATE: RANGE(number, number, number[, number, number]...) must have an odd number of arguments.]],
   [[range(1, 2, 3, 4)], [error],
-   [error: DEBUG EVALUATE: RANGE(number, number, number[, number, number]...) must have an even number of arguments in list.]],
+   [error: DEBUG EVALUATE: RANGE(number, number, number[, number, number]...) must have an odd number of arguments.]],
   [[range(1, 2, 3, 4, 5, 6)], [error],
-   [error: DEBUG EVALUATE: RANGE(number, number, number[, number, number]...) must have an even number of arguments in list.]],
+   [error: DEBUG EVALUATE: RANGE(number, number, number[, number, number]...) must have an odd number of arguments.]],
   [[range('1', 2, 3)], [error],
    [error: DEBUG EVALUATE: Function invocation range(string, number, number) does not match any known function.  Candidates are:
 RANGE(number, number, number[, number, number]...)
@@ -579,11 +616,11 @@ RANGE(string, string, string[, string, string]...).]],
 RANGE(number, number, number[, number, number]...)
 RANGE(string, string, string[, string, string]...).]],
   [[range('1', '2')], [error],
-   [error: DEBUG EVALUATE: RANGE(string, string, string[, string, string]...) must have an even number of arguments in list.]],
+   [error: DEBUG EVALUATE: RANGE(string, string, string[, string, string]...) must have an odd number of arguments.]],
   [[range('1', '2', '3', '4')], [error],
-   [error: DEBUG EVALUATE: RANGE(string, string, string[, string, string]...) must have an even number of arguments in list.]],
+   [error: DEBUG EVALUATE: RANGE(string, string, string[, string, string]...) must have an odd number of arguments.]],
   [[range('1', '2', '3', '4', '5', '6')], [error],
-   [error: DEBUG EVALUATE: RANGE(string, string, string[, string, string]...) must have an even number of arguments in list.]],
+   [error: DEBUG EVALUATE: RANGE(string, string, string[, string, string]...) must have an odd number of arguments.]],
   [[range(1, '2', '3')], [error],
    [error: DEBUG EVALUATE: Function invocation range(number, string, string) does not match any known function.  Candidates are:
 RANGE(number, number, number[, number, number]...)
@@ -609,7 +646,7 @@ MAX(string[, string]...).]],
   [[max(1, 2, 3, $sysmis)], [3.00]],
   [[max.4(1, 2, 3, $sysmis)], [sysmis]],
   [[max.4(1, 2, 3)], [error],
-   [error: DEBUG EVALUATE: With MAX(number[, number]...), using minimum valid argument count of 4 does not make sense when passing only 3 arguments in list.]],
+   [error: DEBUG EVALUATE: For MAX(number[, number]...) with 3 arguments, at most 3 (not 4) may be required to be valid.]],
 
   [[max("2", "3", "5", "1", "4")], ["5"]],
   [[max("1", "2")], ["2"]],
@@ -627,13 +664,13 @@ MIN(string[, string]...).]],
   [[min(1, 2, 3, $sysmis)], [1.00]],
   [[min.4(1, 2, 3, $sysmis)], [sysmis]],
   [[min.4(1, 2, 3)], [error],
-   [error: DEBUG EVALUATE: With MIN(number[, number]...), using minimum valid argument count of 4 does not make sense when passing only 3 arguments in list.]],
+   [error: DEBUG EVALUATE: For MIN(number[, number]...) with 3 arguments, at most 3 (not 4) may be required to be valid.]],
 
   [[min("2", "3", "5", "1", "4")], ["1"]],
   [[min("1", "2")], ["1"]],
   [[min("1")], ["1"]])
 
-CHECK_EXPR_EVAL([cfvar mean sd sum variance],
+CHECK_EXPR_EVAL([cfvar mean median sd sum variance],
   [[cfvar(1, 2, 3, 4, 5)], [0.53]],
   [[cfvar(1, $sysmis, 2, 3, $sysmis, 4, 5)], [0.53]],
   [[cfvar(1, 2)], [0.47]],
@@ -643,7 +680,7 @@ CHECK_EXPR_EVAL([cfvar mean sd sum variance],
   [[cfvar(1, 2, 3, $sysmis)], [0.50]],
   [[cfvar.4(1, 2, 3, $sysmis)], [sysmis]],
   [[cfvar.4(1, 2, 3)], [error],
-   [error: DEBUG EVALUATE: With CFVAR(number, number[, number]...), using minimum valid argument count of 4 does not make sense when passing only 3 arguments in list.]],
+   [error: DEBUG EVALUATE: For CFVAR(number, number[, number]...) with 3 arguments, at most 3 (not 4) may be required to be valid.]],
   [[cfvar('x')], [error],
    [error: DEBUG EVALUATE: Type mismatch invoking CFVAR(number, number[, number]...) as cfvar(string).]],
   [[cfvar('x', 1, 2, 3)], [error],
@@ -659,8 +696,27 @@ CHECK_EXPR_EVAL([cfvar mean sd sum variance],
   [[mean(1, 2, 3, $sysmis)], [2.00]],
   [[mean.4(1, 2, 3, $sysmis)], [sysmis]],
   [[mean.4(1, 2, 3)], [error],
-   [error: DEBUG EVALUATE: With MEAN(number[, number]...), using minimum valid argument count of 4 does not make sense when passing only 3 arguments in list.]],
-
+   [error: DEBUG EVALUATE: For MEAN(number[, number]...) with 3 arguments, at most 3 (not 4) may be required to be valid.]],
+
+  [[median(1, 2, 3, 4, 5)], [3.00]],
+  [[median(2, 3, 4, 5, 1)], [3.00]],
+  [[median(2, 3, 4, 1, 5)], [3.00]],
+  [[median(2, 1, 4, 5, 3)], [3.00]],
+  [[median(1, 2, 3, 4)], [2.50]],
+  [[median(2, 3, 1, 4)], [2.50]],
+  [[median(2, 3, 4, 1)], [2.50]],
+  [[median(2, 1, 4, 3)], [2.50]],
+  [[median(1, $sysmis, 3, 4, 5)], [3.50]],
+  [[median(2, 3, 4, 5, $sysmis, 1)], [3.00]],
+  [[median($sysmis, $sysmis, $sysmis, 2, 3, 4, 1, 5)], [3.00]],
+  [[median(1, 2, 3)], [2.00]],
+  [[median(1)], [1.00]],
+  [[median(1, 2)], [1.50]],
+  [[median(1, 2, $sysmis)], [1.50]],
+  [[median(1, $sysmis, $sysmis)], [1.00]],
+  [[median($sysmis, $sysmis, $sysmis)], [sysmis]],
+  [[median.3(1, 2, $sysmis)], [sysmis]],
+  [[median.2(1, $sysmis)], [sysmis]],
 
   [[sd(1, 2, 3, 4, 5)], [1.58]],
   [[sd(1, $sysmis, 2, 3, $sysmis, 4, 5)], [1.58]],
@@ -671,7 +727,7 @@ CHECK_EXPR_EVAL([cfvar mean sd sum variance],
   [[sd(1, 2, 3, $sysmis)], [1.00]],
   [[sd.4(1, 2, 3, $sysmis)], [sysmis]],
   [[sd.4(1, 2, 3)], [error],
-   [error: DEBUG EVALUATE: With SD(number, number[, number]...), using minimum valid argument count of 4 does not make sense when passing only 3 arguments in list.]],
+   [error: DEBUG EVALUATE: For SD(number, number[, number]...) with 3 arguments, at most 3 (not 4) may be required to be valid.]],
   [[sd('x')], [error],
    [error: DEBUG EVALUATE: Type mismatch invoking SD(number, number[, number]...) as sd(string).]],
   [[sd('x', 1, 2, 3)], [error],
@@ -687,7 +743,7 @@ CHECK_EXPR_EVAL([cfvar mean sd sum variance],
   [[sum(1, 2, 3, $sysmis)], [6.00]],
   [[sum.4(1, 2, 3, $sysmis)], [sysmis]],
   [[sum.4(1, 2, 3)], [error],
-   [error: DEBUG EVALUATE: With SUM(number[, number]...), using minimum valid argument count of 4 does not make sense when passing only 3 arguments in list.]],
+   [error: DEBUG EVALUATE: For SUM(number[, number]...) with 3 arguments, at most 3 (not 4) may be required to be valid.]],
 
   [[variance(1, 2, 3, 4, 5)], [2.50]],
   [[variance(1, $sysmis, 2, 3, $sysmis, 4, 5)], [2.50]],
@@ -698,7 +754,7 @@ CHECK_EXPR_EVAL([cfvar mean sd sum variance],
   [[variance(1, 2, 3, $sysmis)], [1.00]],
   [[variance.4(1, 2, 3, $sysmis)], [sysmis]],
   [[variance.4(1, 2, 3)], [error],
-   [error: DEBUG EVALUATE: With VARIANCE(number, number[, number]...), using minimum valid argument count of 4 does not make sense when passing only 3 arguments in list.]],
+   [error: DEBUG EVALUATE: For VARIANCE(number, number[, number]...) with 3 arguments, at most 3 (not 4) may be required to be valid.]],
   [[variance('x')], [error],
    [error: DEBUG EVALUATE: Type mismatch invoking VARIANCE(number, number[, number]...) as variance(string).]],
   [[variance('x', 1, 2, 3)], [error],
@@ -770,6 +826,7 @@ CHECK_EXPR_EVAL([concat index rindex length lower],
   [[rindex('abcbcde', 'abc', 1)], [5.00]],
   [[rindex('abcbcde', 'bccb', 2)], [4.00]],
   [[rindex('abcbcde', 'bcbc', 2)], [4.00]],
+  [[rindex('abcbcde', 'bcbc', 0)], [sysmis]],
   [[rindex('abcbcde', 'bcbc', $sysmis)], [sysmis]],
   [[rindex('abcbcde', 'bcbcg', 2)], [sysmis]],
   [[rindex('abcbcde', 'bcbcg', $sysmis)], [sysmis]],
@@ -809,7 +866,22 @@ RINDEX(string, string, number).]],
   [[lower(1)], [error],
    [error: DEBUG EVALUATE: Type mismatch invoking LOWER(string) as lower(number).]])
 
-CHECK_EXPR_EVAL([lpad number ltrim lpad rtrim rpad string substr upcase],
+CHECK_EXPR_EVAL([replace],
+  [[replace('banana', 'an', 'AN')], ["bANANa"]],
+  [[replace('banana', 'an', 'a')], ["baaa"]],
+  [[replace('banana', 'an', '')], ["ba"]],
+  [[replace('banana', 'na', '')], ["ba"]],
+  [[replace('banana', 'ba', 'BA')], ["BAnana"]],
+  [[replace('banana', 'na', 'xyzzy')], ["baxyzzyxyzzy"]],
+  [[replace('banana', 'an', 'xyzzy', 1)], ["bxyzzyana"]],
+  [[replace('banana', 'an', 'xyzzy', 1.5)], ["bxyzzyana"]],
+  [[replace('banana', 'bananana', 'xyzzy')], ["banana"]],
+  [[replace('banana', '', 'xyzzy')], ["banana"]],
+  [[replace('banana', 'ba', '', 0)], ["banana"]],
+  [[replace('banana', 'ba', '', -1)], ["banana"]],
+  [[replace('banana', 'ba', '', $sysmis)], ["banana"]])
+
+CHECK_EXPR_EVAL([lpad number ltrim lpad rtrim rpad string strunc substr upcase],
   [[lpad('abc', -1)], [""]],
   [[lpad('abc', 0)], ["abc"]],
   [[lpad('abc', 2)], ["abc"]],
@@ -965,6 +1037,29 @@ dnl E has a minimum width of 6 on output:
    [error: DEBUG EVALUATE: Type mismatch invoking STRING(number, num_output_format) as string(number, format).]],
   [[string(123, e6.0)], ["1E+002"]],
 
+  [[strunc('a c   ', 9)], ["a c"]],
+  [[strunc('a c   ', 7)], ["a c"]],
+  [[strunc('a c   ', 6)], ["a c"]],
+  [[strunc('a c   ', 5)], ["a c"]],
+  [[strunc('a c   ', 4)], ["a c"]],
+  [[strunc('a c   ', 3)], ["a c"]],
+  [[strunc('a c   ', 2)], ["a"]],
+  [[strunc('a c   ', 1)], ["a"]],
+  [[strunc('a c   ', 0)], [""]],
+  [[strunc('a c   ', -1)], [""]],
+  [[strunc('a c   ', $sysmis)], [""]],
+  [[strunc('  abc  ', 9)], ["  abc"]],
+  [[strunc('  abc  ', 8)], ["  abc"]],
+  [[strunc('  abc  ', 7)], ["  abc"]],
+  [[strunc('  abc  ', 6)], ["  abc"]],
+  [[strunc('  abc  ', 5)], ["  abc"]],
+  [[strunc('  abc  ', 4)], ["  ab"]],
+  [[strunc('  abc  ', 3)], ["  a"]],
+  [[strunc('  abc  ', 2)], [""]],
+  [[strunc('  abc  ', 1)], [""]],
+  [[strunc('  abc  ', -1)], [""]],
+  [[strunc('  abc  ', $sysmis)], [""]],
+
   [[substr('abcdefgh', -5)], [""]],
   [[substr('abcdefgh', 0)], [""]],
   [[substr('abcdefgh', 1)], ["abcdefgh"]],
@@ -1902,6 +1997,14 @@ dnl Tests correctness of generic optimizations in optimize_tree().
   [[x ** 1], [5.00], [], [(X = 5.00)]],
   [[x ** 2], [25.00], [], [(X = 5.00)]])
 
+CHECK_EXPR_EVAL([negative checks],
+  [[$nonexistent], [error], [error: DEBUG EVALUATE: Unknown system variable $nonexistent.]],
+  [[RANGE(1, 2)], [error], [error: DEBUG EVALUATE: RANGE(number, number, number[, number, number]...) must have an odd number of arguments.]],
+  [[CONCAT.1('a', 'b')], [error], [error: DEBUG EVALUATE: CONCAT(string[, string]...) function cannot accept suffix .1 to specify the minimum number of valid arguments.]],
+  [[foobar(x)], [error], [error: DEBUG EVALUATE: No function or vector named foobar.]],
+  [[CONCAT.1('a' b)], [error], [error: DEBUG EVALUATE: Syntax error at `b': expecting `,' or `)'.]],
+  [[NCDF.CHISQ(1, 2, 3)], [error], [error: DEBUG EVALUATE: NCDF.CHISQ(number, number, number) is not available in this version of PSPP.]])
+
 AT_SETUP([LAG function])
 AT_DATA([lag.sps], [dnl
 data list /W 1.
@@ -1922,7 +2025,7 @@ AT_CHECK([pspp -o pspp.csv lag.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Reading 1 record from INLINE.
 Variable,Record,Columns,Format
-W,1,1-  1,F1.0
+W,1,1-1,F1.0
 
 Table: Data List
 W,X,Y,Z
@@ -1938,8 +2041,8 @@ AT_SETUP([LAG crash bug])
 AT_DATA([lag.sps], [dnl
 DATA LIST LIST /x.
 BEGIN DATA
-1 
-2 
+1
+2
 END DATA.
 
 DO IF (x <> LAG(x) ).
@@ -2036,10 +2139,10 @@ Table: Data List
 n,s,nlabel,slabel
 .,,,
 0,a,Very dissa,Wouldn't b
-1,b,Dissatisfi,Unhappy   @&t@
-2,c,Neutral   ,Bored     @&t@
-3,d,Satisfied ,Satiated  @&t@
-4,e,Very satis,Elated    @&t@
+1,b,Dissatisfi,Unhappy
+2,c,Neutral,Bored
+3,d,Satisfied,Satiated
+4,e,Very satis,Elated
 5,f,,
 6,g,,
 ])
@@ -2051,7 +2154,7 @@ DATA LIST NOTABLE/N1 TO N5 1-5.
 MISSING VALUES N1 TO N5 (3 THRU 5, 1).
 BEGIN DATA.
 12345
-6789 
+6789
 END DATA.
 
 COMPUTE P1=N1.
@@ -2100,7 +2203,7 @@ DATA LIST NOTABLE /N1 TO N5 1-5.
 MISSING VALUES N1 TO N5 (3 THRU 5, 1).
 BEGIN DATA.
 12345
-6789 
+6789
 END DATA.
 
 VECTOR N=N1 TO N5.