root/trunk/ProjectFortress/src/com/sun/fortress/tests/unit_tests/FileTests.java @ 3909

Revision 3909, 41.8 KB (checked in by sukyoungryu, 5 months ago)

[parser] Implemented some simple ASCII conversion. Added a test.

Line 
1/*******************************************************************************
2    Copyright 2009 Sun Microsystems, Inc.,
3    4150 Network Circle, Santa Clara, California 95054, U.S.A.
4    All rights reserved.
5
6    U.S. Government Rights - Commercial software.
7    Government users are subject to the Sun Microsystems, Inc. standard
8    license agreement and applicable provisions of the FAR and its supplements.
9
10    Use is subject to license terms.
11
12    This distribution may include materials developed by third parties.
13
14    Sun, Sun Microsystems, the Sun logo and Java are trademarks or registered
15    trademarks of Sun Microsystems, Inc. in the U.S. and other countries.
16 ******************************************************************************/
17
18package com.sun.fortress.tests.unit_tests;
19import java.io.BufferedReader;
20import java.io.ByteArrayOutputStream;
21import java.io.File;
22import java.io.FileNotFoundException;
23import java.io.IOException;
24import java.io.InputStream;
25import java.io.OutputStream;
26import java.io.PrintStream;
27import java.util.ArrayList;
28import java.util.Arrays;
29import java.util.List;
30import java.util.Map;
31import java.util.Random;
32import java.util.StringTokenizer;
33
34import junit.framework.Test;
35import junit.framework.TestCase;
36import junit.framework.TestResult;
37import junit.framework.TestSuite;
38
39import com.sun.fortress.compiler.index.ComponentIndex;
40import com.sun.fortress.Shell;
41import com.sun.fortress.interpreter.Driver;
42import com.sun.fortress.interpreter.evaluator.Init;
43import com.sun.fortress.nodes.APIName;
44import com.sun.fortress.nodes.CompilationUnit;
45import com.sun.fortress.nodes.Component;
46import com.sun.fortress.nodes_util.NodeFactory;
47import com.sun.fortress.repository.ProjectProperties;
48import com.sun.fortress.repository.GraphRepository;
49import com.sun.fortress.useful.StreamForwarder;
50import com.sun.fortress.useful.StringMap;
51import com.sun.fortress.useful.Useful;
52import com.sun.fortress.useful.WireTappedPrintStream;
53
54import edu.rice.cs.plt.iter.IterUtil;
55
56public class FileTests {
57
58    private static  String join(String dir, String file) {
59        if (dir.length() == 0)
60            return file;
61        else return dir + "/" + file;
62    }
63
64    public static class BaseTest extends TestCase {
65        /**
66         * Directory-qualified file name
67         */
68        String f;
69        /**
70         * Just the directory.
71         */
72        String dir;
73        /**
74         * The name of the test.
75         */
76        String name;
77        /**
78         * The search path for analysis, compilation, etc.
79         */
80        String path;
81
82        /**
83         * If true, only print test output for unexpected results.
84         */
85        final boolean unexpectedOnly;
86        final boolean knownFailure;
87        final boolean shouldFail;
88
89        final boolean printSuccess;
90        final boolean printFailure;
91
92        public BaseTest(String path, String d, String s, boolean unexpected_only,
93                        boolean knownFailure,
94                        boolean shouldFail) {
95            super("testFile");
96            this.f = join(d,s);
97            this.dir = d;
98            this.path = path;
99            this.name = s;
100            this.unexpectedOnly = unexpected_only;
101
102            this.printSuccess = !unexpected_only || knownFailure;
103            this.printFailure = !unexpected_only || !knownFailure;
104            this.knownFailure = knownFailure;
105            this.shouldFail = shouldFail;
106        }
107
108        public String getName() {
109            return f;
110        }
111
112        /**
113         * Returns true if this test should be regarded as a "Failure",
114         * regardless of the XXX test name or not.  This can be used to
115         * test that a particular exception was thrown, for example; not only
116         * should (say) XXXbadNumber thrown an exception, it should throw
117         * a NumberFormatException.  Thus, the exc string could be tested
118         * to see that it contains "NumberFormatException".
119         *
120         *
121         * @param out
122         * @param err
123         * @param exc
124         * @return
125         */
126        public  String testFailed(String out, String err, String exc) {
127            return null;
128        }
129
130        /**
131         * Looks for properties of the form
132         * compile/link/run_
133         * out/err/exceptions_
134         * contains/matches/WImatches/equals/WCIequals,
135         * returns true if an expected condition fails.
136         *
137         * @param pfx
138         * @param props
139         * @param out
140         * @param err
141         * @param exc
142         * @return
143         */
144        protected String generalTestFailed(String pfx, StringMap props, String out, String err, String exc) {
145            String s = null;
146
147            if (s == null)
148                s = generalTestFailed(pfx, props, "out",  out);
149
150            if (s == null)
151                s = generalTestFailed(pfx, props, "err",  err);
152
153            if (s == null)
154                s = generalTestFailed(pfx, props, "exception",  exc) ;
155            return s;
156
157        }
158
159        private String generalTestFailed(String pfx, StringMap props,
160                String which, String contents) {
161            String what;
162            String test;
163
164            boolean any_check = false;
165
166            what = pfx+which+"_contains";
167            test = props.get(what);
168            test = ProjectProperties.get(test);
169            if (test != null && test.length() > 0) {
170                if (!contents.contains(test))
171                    return what+"="+test;
172                any_check = true;
173            }
174
175            what = pfx+which+"_matches";
176            test = props.get(what);
177            test = ProjectProperties.get(test);
178            if (test != null && test.length() > 0) {
179                if (!contents.matches(test))
180                    return what+"="+test;
181                any_check = true;
182           }
183
184            what = pfx+which+"_WImatches";
185            test = props.get(what);
186            test = ProjectProperties.get(test);
187            if (test != null && test.length() > 0) {
188                String wi_contents = contents.replaceAll("\\s+", " ").trim();
189                if (!wi_contents.matches(test))
190                    return what+"="+test;
191                any_check = true;
192           }
193
194            what = pfx+which+"_WCIequals";
195            test = props.get(what);
196            test = props.getCompletely(test);
197            if (test != null && test.length() > 0) {
198                String wci_contents = contents.replaceAll("\\s+", " ").trim();
199                String wci_test = test.replaceAll("\\s+", " ").trim();
200                if (!wci_contents.equalsIgnoreCase(wci_test))
201                    return what+"="+test;
202                any_check = true;
203            }
204
205            what = pfx+which+"_equals";
206            test = props.get(what);
207            test = props.getCompletely(test);
208            if (test != null && test.length() > 0) {
209
210                String wi_contents = contents.replaceAll("[ \\\t]+", " ");
211                String wi_test = test.replaceAll("[ \\\t]+", " ");
212                // Convert Windows CRLF to UNIX LF
213                wi_contents = wi_contents.replaceAll("\\\r\\\n","\n");
214                wi_test = wi_test.replaceAll("\\\r\\\n","\n");
215                // Convert Mac CR to UNIX LF
216                wi_contents = wi_contents.replaceAll("\\\r","\n");
217                wi_test = wi_test.replaceAll("\\\r","\n");
218
219                if (!wi_contents.equals(wi_test)) {
220                    if (wi_contents.trim().equals(wi_test.trim())) {
221                        // It is a leading/trailing whitespace problem....
222                        char c0 = wi_contents.charAt(0);
223                        char t0 = wi_test.charAt(0);
224                        char cN = wi_contents.charAt(wi_contents.length()-1);
225                        char tN = wi_test.charAt(wi_test.length()-1);
226                        String problem = "";
227                        if (c0 == ' ' || c0 == '\n') {
228                            if (t0 == ' ' || t0 == '\n') {
229
230                            } else {
231                                problem += "text began with unexpected whitespace";
232                            }
233                        } else {
234                            if (t0 == ' ' || t0 == '\n') {
235                                problem += "text began without expected whitespace";
236                            } else {
237
238                            }
239                        }
240
241                        String problemAnd = problem.length() > 0 ? problem + " and " : problem;
242
243                        if (cN == ' ' || cN == '\n') {
244                            if (tN == ' ' || tN == '\n') {
245
246                            } else {
247                                problem = problemAnd + "text ended with unexpected whitespace";
248                            }
249                        } else {
250                            if (tN == ' ' || tN == '\n') {
251                                problem = problemAnd + "text ended without expected whitespace";
252                            } else {
253
254                            }
255                        }
256
257                        return what + ": " + problem;
258                    } else if (wi_contents.replaceAll("\\s+", " ").trim().equals(wi_test.replaceAll("\\s+", " ").trim())) {
259                        String cL = wi_contents.replaceAll("\n[ \t]+", "\n").trim();
260                        String cT = wi_contents.replaceAll("[ \t]+\n", "\n").trim();
261                        String tL = wi_test.replaceAll("\n[ \t]+", "\n").trim();
262                        String tT = wi_test.replaceAll("[ \t]+\n", "\n").trim();
263
264                        if (cL.equals(tL))
265                            return what + ": different LEADING whitespace on some line(s)";
266
267                        else if (cT.equals(tT))
268                            return what + ": different TRAILING whitespace on some line(s)";
269
270                        else if (wi_contents.replaceAll("[ \\\t]*\\\n[ \\\t]*", "\n").trim().equals(wi_test.replaceAll("[ \\\t]*\\\n[ \\\t]*", "\n").trim()))
271                            return what + ": different LEADING AND TRAILING whitespace on some line(s)";
272
273                        return what + ": some sort of an internal whitespace problem (linebreaks?)";
274                    }
275                    return what+"="+test;
276                }
277                any_check = true;
278           }
279
280            if (!any_check && pfx.equals("run_") && which.equals("out")) {
281                // If there is no check specified on run_out, demand that it
282                // contain "pass" or "PASS".
283                if (!(contents.contains("pass") || contents.contains("PASS"))) {
284                    return "default check run_out_contains=PASS";
285                }
286            }
287
288            return null;
289        }
290
291    }
292
293    /**
294     * For tests that are applied to a single source file (or are rooted at a
295     * single source file), this takes care of checking for success/failure,
296     * what is expected, printing, etc.
297     */
298    public abstract static class SourceFileTest extends BaseTest {
299        public SourceFileTest(String path, String d, String s,
300                boolean unexpected_only,
301                boolean knownFailure,
302                boolean shouldFail) {
303            super(path, d, s, unexpected_only, knownFailure, shouldFail);
304        }
305
306        public abstract String tag();
307
308         public void testFile() throws Throwable {
309            // Useful when a test is running forever
310            //            System.out.println(this.name);
311            //            System.out.flush();
312
313            PrintStream oldOut = System.out;
314            PrintStream oldErr = System.err;
315            WireTappedPrintStream wt_err =
316                WireTappedPrintStream.make(System.err, unexpectedOnly);
317            WireTappedPrintStream wt_out =
318                WireTappedPrintStream.make(System.out, unexpectedOnly);
319            System.setErr(wt_err);
320            System.setOut(wt_out);
321
322
323            long start = System.nanoTime();
324            String fssFile = f + ".fss";
325            int rc = 0;
326
327            try {
328                //BufferedReader in = null;
329                try {
330                    oldOut.print(" " + tag() + " ") ; oldOut.print(f); oldOut.print(" "); oldOut.flush();
331                    //in = Useful.utf8BufferedFileReader(fssFile);
332
333                    rc = justTheTest();
334                }
335                finally {
336                    System.setErr(oldErr);
337                    System.setOut(oldOut);
338                    //if (in != null)
339                    //    in.close();
340                }
341            }
342            catch (Throwable ex) {
343                String outs = wt_out.getString();
344                String errs = wt_err.getString();
345                String exFirstLine = ex.toString();
346                String trueFailure = testFailed(outs, errs, exFirstLine);
347                if (f.contains("XXX")) {
348                    if (trueFailure != null) {
349                        unexpectedExceptionBoilerplate(wt_err, wt_out, ex, " Did not satisfy " + trueFailure);
350                        return;
351
352                    } else {
353                        // "Failed", but correctly
354                        // !unexpectedOnly || expectFailure
355                        wt_err.flush(printSuccess);
356                        wt_out.flush(printSuccess);
357                        int crLoc = exFirstLine.indexOf("\n");
358                        if (crLoc == -1) crLoc = exFirstLine.length();
359                        exFirstLine = exFirstLine.substring(0, crLoc);
360                        if (printSuccess)
361                            System.out.println(exFirstLine);
362                        System.out.println(" OK Saw expected exception");
363                        return;
364                    }
365                }
366                else {
367                    unexpectedExceptionBoilerplate(wt_err, wt_out, ex, " UNEXPECTED exception ");
368                    // return;
369                }
370            } finally {
371                            //fr.clear();
372            }
373
374            /* Come here IFF NO EXCEPTIONS, to analyze output */
375
376            String outs = wt_out.getString();
377            String errs = wt_err.getString();
378
379            boolean anyFails = outs.contains("fail") || outs.contains("FAIL") ||
380                      errs.contains("fail") || errs.contains("FAIL") || rc != 0;
381
382            String trueFailure = testFailed(outs, errs, "");
383
384            if (shouldFail) {
385                // NOTE expect to see this on STANDARD OUTPUT, not ERROR.
386                if (anyFails && trueFailure == null) {
387                    wt_err.flush(printSuccess);
388                    wt_out.flush(printSuccess);
389                    // Saw a failure, that is good.
390                    System.out.println(" Saw expected failure" );
391                } else {
392                    if (printFailure) System.out.println();
393                    wt_err.flush(printFailure);
394                    wt_out.flush(printFailure);
395                    if (trueFailure != null) {
396                        System.out.println(" Saw failure, but did not satisfy " + trueFailure);
397                        // Expected exception, saw none.
398                        fail("Saw wrong failure.");
399                    } else {
400                        System.out.println(" Missing expected failure " );
401                        // Expected exception, saw none.
402                        fail("Expected failure or exception, saw none.");
403                    }
404                }
405            } else {
406                // This logic is a little confusing.
407                // Failure is failure.  TrueFailure contains the better message.
408                if (anyFails && trueFailure == null)
409                    trueFailure = "FAIL or fail should not appear in output";
410
411                long duration = (System.nanoTime() - start) / 1000000;
412                    System.out.println(trueFailure != null ? " FAIL" : " OK (time = " + duration + "ms)");
413                    wt_err.flush(trueFailure != null ? printFailure : printSuccess);
414                    wt_out.flush(trueFailure != null ? printFailure : printSuccess);
415
416                    assertTrue("Must satisfy " + trueFailure, trueFailure == null);
417
418            }
419        }
420
421        /**
422         * @param wt_err
423         * @param wt_out
424         * @param ex
425         * @param s
426         * @throws IOException
427         */
428        private void unexpectedExceptionBoilerplate(
429                WireTappedPrintStream wt_err, WireTappedPrintStream wt_out,
430                Throwable ex, String s) throws IOException {
431            if (printFailure) System.out.println();
432            wt_err.flush(printFailure);
433            wt_out.flush(printFailure);
434            if (printFailure) {
435                System.out.println(s);
436                ex.printStackTrace();
437                fail();
438            } else {
439                System.out.println(s);
440                fail(ex.getMessage());
441            }
442        }
443
444        abstract protected int justTheTest() throws FileNotFoundException, IOException, Throwable;
445
446    }
447
448    public static class TestTest extends BaseTest {
449
450        private final StringMap props;
451
452        public TestTest(StringMap props, String path, String d, String s,
453                boolean unexpected_only, boolean knownFailure, boolean shouldFail) {
454            super(path, d, s, unexpected_only, knownFailure, shouldFail);
455            this.props = props;
456        }
457
458        static boolean whinedAboutTimingIssues = false;
459
460        public void testFile() throws Throwable {
461            String scriptName = ProjectProperties.FORTRESS_AUTOHOME
462                    + "/bin/fortress";
463            Runtime runtime = Runtime.getRuntime();
464            System.out.print(" run  ");
465            System.out.print(f);
466            System.out.print(" ");
467            System.out.flush();
468
469            ArrayList<String> commandAndArgs = new ArrayList<String>();
470            commandAndArgs.add(scriptName);
471            commandAndArgs.add("run");
472            commandAndArgs.add(name);
473            for (int i=1; i < Integer.MAX_VALUE; i++) {
474                String s = props.get("arg"+String.valueOf(i));
475                if (s == null) {
476                    break;
477                }
478                commandAndArgs.add(s);
479            }
480
481
482            ProcessBuilder pb = new ProcessBuilder(commandAndArgs);
483            Map<String, String> env = pb.environment();
484            if (!env.containsKey("FORTRESS_HOME")) {
485                env.put("FORTRESS_HOME", ProjectProperties.FORTRESS_AUTOHOME);
486            }
487
488            long start_time = System.currentTimeMillis();
489
490            Process p = pb.start();
491            InputStream err = p.getErrorStream();
492            InputStream out = p.getInputStream();
493            OutputStream in = p.getOutputStream();
494            in.close();
495
496            ByteArrayOutputStream cached_err = new ByteArrayOutputStream();
497            ByteArrayOutputStream cached_out = new ByteArrayOutputStream();
498
499            StreamForwarder f_out = new StreamForwarder(out, cached_out, true);
500            StreamForwarder f_err = new StreamForwarder(err, cached_err, true);
501
502            f_out.join();
503            f_err.join();
504            int exitValue = p.waitFor();
505
506            long stop_time = System.currentTimeMillis();
507
508            String s_out = cached_out.toString();
509            String s_err = cached_err.toString();
510
511            boolean fail_exit = exitValue != 0;
512            // We've decided that exit codes are definitive.
513            boolean fail_out = false && s_out.contains("FAIL");
514            boolean fail_err = false && s_err.contains("FAIL");
515            boolean failed = fail_exit || fail_out || fail_err;
516            String fail_cause = !failed ? ""
517                    : ((fail_exit ? "Exit code != 0" : "")
518                            + (fail_out ? " Stdout contained FAIL" : "") + (fail_err ? " Stderr contained FAIL"
519                            : "")).trim();
520
521            String trueFailure = testFailed(s_out, s_err, "");
522
523            if (trueFailure != null) {
524                fail_cause = "Failed to satisfy " + trueFailure;
525                failed = true;
526            }
527
528            if (!failed) {
529                // check for timing constraint.
530                String timingfile_name = join(dir,name) + ".timing";
531                File timingfile = new File(timingfile_name);
532                if (timingfile.exists()) {
533                    // Only check timing constraint if file exists.
534                    StringMap tprops = new StringMap.FromFileProps(
535                            timingfile_name);
536                    tprops = ProjectProperties.composedWith(tprops);
537                    String whoami = tprops.get("machine.type", "");
538
539                    if (whoami.length() == 0) {
540                        // Complain if no machine type supplied
541                        System.err.println("No machine.type (MACHINE_TYPE) provided for timing constraint");
542                    } else if (whoami.equals("untimed")) {
543                       // do nothing
544                    } else {
545
546
547                        int timeLimit = tprops.getInt(whoami, -1);
548
549                        if (timeLimit == -1) {
550                            // Complain if machine type not listed
551                            System.err.println("machine.type (MACHINE_TYPE) " + whoami + " not listed in timing file " + timingfile_name);
552
553                        } else {
554                            long elapsed = (stop_time - start_time);
555                            if (timeLimit < elapsed) {
556                                // Late answers are wrong.
557                                fail_cause = "Failed timing deadline " + timeLimit +
558                                " for machine.type " + whoami + " from timing file " + timingfile_name + "; elapsed was " + elapsed;
559                                failed = true;
560
561                            } else {
562                                // Time ok.
563                            }
564                        }
565                    }
566
567                }
568            }
569
570            // OY, pass/fail dsylexia here.
571
572            if (failed && printFailure || !failed && printSuccess) {
573                System.out.print(s_out);
574                System.out.print(s_err);
575            }
576
577            if (trueFailure != null) {
578                System.out.println("Failed to satisfy " + trueFailure);
579                fail();
580
581            } else if (shouldFail != failed) {
582                System.out.println(failed ? "UNEXPECTED failure (" + fail_cause
583                        + ")" : "Did not see expected failure");
584                fail();
585            } else {
586                System.out.println(failed ? "Saw expected failure ("
587                        + fail_cause + ")" : "Passed");
588            }
589        }
590
591        public String testFailed(String out, String err, String exc) {
592            return generalTestFailed("run_", props, out, err, exc);
593
594        }
595    }
596
597
598
599    public static class ShellTest extends BaseTest {
600
601        public ShellTest(String path, String d, String s, boolean unexpected_only, boolean knownFailure) {
602            super(path, d, s, unexpected_only, knownFailure, s.startsWith("XXX") );
603        }
604
605        public void testFile() throws Throwable {
606            String scriptName = f + ".sh";
607            Runtime runtime = Runtime.getRuntime();
608            System.out.print("  ") ; System.out.print(f); System.out.print(" "); System.out.flush();
609
610            ProcessBuilder pb = new ProcessBuilder(scriptName);
611            Map<String, String> env = pb.environment();
612            if (! env.containsKey("FORTRESS_HOME")) {
613                env.put("FORTRESS_HOME", ProjectProperties.FORTRESS_AUTOHOME);
614            }
615            Process p = pb.start();
616            InputStream err = p.getErrorStream();
617            InputStream out = p.getInputStream();
618            OutputStream in = p.getOutputStream();
619            in.close();
620
621            ByteArrayOutputStream cached_err = new ByteArrayOutputStream();
622            ByteArrayOutputStream cached_out = new ByteArrayOutputStream();
623
624            StreamForwarder f_out = new StreamForwarder(out, cached_out, true);
625            StreamForwarder f_err = new StreamForwarder(err, cached_err, true);
626
627                f_out.join();
628                f_err.join();
629                int exitValue = p.waitFor();
630                String s_out = cached_out.toString();
631                String s_err = cached_err.toString();
632
633                boolean fail_exit = exitValue != 0;
634                // We've decided that exit codes are definitive.
635                boolean fail_out =  false && s_out.contains("FAIL");
636                boolean fail_err =  false && s_err.contains("FAIL");
637                boolean failed = fail_exit || fail_out || fail_err;
638                String fail_cause = !failed ? "" : (
639                        (fail_exit ? "Exit code != 0" : "") +
640                        (fail_out ? " Stdout contained FAIL" : "") +
641                        (fail_err ? " Stderr contained FAIL" : "")
642                ).trim();
643
644                if (failed && printFailure || !failed && printSuccess) {
645                    System.out.print(s_out);
646                    System.out.print(s_err);
647                }
648
649                if (shouldFail != failed) {
650                    System.out.println(failed ? "UNEXPECTED failure ("+ fail_cause+")" : "Did not see expected failure");
651                    fail();
652                } else {
653                    System.out.println(failed ? "Saw expected failure ("+ fail_cause+")" : "Passed");
654                }
655        }
656    }
657
658    private static String makeTestFileName(String name) {
659        if (name.endsWith(".fss") || name.endsWith(".fsi") ) {
660            return name;
661        } else return name+".fss";
662    }
663
664    public static class CommandTest extends SourceFileTest {
665        private final String command;
666        private final StringMap props;
667        public CommandTest(String command, StringMap props, String path, String d, String s,
668                           boolean unexpected_only, boolean knownFailure, boolean shouldFail) {
669            super(path, d, s, unexpected_only, knownFailure, shouldFail );
670            this.command = command;
671            this.props = props;
672        }
673
674        @Override
675        protected int justTheTest()
676                throws FileNotFoundException, IOException, Throwable {
677            String[] tokens = new String [] {command, join(dir, makeTestFileName(name))};
678            int rc = com.sun.fortress.Shell.subMain(tokens);
679            return rc;
680
681        }
682
683        @Override
684        public String tag() {
685            // TODO Auto-generated method stub
686            return command;
687        }
688
689        public  String testFailed(String out, String err, String exc) {
690            return generalTestFailed(command + "_", props, out, err, exc);
691        }
692
693    }
694
695    public static class InterpreterTest extends SourceFileTest {
696
697        public InterpreterTest(String path, String d, String s, boolean unexpected_only, boolean knownFailure) {
698            super(path, d, s, unexpected_only, knownFailure, s.startsWith("XXX"));
699        }
700
701
702        /**
703         * @param repository
704         * @param apiname
705         * @throws FileNotFoundException
706         * @throws IOException
707         * @throws Throwable
708         */
709        protected int justTheTest()
710                throws FileNotFoundException, IOException, Throwable {
711            String s = f.replaceFirst(".*/", "");
712            APIName apiname = NodeFactory.makeAPIName(NodeFactory.testSpan, s);
713            GraphRepository repository = Shell.specificInterpreterRepository( ProjectProperties.SOURCE_PATH.prepend(path) );
714
715            ComponentIndex ci = repository.getLinkedComponent(apiname);
716
717            //Option<CompilationUnit> _p = ASTIO.parseToJavaAst(fssFile, in, false);
718
719            {
720                Component p = (Component) ci.ast();
721
722                // oldOut.print(" RUNNING"); oldOut.flush();
723                if (!unexpectedOnly) System.out.println();
724                // A demo file requiring arguments
725                if (name.equals("tennisRanking")) {
726                    ArrayList<String> args = new ArrayList<String>();
727                    args.add(dir + "/tennis050307");
728                    args.add(dir + "/tennis051707");
729                    args.add(dir + "/tennisGames");
730                    Driver.runProgram(repository, ci, args);
731                }
732                // Test files requiring "test" command
733                else if (name.equals("XXXTestTest") ||
734                         name.equals("natInference0") ||
735                         name.equals("testTest1") ||
736                         name.equals("testTest2")) {
737                    Driver.runTests(repository, ci, false);
738                }
739                else {
740                    Driver.runProgram(repository, ci, new ArrayList<String>());
741                }
742            }
743            return 0;
744        }
745
746
747        @Override
748        public String tag() {
749            // TODO Auto-generated method stub
750            return "interpret";
751        }
752
753    }
754    public static void main(String[] args) throws IOException {
755        junit.textui.TestRunner.run(FileTests.interpreterSuite("shelltests", true, false));
756        junit.textui.TestRunner.run(FileTests.interpreterSuite("tests", true, false));
757        junit.textui.TestRunner.run(FileTests.interpreterSuite("not_passing_yet", false, true));
758    }
759
760    public static TestSuite interpreterSuite(
761            String dir_name,
762            boolean failsOnly,
763            boolean expect_failure) throws IOException {
764
765        TestSuite suite = new TestSuite("Runs all tests in " + dir_name) {
766            public void run(TestResult result) {
767                super.run(result);
768                Init.allowForLeakChecks();
769            }
770        };
771
772        String dirname = ProjectProperties.backslashToSlash(dir_name);
773        File dir = directoryAsFile(dirname);
774        System.err.println(dir);
775
776        /* Many lines of random number generator seed nonsense. */
777
778        Iterable<String> shuffled = shuffledFileList(dir, true);
779
780        int testCount = testCount();
781        int i = testCount;
782
783        for(String s : shuffled){
784              if (i <= 0) {
785                  System.out.println("Early testing exit after " + testCount + " tests");
786                  break;
787              }
788              boolean decrement = true;
789              if (s.endsWith("Syntax.fss") || s.endsWith("DynamicSemantics.fss")) {
790                  System.out.println("Not compiling file " + s);
791                  decrement = false;
792              } else if (!s.startsWith(".")) {
793                  if (s.endsWith(".fss")) {
794                      int l = s.lastIndexOf(".fss");
795                      String testname = s.substring(0, l);
796                      suite.addTest(new InterpreterTest(dir.getCanonicalPath(), dirname, testname, failsOnly, expect_failure));
797                  } else if (s.endsWith(".sh")) {
798                      int l = s.lastIndexOf(".sh");
799                      String testname = s.substring(0, l);
800                      suite.addTest(new ShellTest(dir.getCanonicalPath(), dirname, testname, failsOnly, expect_failure));
801                  } else {
802                      System.out.println("Not compiling file " + s);
803                      decrement = false;
804                  }
805              }
806
807              if (decrement) {
808                  i--;
809              }
810
811        }
812        return suite;
813    }
814
815    /**
816     * Generates a suite of tests from directory dir_name, using "foo.test" files
817     * to determine the content of the test.  failsOnly means to only print failing
818     * tests (either normal tests that fail, or XXX tests that succeed).
819     *
820     * WARNING: expect_failure  is not treated consistently.
821     *
822     * It either means, "the test fails, and that is a good thing",
823     * or it means, "the test fails, it is a bad thing, but we are working on it
824     * and do not want to be bothered by something we already know is a problem".
825     *
826     * @param dir_name_from_user
827     * @param failsOnly
828     * @param expect_failure
829     * @return
830     * @throws IOException
831     */
832    public static TestSuite compilerSuite(String dir_name_from_user,
833                                          boolean shuffle,
834                                          boolean failsOnly,
835                                          boolean expect_failure) throws IOException {
836
837        String dir_name_slashes_normalized = ProjectProperties.backslashToSlash(dir_name_from_user);
838        File dir = directoryAsFile(dir_name_slashes_normalized);
839        System.err.println(dir);
840        String dir_name_canonical = dir.getCanonicalPath();
841
842        /* Many lines of random number generator seed nonsense. */
843
844        Iterable<String> shuffled = shuffledFileList(dir, shuffle);
845
846        return suiteFromListOfFiles(shuffled, dir_name_from_user,
847                dir_name_slashes_normalized, dir_name_canonical, failsOnly,
848                expect_failure);
849    }
850
851    /**
852     * @param shuffled
853     * @param dir_name_from_user
854     * @param dir_name_slashes_normalized
855     * @param dir_name_canonical
856     * @param failsOnly
857     * @param expect_failure
858     * @return
859     * @throws IOException
860     */
861    public static TestSuite suiteFromListOfFiles(Iterable<String> shuffled,
862            String dir_name_from_user, String dir_name_slashes_normalized,
863            String dir_name_canonical, boolean failsOnly, boolean expect_failure)
864            throws IOException {
865        int testCount = testCount();
866        int i = testCount;
867
868        TestSuite suite = new TestSuite("Runs all tests in " + dir_name_from_user) {
869            public void run(TestResult result) {
870                super.run(result);
871                Init.allowForLeakChecks();
872            }
873        };
874
875        List<Test> commandTests = new ArrayList<Test>();
876        List<Test> runTests = new ArrayList<Test>();
877
878        for(String s : shuffled){
879              int slashi = s.lastIndexOf('/');
880              if (slashi != -1) {
881                  String candidatedir = s.substring(0,slashi);
882                  s = s.substring(slashi+1);
883                  dir_name_from_user = candidatedir;
884                  dir_name_slashes_normalized = candidatedir;
885                  dir_name_canonical =
886                      directoryAsFile(dir_name_slashes_normalized).getCanonicalPath();
887              }
888
889
890              if (i <= 0) {
891                  System.out.println("Early testing exit after " + testCount + " tests");
892                  break;
893              }
894              boolean decrement = true;
895              boolean shouldFail = s.startsWith("XXX");
896
897              if (s.endsWith(".fss") || s.endsWith(".fsi") ) {
898                  // do nothing
899                  decrement = false;
900              } else if (!s.startsWith(".")) {
901                  if (s.endsWith(".sh")) {
902                      int l = s.lastIndexOf(".sh");
903                      String testname = s.substring(0, l);
904                      suite.addTest(new ShellTest(dir_name_canonical, dir_name_slashes_normalized, testname, failsOnly, expect_failure));
905                  } else if (s.endsWith(".test")) { // need to define the test of tests.
906
907                      StringMap props = new StringMap.FromFileProps(join(dir_name_canonical, s));
908                      props = ProjectProperties.composedWith(props);
909
910                      int l = s.lastIndexOf(".test");
911                      String testname = s.substring(0, l);
912
913                      String testNames = props.get("tests");
914                      if (testNames == null)
915                          testNames = "";
916                      else
917                          testNames = testNames.trim();
918
919                      if (testNames.length() > 0) {
920                          StringTokenizer st = new StringTokenizer(testNames);
921                          while  (st.hasMoreTokens()) {
922                              String token = st.nextToken();
923                                  standardCompilerTests(props, dir_name_canonical, dir_name_slashes_normalized, token,
924                                                        expect_failure, shouldFail, failsOnly,
925                                                        commandTests, runTests);
926                          }
927                      }
928                      else {
929                              standardCompilerTests(props, dir_name_canonical, dir_name_slashes_normalized, testname,
930                                                    expect_failure, shouldFail, failsOnly,
931                                                    commandTests, runTests);
932                      }
933                  } else {
934                      System.out.println("Not compiling file " + s);
935                      decrement = false;
936                  }
937              }
938
939              if (decrement) {
940                  i--;
941              }
942
943        }
944        // Do all the larger tests
945        if (i > 0) {
946            for (Test test: commandTests)
947                suite.addTest(test);
948
949            for (Test test: runTests)
950                suite.addTest(test);
951        }
952        return suite;
953    }
954
955    /**
956     * @param props
957     * @param dir
958     * @param dirname
959     * @param testname
960     * @param expect_not_passing Test does not pass yet
961     * @param shouldFail Test passes, if it fails (e.g., is an error printed?)
962     * @param failsOnly
963     * @param commandTests
964     * @param runTests
965     * @throws IOException
966     */
967    private static void standardCompilerTests(StringMap props, String canonicalDirName,
968                                              String dirname, String testname,
969                                              boolean expect_not_passing,
970                                              boolean shouldFail,
971                                              boolean failsOnly,
972                                              List<Test> commandTests,
973                                              List<Test> runTests) throws IOException {
974        String[] commands = new String [] {"compile", "desugar", "link", "run", "api",
975                                           "parse", "disambiguate", "grammar", "typecheck",
976                                           "unparse", "compare", "build",
977                                           "fss", "fsi"};
978
979        if (props.get("compile") != null)
980            commandTests.add(new CommandTest("compile", props, canonicalDirName,
981                                             dirname, testname, failsOnly,
982                                             expect_not_passing, shouldFail));
983        if (props.get("desugar") != null)
984            commandTests.add(new CommandTest("desugar", props, canonicalDirName,
985                                             dirname, testname, failsOnly,
986                                             expect_not_passing, shouldFail));
987        if (props.get("link") != null)
988            commandTests.add(new CommandTest("link", props, canonicalDirName,
989                                             dirname, testname, failsOnly,
990                                             expect_not_passing, shouldFail));
991
992        if (props.get("api") != null)
993            runTests.add(new CommandTest("api", props, canonicalDirName,
994                                         dirname, testname, failsOnly,
995                                         expect_not_passing, shouldFail));
996
997        if (props.get("parse") != null)
998            runTests.add(new CommandTest("parse", props, canonicalDirName,
999                                         dirname, testname, failsOnly,
1000                                         expect_not_passing, shouldFail));
1001
1002        if (props.get("run") != null)
1003            runTests.add(new TestTest(props, canonicalDirName,
1004                                      dirname, testname, failsOnly,
1005                                      expect_not_passing, shouldFail));
1006
1007        boolean found = false;
1008        for ( String c : new ArrayList<String>(java.util.Arrays.asList(commands)) ) {
1009            if (props.get(c) != null) found = true;
1010        }
1011
1012        if (! found)
1013            System.out.println("Not supported " + dirname + "/" + testname);
1014    }
1015
1016    /**
1017     * @param dirname
1018     * @return
1019     * @throws FileNotFoundException
1020     */
1021    private static File directoryAsFile(String dirname)
1022            throws FileNotFoundException {
1023        File dir = new File(dirname);
1024        if (!dir.exists()) {
1025            System.err.println(dirname + " does not exist");
1026            throw new FileNotFoundException(dirname);
1027        }
1028        if (!dir.isDirectory()) {
1029            System.err.println(dirname + " exists but is not a directory");
1030            throw new IllegalArgumentException(dirname);
1031        }
1032        return dir;
1033    }
1034
1035    /**
1036     * @return
1037     */
1038    private static int testCount() {
1039        int testCount = Integer.MAX_VALUE;
1040        try {
1041            testCount = ProjectProperties.getInt("fortress.unittests.count",
1042                    Integer.MAX_VALUE);
1043        } catch (NumberFormatException ex) {
1044            System.err
1045                    .println("Failed to translate property fortress.unittests.count as an int, string = "
1046                            + ProjectProperties.get("fortress.unittests.count"));
1047            System.err.println("Expected a number in the form DIGITS (base 10) or DIGITS_BASE");
1048        }
1049
1050        /* Limited testing count, such as it is. */
1051        if (testCount != Integer.MAX_VALUE)
1052            System.err.println("Test count = " + testCount);
1053        return testCount;
1054    }
1055
1056    private static long default_seed = System.currentTimeMillis();
1057
1058    /**
1059     * @param files
1060     * @return
1061     */
1062    private static Iterable<String> shuffledFileList(File dir, boolean shuffle) {
1063        String[] files = dir.list();
1064
1065        long seed = default_seed;
1066        try {
1067            seed = ProjectProperties.getLong("fortress.unittests.seed",
1068                    default_seed);
1069        } catch (NumberFormatException ex) {
1070            System.err
1071                    .println("Failed to translate property fortress.unittests.seed as a long, string = "
1072                            + ProjectProperties.get("fortress.unittests.seed"));
1073            System.err.println("Expected a number in the form DIGITS (base 10) or DIGITS_BASE");
1074        }
1075        Random random = new java.util.Random(seed);
1076
1077        Iterable<String> shuffled = shuffle ? IterUtil.shuffle(Arrays.asList(files),
1078                random) : Arrays.asList(files);
1079
1080        System.err.println("Test shuffling seed env var = FORTRESS_UNITTESTS_SEED="
1081                + Long.toHexString(seed) + "_16");
1082        return shuffled;
1083    }
1084}
Note: See TracBrowser for help on using the browser.