Convert all Perl build tools to Python and remove Perl build dependency.
[pspp] / tests / language / data-io / data-reader.at
1 dnl PSPP - a program for statistical analysis.
2 dnl Copyright (C) 2017 Free Software Foundation, Inc.
3 dnl
4 dnl This program is free software: you can redistribute it and/or modify
5 dnl it under the terms of the GNU General Public License as published by
6 dnl the Free Software Foundation, either version 3 of the License, or
7 dnl (at your option) any later version.
8 dnl
9 dnl This program is distributed in the hope that it will be useful,
10 dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
11 dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 dnl GNU General Public License for more details.
13 dnl
14 dnl You should have received a copy of the GNU General Public License
15 dnl along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 dnl
17 AT_BANNER([BEGIN DATA])
18
19 # BEGIN DATA can run as a command in itself, or it can appear as part
20 # of the first procedure.  First, test it after a procedure.
21 AT_SETUP([BEGIN DATA as part of a procedure])
22 AT_DATA([begin-data.sps], [dnl
23 TITLE 'Test BEGIN DATA ... END DATA'.
24
25 DATA LIST /a b 1-2.
26 LIST.
27 BEGIN DATA.
28 12
29 34
30 56
31 78
32 90
33 END DATA.
34 ])
35 AT_CHECK([pspp -O format=csv begin-data.sps], [0], [dnl
36 Table: Reading 1 record from INLINE.
37 Variable,Record,Columns,Format
38 a,1,1-1,F1.0
39 b,1,2-2,F1.0
40
41 Table: Data List
42 a,b
43 1,2
44 3,4
45 5,6
46 7,8
47 9,0
48 ])
49 AT_CLEANUP
50
51 # Also test BEGIN DATA as an independent command.
52 AT_SETUP([BEGIN DATA as an independent command])
53 AT_DATA([begin-data.sps], [dnl
54 data list /A B 1-2.
55 begin data.
56 09
57 87
58 65
59 43
60 21
61 end data.
62 list.
63 ])
64 AT_CHECK([pspp -O format=csv begin-data.sps], [0], [dnl
65 Table: Reading 1 record from INLINE.
66 Variable,Record,Columns,Format
67 A,1,1-1,F1.0
68 B,1,2-2,F1.0
69
70 Table: Data List
71 A,B
72 0,9
73 8,7
74 6,5
75 4,3
76 2,1
77 ])
78 AT_CLEANUP
79
80 m4_define([DATA_READER_BINARY],
81   [AT_SETUP([read and write files with $1])
82 $3
83    AT_DATA([input.txt], [dnl
84 07-22-2007
85 10-06-2007
86 321
87 07-14-1789
88 08-26-1789
89 4
90 01-01-1972
91 12-31-1999
92 682
93 ])
94    AT_DATA([make-binary.py], [[
95 #! /usr/bin/python3
96
97 import struct
98 import sys
99
100 # This random number generator and the test for it below are drawn
101 # from Park and Miller, "Random Number Generators: Good Ones are Hard
102 # to Come By", Communications of the ACM 31:10 (October 1988).  It is
103 # documented to function properly on systems with a 46-bit or longer
104 # real significand, which includes systems that have 64-bit IEEE reals
105 # (with 53-bit significand).  The test should catch any systems for
106 # which this is not true, in any case.
107 def my_rand(modulus):
108     global seed
109     a = 16807
110     m = 2147483647
111     tmp = a * seed
112     seed = tmp - m * (tmp // m)
113     return seed % modulus
114
115 # Test the random number generator for reproducibility,
116 # then reset the seed
117 seed = 1
118 for i in range(10000):
119     my_rand(1)
120 assert seed == 1043618065
121 seed = 1
122
123 # ASCII to EBCDIC translation table
124 ascii2ebcdic = (
125     0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f, 
126     0x16, 0x05, 0x25, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 
127     0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, 
128     0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f, 
129     0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d, 
130     0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61, 
131     0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 
132     0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f, 
133     0x7c, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 
134     0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 
135     0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 
136     0xe7, 0xe8, 0xe9, 0xad, 0xe0, 0xbd, 0x9a, 0x6d, 
137     0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 
138     0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 
139     0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 
140     0xa7, 0xa8, 0xa9, 0xc0, 0x4f, 0xd0, 0x5f, 0x07, 
141     0x20, 0x21, 0x22, 0x23, 0x24, 0x15, 0x06, 0x17, 
142     0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x09, 0x0a, 0x1b, 
143     0x30, 0x31, 0x1a, 0x33, 0x34, 0x35, 0x36, 0x08, 
144     0x38, 0x39, 0x3a, 0x3b, 0x04, 0x14, 0x3e, 0xe1, 
145     0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 
146     0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 
147     0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
148     0x68, 0x69, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 
149     0x76, 0x77, 0x78, 0x80, 0x8a, 0x8b, 0x8c, 0x8d, 
150     0x8e, 0x8f, 0x90, 0x6a, 0x9b, 0x9c, 0x9d, 0x9e, 
151     0x9f, 0xa0, 0xaa, 0xab, 0xac, 0x4a, 0xae, 0xaf, 
152     0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 
153     0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xa1, 0xbe, 0xbf, 
154     0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xda, 0xdb, 
155     0xdc, 0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xec, 0xed, 
156     0xee, 0xef, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff)
157 assert len(ascii2ebcdic) == 256
158
159 def a2e(s):
160     return bytearray((ascii2ebcdic[ord(c)] for c in s))
161
162 def dump_records(out, records):
163     while records:
164         n = min(my_rand(5) + 1, len(records))
165         r = records[:n]
166         records[:n] = []
167
168         count = sum((len(rec) for rec in r))
169         out.buffer.write(struct.pack(">H xx", count + 4))
170         for rec in r:
171             out.buffer.write(rec)
172
173 data = []
174 for line in open('input.txt', 'r'):
175     data += [line.rstrip('\r\n')]
176
177 # MODE=BINARY
178 out = open('binary.bin', 'w')
179 for item in data:
180     reclen = struct.pack("<I", len(item))
181     out.buffer.write(reclen)
182     out.buffer.write(bytearray([ord(c) for c in item]))
183     out.buffer.write(reclen)
184 out.close()
185     
186 # MODE=360 /RECFORM=FIXED /LRECL=32
187 out = open('fixed.bin', 'w')
188 lrecl = 32
189 for item in data:
190     s = item[:lrecl]
191     s += ' ' * (lrecl - len(s))
192     assert len(s) == 32
193     out.buffer.write(a2e(s))
194 out.close()
195
196 # MODE=360 /RECFORM=VARIABLE
197 out = open('variable.bin', 'w')
198 records = []
199 for item in data:
200     records += [struct.pack('>H xx', len(item) + 4) + a2e(item)]
201 dump_records(out, records)
202 out.close()
203
204 # MODE=360 /RECFORM=SPANNED
205 out = open('spanned.bin', 'w')
206 records = []
207 for line in data:
208     r = []
209     while line:
210         n = min(my_rand(5), len(line))
211         r += [line[:n]]
212         line = line[n:]
213     for i, s in enumerate(r):
214         scc = (0 if len(r) == 1
215                else 1 if i == 0
216                else 2 if i == len(r) - 1
217                else 3)
218         records += [struct.pack('>H B x', len(s) + 4, scc) + a2e(s)]
219 dump_records(out, records)
220 out.close()
221 ]])
222    AT_CHECK([$PYTHON3 make-binary.py])
223    AT_DATA([data-reader.sps], [dnl
224 FILE HANDLE input/NAME='$2'/$1.
225 DATA LIST FIXED FILE=input NOTABLE
226         /1 start 1-10 (ADATE)
227         /2 end 1-10 (ADATE)
228         /3 count 1-3.
229 LIST.
230
231 * Output the data to a new file in the same format.
232 FILE HANDLE OUTPUT/NAME='output.bin'/$1.
233 COMPUTE count=count + 1.
234 PRINT OUTFILE=output/start end count.
235 EXECUTE.
236 ])
237    AT_CHECK([pspp -O format=csv data-reader.sps], [0], [dnl
238 Table: Data List
239 start,end,count
240 07/22/2007,10/06/2007,321
241 07/14/1789,08/26/1789,4
242 01/01/1972,12/31/1999,682
243 ])
244    AT_CHECK([test -s output.bin])
245    AT_DATA([data-reader-2.sps], [dnl
246 * Re-read the new data and list it, to verify that it was written correctly.
247 FILE HANDLE OUTPUT/NAME='output.bin'/$1.
248 DATA LIST FIXED FILE=output NOTABLE/
249         start 2-11 (ADATE)
250         end 13-22 (ADATE)
251         count 24-26.
252 LIST.
253 ])
254    AT_CHECK([pspp -O format=csv data-reader-2.sps], [0], [dnl
255 Table: Data List
256 start,end,count
257 07/22/2007,10/06/2007,322
258 07/14/1789,08/26/1789,5
259 01/01/1972,12/31/1999,683
260 ])
261    AT_CLEANUP])
262
263 DATA_READER_BINARY([MODE=BINARY], [binary.bin])
264 DATA_READER_BINARY([MODE=360 /RECFORM=FIXED /LRECL=32], [fixed.bin],
265   [AT_CHECK([i18n-test supports_encodings EBCDIC-US])])
266 DATA_READER_BINARY([MODE=360 /RECFORM=VARIABLE], [variable.bin],
267   [AT_CHECK([i18n-test supports_encodings EBCDIC-US])])
268 DATA_READER_BINARY([MODE=360 /RECFORM=SPANNED], [spanned.bin],
269   [AT_CHECK([i18n-test supports_encodings EBCDIC-US])])