MATCH FILES, UPDATE, ADD FILES: Improve error messages.
[pspp] / tests / language / data-io / match-files.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([MATCH FILES])
18
19 m4_define([PREPARE_MATCH_FILES],
20   [AT_DATA([data1.txt], [dnl
21 1aB
22 8aM
23 3aE
24 5aG
25 0aA
26 5aH
27 6aI
28 7aJ
29 2aD
30 7aK
31 1aC
32 7aL
33 4aF
34 ])
35
36    AT_DATA([data2.txt], [dnl
37 1bN
38 3bO
39 4bP
40 6bQ
41 7bR
42 9bS
43 ])
44
45    AT_DATA([prepare.sps], [dnl
46 DATA LIST NOTABLE FILE='data1.txt' /a b c 1-3 (A).
47 SAVE OUTFILE='data1.sav'.
48 DATA LIST NOTABLE FILE='data2.txt' /a b c 1-3 (A).
49 SAVE OUTFILE='data2.sav'.
50 ])
51    AT_CHECK([pspp -O format=csv prepare.sps])
52    AT_CHECK([test -f data1.sav && test -f data2.sav])])
53
54 dnl CHECK_MATCH_FILES(TYPE2, SOURCE1, SOURCE2)
55 dnl
56 dnl Checks the MATCH FILES procedure with the specified combination of:
57 dnl
58 dnl - TYPE2: Either "file" or "table" for the type of matching used for
59 dnl   the second data source.  (The first data source is always "file").
60 dnl
61 dnl - SOURCE1: Either "system" or "active" for the source of data for
62 dnl   the first data source.
63 dnl
64 dnl - SOURCE2: Either "system" or "active" for the source of data for
65 dnl   the second data source.  (SOURCE1 and SOURCE2 may not both be
66 dnl   "active".)
67 m4_define([CHECK_MATCH_FILES],
68   [AT_SETUP([MATCH FILES -- $2 file and $3 $1])
69    PREPARE_MATCH_FILES
70    AT_DATA([expout],
71     [m4_if([$1], [file], [dnl
72 Table: Data List
73 a,b,c,d,ina,inb,first,last
74 0,a,A,,1,0,1,1
75 1,a,B,N,1,1,1,0
76 1,a,C,,1,0,0,1
77 2,a,D,,1,0,1,1
78 3,a,E,O,1,1,1,1
79 4,a,F,P,1,1,1,1
80 5,a,G,,1,0,1,0
81 5,a,H,,1,0,0,1
82 6,a,I,Q,1,1,1,1
83 7,a,J,R,1,1,1,0
84 7,a,K,,1,0,0,0
85 7,a,L,,1,0,0,1
86 8,a,M,,1,0,1,1
87 9,b,,S,0,1,1,1
88 ], [dnl
89 Table: Data List
90 a,b,c,d,ina,inb,first,last
91 0,a,A,,1,0,1,1
92 1,a,B,N,1,1,1,0
93 1,a,C,N,1,1,0,1
94 2,a,D,,1,0,1,1
95 3,a,E,O,1,1,1,1
96 4,a,F,P,1,1,1,1
97 5,a,G,,1,0,1,0
98 5,a,H,,1,0,0,1
99 6,a,I,Q,1,1,1,1
100 7,a,J,R,1,1,1,0
101 7,a,K,R,1,1,0,0
102 7,a,L,R,1,1,0,1
103 8,a,M,,1,0,1,1
104 ])])
105
106    AT_DATA([match-files.sps], [dnl
107 m4_if([$2], [active], [GET FILE='data1.sav'.],
108       [$3], [active], [GET FILE='data2.sav'.],
109       [])
110 MATCH FILES
111         FILE=m4_if([$2], [active], [*], ['data1.sav']) /IN=ina /SORT
112         $1=m4_if([$3], [active], [*], ['data2.sav']) /in=inb /rename c=d
113         /BY a /FIRST=first /LAST=last.
114 LIST.
115 ])
116    AT_CHECK([pspp -o pspp.csv match-files.sps])
117    AT_CHECK([cat pspp.csv], [0], [expout])
118    AT_CLEANUP])
119
120 CHECK_MATCH_FILES([file], [system], [system])
121 CHECK_MATCH_FILES([file], [system], [active])
122 CHECK_MATCH_FILES([file], [active], [system])
123 CHECK_MATCH_FILES([table], [system], [system])
124 CHECK_MATCH_FILES([table], [system], [active])
125 CHECK_MATCH_FILES([table], [active], [system])
126
127 AT_SETUP([MATCH FILES parallel match])
128 PREPARE_MATCH_FILES
129 AT_DATA([match-files.sps], [dnl
130 MATCH FILES FILE='data1.sav' /FILE='data2.sav' /RENAME (a b c=d e f).
131 LIST.
132 ])
133 AT_CHECK([pspp -o pspp.csv match-files.sps])
134 AT_CHECK([cat pspp.csv], [0], [dnl
135 Table: Data List
136 a,b,c,d,e,f
137 1,a,B,1,b,N
138 8,a,M,3,b,O
139 3,a,E,4,b,P
140 5,a,G,6,b,Q
141 0,a,A,7,b,R
142 5,a,H,9,b,S
143 6,a,I,,,
144 7,a,J,,,
145 2,a,D,,,
146 7,a,K,,,
147 1,a,C,,,
148 7,a,L,,,
149 4,a,F,,,
150 ])
151 AT_CLEANUP
152
153 dnl Test bug handling TABLE from active dataset found by John Darrington.
154 AT_SETUP([MATCH FILES bug with TABLE from active dataset])
155 AT_DATA([match-files.sps], [dnl
156 DATA LIST LIST NOTABLE /x * y *.
157 BEGIN DATA
158 3 30
159 2 21
160 1 22
161 END DATA.
162
163 SAVE OUTFILE='bar.sav'.
164
165 DATA LIST LIST NOTABLE /x * z *.
166 BEGIN DATA
167 3 8
168 2 9
169 END DATA.
170
171 MATCH FILES TABLE=* /FILE='bar.sav' /BY=x.
172 LIST.
173 ])
174 AT_CHECK([pspp -o pspp.csv match-files.sps])
175 AT_CHECK([cat pspp.csv], [0], [dnl
176 Table: Data List
177 x,z,y
178 3.00,8.00,30.00
179 2.00,.  ,21.00
180 1.00,.  ,22.00
181 ])
182 AT_CLEANUP
183
184 dnl Tests for a bug which caused MATCH FILES to crash
185 dnl when used with scratch variables.
186 AT_SETUP([MATCH FILES bug with scratch variables])
187 AT_DATA([match-files.sps], [dnl
188 DATA LIST LIST /w * x * y * .
189 BEGIN DATA
190 4 5 6
191 1 2 3
192 END DATA.
193
194 COMPUTE j=0.
195 LOOP #k = 1 to 10.
196 COMPUTE j=#k + j.
197 END LOOP.
198
199 MATCH FILES FILE=* /DROP=w.
200 LIST.
201 FINISH.
202 ])
203 AT_CHECK([pspp -o pspp.csv match-files.sps])
204 AT_CHECK([cat pspp.csv], [0], [dnl
205 Table: Reading free-form data from INLINE.
206 Variable,Format
207 w,F8.0
208 x,F8.0
209 y,F8.0
210
211 Table: Data List
212 x,y,j
213 5.00,6.00,55.00
214 2.00,3.00,55.00
215 ])
216 AT_CLEANUP
217
218 dnl Tests for a bug that caused MATCH FILES to crash
219 dnl with incompatible variables, especially but not
220 dnl exclusively when one variable came from the active
221 dnl file.
222 AT_SETUP([MATCH FILES with incompatible variable types])
223 AT_DATA([match-files.sps], [dnl
224 DATA LIST LIST NOTABLE/name (A6) x.
225 BEGIN DATA.
226 al,7
227 brad,8
228 carl,9
229 END DATA.
230 SAVE OUTFILE='x.sav'.
231
232 DATA LIST LIST NOTABLE/name (A7) y.
233 BEGIN DATA.
234 al,1
235 carl,2
236 dan,3
237 END DATA.
238 MATCH FILES/FILE='x.sav'/FILE=*/BY name.
239 LIST.
240 ])
241 AT_CHECK([pspp -O format=csv match-files.sps], [1], [dnl
242 match-files.sps:15: error: MATCH FILES: Variable name has different type or width in different files.
243
244 "match-files.sps:15.13-15.24: note: MATCH FILES: In file `x.sav', name is a string with width 6.
245    15 | MATCH FILES/FILE='x.sav'/FILE=*/BY name.
246       |             ^~~~~~~~~~~~"
247
248 "match-files.sps:15.26-15.31: note: MATCH FILES: In file *, name is a string with width 7.
249    15 | MATCH FILES/FILE='x.sav'/FILE=*/BY name.
250       |                          ^~~~~~"
251
252 match-files.sps:16: error: Stopping syntax file processing here to avoid a cascade of dependent command failures.
253 ])
254 AT_CLEANUP
255
256 AT_SETUP([MATCH FILES syntax errors])
257 AT_DATA([insert.sps], [dnl
258 INSERT FILE='match-files.sps' ERROR=IGNORE.
259 ])
260 AT_DATA([match-files.sps], [dnl
261 MATCH FILES/FILE=*.
262
263 DATA LIST LIST NOTABLE/name (A6) x.
264 BEGIN DATA.
265 al,7
266 brad,8
267 carl,9
268 END DATA.
269 SAVE OUTFILE='x.sav'.
270
271 TEMPORARY.
272 MATCH FILES/FILE=*.
273
274 DATA LIST LIST NOTABLE/name (A7) y.
275 BEGIN DATA.
276 al,1
277 carl,2
278 dan,3
279 END DATA.
280 MATCH FILES/FILE='x.sav'/FILE=*/BY name.
281 MATCH FILES/FILE='x.sav'/IN=**.
282 MATCH FILES/FILE='x.sav'/IN=x/IN=y.
283 MATCH FILES/FILE='x.sav'/BY=x/BY=y.
284 MATCH FILES/FILE='x.sav'/BY=**.
285 MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/BY y.
286 MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/BY x.
287 MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/FIRST x/FIRST y.
288 MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/FIRST=**.
289 MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/LAST x/LAST y.
290 MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/LAST=**.
291 MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/DROP=xyzzy.
292 MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/DROP=ALL.
293 MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/KEEP=xyzzy.
294 MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/LAST=x **.
295 MATCH FILES/FILE='x.sav'/TABLE=*/RENAME(name=name2).
296 MATCH FILES/FILE='x.sav'/SORT/FILE=*/RENAME(name=name2)/SORT.
297 MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/FIRST=x.
298 MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/LAST=x.
299 MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/IN=x.
300 ])
301 AT_CHECK([pspp --testing-mode -O format=csv insert.sps], [1], [dnl
302 "match-files.sps:1.18: error: MATCH FILES: Cannot specify the active dataset since none has been defined.
303     1 | MATCH FILES/FILE=*.
304       |                  ^"
305
306 "match-files.sps:12.18: error: MATCH FILES: This command may not be used after TEMPORARY when the active dataset is an input source.  Temporary transformations will be made permanent.
307    12 | MATCH FILES/FILE=*.
308       |                  ^"
309
310 match-files.sps:20: error: MATCH FILES: Variable name has different type or width in different files.
311
312 "match-files.sps:20.13-20.24: note: MATCH FILES: In file `x.sav', name is a string with width 6.
313    20 | MATCH FILES/FILE='x.sav'/FILE=*/BY name.
314       |             ^~~~~~~~~~~~"
315
316 "match-files.sps:20.26-20.31: note: MATCH FILES: In file *, name is a string with width 7.
317    20 | MATCH FILES/FILE='x.sav'/FILE=*/BY name.
318       |                          ^~~~~~"
319
320 "match-files.sps:21.29-21.30: error: MATCH FILES: Syntax error expecting identifier.
321    21 | MATCH FILES/FILE='x.sav'/IN=**.
322       |                             ^~"
323
324 "match-files.sps:22.34: error: MATCH FILES: Multiple IN subcommands for a single FILE or TABLE.
325    22 | MATCH FILES/FILE='x.sav'/IN=x/IN=y.
326       |                                  ^"
327
328 "match-files.sps:23.31-23.32: error: MATCH FILES: Subcommand BY may only be specified once.
329    23 | MATCH FILES/FILE='x.sav'/BY=x/BY=y.
330       |                               ^~"
331
332 "match-files.sps:24.29-24.30: error: MATCH FILES: Syntax error expecting variable name.
333    24 | MATCH FILES/FILE='x.sav'/BY=**.
334       |                             ^~"
335
336 "match-files.sps:25.13-25.24: error: MATCH FILES: File `x.sav' lacks BY variable y.
337    25 | MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/BY y.
338       |             ^~~~~~~~~~~~"
339
340 "match-files.sps:26.26-26.31: error: MATCH FILES: File * lacks BY variable x.
341    26 | MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/BY x.
342       |                          ^~~~~~"
343
344 "match-files.sps:27.60-27.64: error: MATCH FILES: Subcommand FIRST may only be specified once.
345    27 | MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/FIRST x/FIRST y.
346       |                                                            ^~~~~"
347
348 "match-files.sps:28.58-28.59: error: MATCH FILES: Syntax error expecting identifier.
349    28 | MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/FIRST=**.
350       |                                                          ^~"
351
352 "match-files.sps:29.59-29.62: error: MATCH FILES: Subcommand LAST may only be specified once.
353    29 | MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/LAST x/LAST y.
354       |                                                           ^~~~"
355
356 "match-files.sps:30.57-30.58: error: MATCH FILES: Syntax error expecting identifier.
357    30 | MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/LAST=**.
358       |                                                         ^~"
359
360 "match-files.sps:31.57-31.61: error: MATCH FILES: xyzzy is not a variable name.
361    31 | MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/DROP=xyzzy.
362       |                                                         ^~~~~"
363
364 "match-files.sps:32.52-32.59: error: MATCH FILES: Cannot DROP all variables from dictionary.
365    32 | MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/DROP=ALL.
366       |                                                    ^~~~~~~~"
367
368 "match-files.sps:33.57-33.61: error: MATCH FILES: xyzzy is not a variable name.
369    33 | MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/KEEP=xyzzy.
370       |                                                         ^~~~~"
371
372 "match-files.sps:34.59-34.60: error: MATCH FILES: Syntax error expecting end of command.
373    34 | MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/LAST=x **.
374       |                                                           ^~"
375
376 "match-files.sps:35.26-35.32: error: MATCH FILES: BY is required when TABLE is specified.
377    35 | MATCH FILES/FILE='x.sav'/TABLE=*/RENAME(name=name2).
378       |                          ^~~~~~~"
379
380 "match-files.sps:36.26-36.29: error: MATCH FILES: BY is required when SORT is specified.
381    36 | MATCH FILES/FILE='x.sav'/SORT/FILE=*/RENAME(name=name2)/SORT.
382       |                          ^~~~"
383
384 "match-files.sps:37.58: error: MATCH FILES: Variable name x specified on FIRST subcommand duplicates an existing variable name.
385    37 | MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/FIRST=x.
386       |                                                          ^"
387
388 "match-files.sps:38.57: error: MATCH FILES: Variable name x specified on LAST subcommand duplicates an existing variable name.
389    38 | MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/LAST=x.
390       |                                                         ^"
391
392 "match-files.sps:39.55: error: MATCH FILES: Variable name x specified on IN subcommand duplicates an existing variable name.
393    39 | MATCH FILES/FILE='x.sav'/FILE=*/RENAME(name=name2)/IN=x.
394       |                                                       ^"
395 ])
396 AT_CLEANUP