Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/tests/cmdline.py
4045 views
1
r"""
2
This file contains some tests that Sage command line options actually
3
do something.
4
5
We test the following command line options:
6
7
test.py
8
/path/to/test.py
9
test.sage
10
/path/to/test.sage
11
--advanced
12
--branch
13
-c
14
--cython
15
--ecl
16
--experimental
17
--gap
18
--gp
19
-h
20
--help
21
--hg
22
--ipython
23
--kash
24
--lisp
25
--maxima
26
--min
27
--mwrank
28
--optional
29
--preparse
30
--python
31
-q
32
--R
33
--root
34
--scons
35
--sh
36
--singular
37
--sqlite3
38
--standard
39
--startuptime
40
-t
41
-v
42
--zzfoobar (illegal option)
43
44
45
AUTHORS:
46
47
- Jeroen Demeyer (2010-11-20): initial version (#10300)
48
49
"""
50
51
from subprocess import *
52
import os, select
53
54
def test_executable(args, input="", timeout=50.0):
55
"""
56
Run the program defined by ``args`` using the string ``input`` on
57
the standard input.
58
59
INPUT:
60
61
- ``args`` -- a list of program arguments, the first being the
62
executable.
63
64
- ``input`` -- a string serving as standard input. Usually, this
65
should end with a newline.
66
67
- ``timeout`` -- if the program produces no output for ``timeout``
68
seconds, a RuntimeError is raised.
69
70
OUTPUT: a tuple ``(out, err, ret)`` with the standard output,
71
standard error and exitcode of the program run.
72
73
74
EXAMPLES::
75
76
sage: from sage.tests.cmdline import test_executable
77
sage: (out, err, ret) = test_executable(["cat"], "Hello World!")
78
sage: out
79
'Hello World!'
80
sage: err
81
''
82
sage: ret
83
0
84
85
We test the timeout option::
86
87
sage: (out, err, ret) = test_executable(["sleep", "1"], timeout=0.1)
88
Traceback (most recent call last):
89
...
90
RuntimeError: timeout in test_executable()
91
92
TESTS:
93
94
Run Sage itself with various options::
95
96
sage: (out, err, ret) = test_executable(["sage"])
97
sage: out.find(version()) >= 0
98
True
99
sage: err
100
''
101
sage: ret
102
0
103
104
sage: (out, err, ret) = test_executable(["sage"], "3^33\n")
105
sage: out.find(version()) >= 0
106
True
107
sage: out.find("5559060566555523") >= 0
108
True
109
sage: err
110
''
111
sage: ret
112
0
113
114
sage: (out, err, ret) = test_executable(["sage", "-q"], "3^33\n")
115
sage: out.find(version()) >= 0
116
False
117
sage: out.find("5559060566555523") >= 0
118
True
119
sage: err
120
''
121
sage: ret
122
0
123
124
sage: (out, err, ret) = test_executable(["sage", "-c", "print 3^33"])
125
sage: print out
126
5559060566555523
127
sage: err
128
''
129
sage: ret
130
0
131
132
sage: (out, err, ret) = test_executable(["sage", "--min", "-c", "print 3^33"])
133
sage: print out
134
5559060566555523
135
sage: err
136
''
137
sage: ret
138
0
139
140
sage: (out, err, ret) = test_executable(["sage", "--startuptime"])
141
sage: out.find("sage.all: ") >= 0
142
True
143
sage: err
144
''
145
sage: ret
146
0
147
148
Test help::
149
150
sage: (out, err, ret) = test_executable(["sage", "-h"])
151
sage: out.find("Optional arguments:") >= 0
152
True
153
sage: err
154
''
155
sage: ret
156
0
157
158
sage: (out, err, ret) = test_executable(["sage", "--help"])
159
sage: out.find("Optional arguments:") >= 0
160
True
161
sage: err
162
''
163
sage: ret
164
0
165
166
sage: (out, err, ret) = test_executable(["sage", "--advanced"])
167
sage: out.find("run with no output prompts") >= 0
168
True
169
sage: err
170
''
171
sage: ret
172
0
173
174
Basic information about the Sage installation::
175
176
sage: (out, err, ret) = test_executable(["sage", "-v"])
177
sage: out.find(version()) >= 0
178
True
179
sage: err
180
''
181
sage: ret
182
0
183
184
sage: (out, err, ret) = test_executable(["sage", "--branch"])
185
sage: len(out) >= 2 # at least one character + newline
186
True
187
sage: err
188
''
189
sage: ret
190
0
191
192
sage: (out, err, ret) = test_executable(["sage", "--root"])
193
sage: len(out) >= 2 # at least one character + newline
194
True
195
sage: err
196
''
197
sage: ret
198
0
199
200
Test ``sage-run`` on a Python file, both with an absolute and with a relative path::
201
202
sage: import tempfile
203
sage: F = tempfile.NamedTemporaryFile(suffix=".py")
204
sage: F.write("print 3^33\n")
205
sage: F.flush()
206
sage: (out, err, ret) = test_executable(["sage", F.name])
207
sage: print out
208
34
209
sage: err
210
''
211
sage: ret
212
0
213
sage: (dir,filename) = os.path.split(F.name)
214
sage: os.chdir(dir)
215
sage: (out, err, ret) = test_executable(["sage", filename])
216
sage: print out
217
34
218
sage: err
219
''
220
sage: ret
221
0
222
sage: del F # Close and delete the file
223
224
The same as above, but now with a ``.sage`` file. This indirectly
225
also tests the preparser::
226
227
sage: import tempfile
228
sage: F = tempfile.NamedTemporaryFile(suffix=".sage")
229
sage: py_file = F.name[:-5] + ".py" # Will be created by the preparser
230
sage: F.write("k.<a> = GF(5^3); print a^124\n")
231
sage: F.flush()
232
sage: (out, err, ret) = test_executable(["sage", F.name])
233
sage: os.unlink(py_file)
234
sage: print out
235
1
236
sage: err
237
''
238
sage: ret
239
0
240
sage: (dir,filename) = os.path.split(F.name)
241
sage: os.chdir(dir)
242
sage: (out, err, ret) = test_executable(["sage", filename])
243
sage: os.unlink(py_file)
244
sage: print out
245
1
246
sage: err
247
''
248
sage: ret
249
0
250
sage: del F # Close and delete the file
251
252
Testing "sage --preparse FILE" and "sage -t FILE". First create a file and preparse it::
253
254
sage: import os
255
sage: s = '\"\"\"\nThis is a test file.\n\"\"\"\ndef my_add(a,b):\n \"\"\"\n Add a to b.\n\n EXAMPLES::\n\n sage: my_add(2,2)\n 4\n \"\"\"\n return a+b\n'
256
sage: script = os.path.join(SAGE_TMP, 'my_script.sage')
257
sage: F = open(script, 'w')
258
sage: F.write(s)
259
sage: F.close()
260
sage: os.chdir(SAGE_TMP)
261
sage: (out, err, ret) = test_executable(["sage", "--preparse", script])
262
sage: ret
263
0
264
sage: os.path.exists(os.path.join(SAGE_TMP, 'my_script.py'))
265
True
266
267
Now test my_script.sage and the preparsed version my_script.py::
268
269
sage: (out, err, ret) = test_executable(["sage", "-t", script])
270
sage: ret
271
0
272
sage: out.find("All tests passed!") >= 0
273
True
274
sage: (out, err, ret) = test_executable(["sage", "-t", os.path.join(SAGE_TMP, 'my_script.py')])
275
sage: ret
276
0
277
sage: out.find("All tests passed!") >= 0
278
True
279
280
Now for a file which should fail tests. Run this test with
281
SAGE_TESTDIR equal to a temporary directory, because failed doctests
282
leave files lying around in SAGE_TESTDIR::
283
284
sage: s = s.replace('4', '5') # (2+2 != 5)
285
sage: F = open(script, 'w')
286
sage: F.write(s)
287
sage: F.close()
288
sage: OLD_TESTDIR = os.environ['SAGE_TESTDIR']
289
sage: os.environ['SAGE_TESTDIR'] = SAGE_TMP
290
sage: (out, err, ret) = test_executable(["sage", "-t", script])
291
sage: ret
292
128
293
sage: out.find("1 items had failures:") >= 0
294
True
295
sage: os.environ['SAGE_TESTDIR'] = OLD_TESTDIR # just in case
296
297
Test external programs being called by Sage::
298
299
sage: (out, err, ret) = test_executable(["sage", "--sh"], "echo Hello World\nexit 42\n")
300
sage: out.find("Hello World\n") >= 0
301
True
302
sage: ret
303
42
304
305
sage: (out, err, ret) = test_executable(["sage", "--sh", "-c", "echo Hello World; exit 42"])
306
sage: out.find("Hello World\n") >= 0
307
True
308
sage: ret
309
42
310
311
When testing IPython, use Sage's ipython directory, to avoid
312
incompatibilities for config files among different versions of
313
IPython. ::
314
315
sage: os.environ['IPYTHONDIR'] = os.path.join(os.environ['DOT_SAGE'], 'ipython')
316
sage: (out, err, ret) = test_executable(["sage", "--ipython"], "\n3**33\n")
317
sage: out.find("5559060566555523") >= 0
318
True
319
sage: err
320
''
321
sage: ret
322
0
323
324
sage: (out, err, ret) = test_executable(["sage", "--python"], "print 3^33\n")
325
sage: out
326
'34\n'
327
sage: err
328
''
329
sage: ret
330
0
331
332
sage: (out, err, ret) = test_executable(["sage", "--cython"])
333
sage: print err
334
Cython (http://cython.org) is a compiler for code written in the
335
Cython language. Cython is based on Pyrex by Greg Ewing.
336
...
337
338
sage: (out, err, ret) = test_executable(["sage", "--ecl"], "(* 12345 54321)\n")
339
sage: out.find("Embeddable Common-Lisp") >= 0
340
True
341
sage: out.find("670592745") >= 0
342
True
343
sage: err
344
''
345
sage: ret
346
0
347
348
sage: (out, err, ret) = test_executable(["sage", "--lisp"], "(* 12345 54321)\n")
349
sage: out.find("Embeddable Common-Lisp") >= 0
350
True
351
sage: out.find("670592745") >= 0
352
True
353
sage: err
354
''
355
sage: ret
356
0
357
358
sage: (out, err, ret) = test_executable(["sage", "--gap", "-q"], "Size(SymmetricGroup(5));\n")
359
sage: out
360
'120\n'
361
sage: err
362
''
363
sage: ret
364
0
365
366
sage: (out, err, ret) = test_executable(["sage", "--kash", "-b", "3^33;\n"]) # optional - kash
367
sage: out.find("5559060566555523") >= 0 # optional - kash
368
True
369
sage: err # optional - kash
370
''
371
sage: ret # optional - kash
372
0
373
374
sage: (out, err, ret) = test_executable(["sage", "--mwrank", "-v0", "-q", "-o"], "0 0 1 -7 6 0 0 0 0 0\n")
375
sage: out
376
'Curve [0,0,1,-7,6] :\tRank = 3\n[[3],[[1,-1],[-2,3],[-7/4,25/8]]]\n\n\n'
377
sage: err
378
''
379
sage: ret
380
0
381
382
sage: (out, err, ret) = test_executable(["sage", "--singular"], "12345*54321;\n")
383
sage: out.find("A Computer Algebra System for Polynomial Computations") >= 0
384
True
385
sage: out.find("670592745") >= 0
386
True
387
sage: err
388
''
389
sage: ret
390
0
391
392
Check that ``sage-make_relative`` did its job. We test it on the
393
``ipython`` script::
394
395
sage: open(os.path.join(SAGE_ROOT, "local", "bin", "ipython")).readline()
396
'#!/usr/bin/env python\n'
397
398
Test GP using the ``-f`` option which prevents the reading of a ``.gprc``
399
configuration file::
400
401
sage: (out, err, ret) = test_executable(["sage", "--gp", "-f"], "3^33\nquit(42)\n")
402
sage: out.find("PARI/GP") >= 0
403
True
404
sage: out.find("5559060566555523") >= 0
405
True
406
sage: err
407
''
408
sage: ret
409
42
410
411
Some programs of which we check functionality using only ``--version``::
412
413
sage: (out, err, ret) = test_executable(["sage", "--hg", "--version"])
414
sage: out.find("Mercurial Distributed SCM") >= 0
415
True
416
sage: err
417
''
418
sage: ret
419
0
420
421
sage: (out, err, ret) = test_executable(["sage", "--maxima", "--version"])
422
sage: out.find("Maxima ") >= 0
423
True
424
sage: err
425
''
426
sage: ret
427
0
428
429
sage: (out, err, ret) = test_executable(["sage", "--R", "--version"])
430
sage: out.find("R version ") >= 0
431
True
432
sage: err
433
''
434
sage: ret
435
0
436
437
sage: (out, err, ret) = test_executable(["sage", "--scons", "--version"])
438
sage: out.find("SCons") >= 0
439
True
440
sage: err
441
''
442
sage: ret
443
0
444
445
sage: (out, err, ret) = test_executable(["sage", "--sqlite3", "--version"])
446
sage: out.startswith("3.")
447
True
448
sage: err
449
''
450
sage: ret
451
0
452
453
Check some things requiring an internet connection::
454
455
sage: (out, err, ret) = test_executable(["sage", "--standard"]) # optional - internet
456
sage: out.find("atlas") >= 0 # optional - internet
457
True
458
sage: err # optional - internet
459
''
460
sage: ret # optional - internet
461
0
462
463
sage: (out, err, ret) = test_executable(["sage", "--optional"]) # optional - internet
464
sage: out.find("database_cremona_ellcurve") >= 0 # optional - internet
465
True
466
sage: err # optional - internet
467
''
468
sage: ret # optional - internet
469
0
470
471
sage: (out, err, ret) = test_executable(["sage", "--experimental"]) # optional - internet
472
sage: out.find("macaulay2") >= 0 # optional - internet
473
True
474
sage: err # optional - internet
475
''
476
sage: ret # optional - internet
477
0
478
479
Check an illegal command line option. This outputs an error to stdout,
480
but we allow stderr in case this changes in the future::
481
482
sage: (out, err, ret) = test_executable(["sage", "--zzfoobar"])
483
sage: (out+err).find("unknown option: --zzfoobar") >= 0
484
True
485
sage: ret > 0
486
True
487
488
"""
489
p = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE)
490
if input: p.stdin.write(input)
491
p.stdin.close()
492
fdout = p.stdout.fileno()
493
fderr = p.stderr.fileno()
494
out = ""; err = ""
495
496
while True:
497
# Try reading from fdout and fderr
498
rfd = []
499
if fdout: rfd.append(fdout)
500
if fderr: rfd.append(fderr)
501
if len(rfd) == 0: break
502
rlist = select.select(rfd, [], [], timeout)[0]
503
504
if len(rlist) == 0:
505
# Timeout!
506
p.terminate()
507
raise RuntimeError("timeout in test_executable()")
508
if fdout in rlist:
509
s = os.read(fdout, 1024)
510
if s == "": fdout = None # EOF
511
out += s
512
if fderr in rlist:
513
s = os.read(fderr, 1024)
514
if s == "": fderr = None # EOF
515
err += s
516
517
return (out, err, p.wait())
518
519