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

Revision 3886, 43.6 KB (checked in by dr2chase, 5 months ago)

Added doc for 'fortress junit', added ability to specify time limits in 'whatever.timing' file

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 CompileTest extends SourceFileTest {
665
666        private final StringMap props;
667//        public CompileTest(StringMap props, String path, String d, String s,
668//                boolean unexpected_only, boolean knownFailure) {
669//            super(path, d, s, unexpected_only, knownFailure, s.startsWith("XXX") );
670//            this.props = props;
671//        }
672        public CompileTest(StringMap props, String path, String d, String s,
673                           boolean unexpected_only, boolean knownFailure, boolean shouldFail) {
674            super(path, d, s, unexpected_only, knownFailure, shouldFail );
675            this.props = props;
676        }
677
678        @Override
679        protected int justTheTest()
680                throws FileNotFoundException, IOException, Throwable {
681            String[] tokens = new String [] {"compile", join(dir, makeTestFileName(name))};
682            int rc = com.sun.fortress.Shell.subMain(tokens);
683            return rc;
684
685        }
686
687        @Override
688        public String tag() {
689            // TODO Auto-generated method stub
690            return "compile";
691        }
692
693        public  String testFailed(String out, String err, String exc) {
694            return generalTestFailed("compile_", props, out, err, exc);
695        }
696
697    }
698
699    public static class DesugarTest extends SourceFileTest {
700
701        private final StringMap props;
702        public DesugarTest(StringMap props, String path, String d, String s,
703                           boolean unexpected_only, boolean knownFailure, boolean shouldFail) {
704            super(path, d, s, unexpected_only, knownFailure, shouldFail );
705            this.props = props;
706
707        }
708
709        @Override
710        protected int justTheTest()
711            throws FileNotFoundException, IOException, Throwable {
712            // might need to strip the .fss off f "f".
713            String[] tokens = new String [] {"desugar", join(dir, makeTestFileName(name))};
714            int rc = com.sun.fortress.Shell.subMain(tokens);
715            return rc;
716        }
717
718        @Override
719        public String tag() {
720            // TODO Auto-generated method stub
721            return "desugar";
722        }
723
724        public  String testFailed(String out, String err, String exc) {
725            return generalTestFailed("desugar_", props, out, err, exc);
726        }
727
728    }
729
730    public static class LinkTest extends SourceFileTest {
731
732        private final StringMap props;
733       public LinkTest(StringMap props, String path, String d, String s,
734                boolean unexpected_only, boolean knownFailure, boolean shouldFail) {
735            super(path, d, s, unexpected_only, knownFailure, shouldFail );
736            this.props = props;
737
738        }
739
740        @Override
741        protected int justTheTest()
742                throws FileNotFoundException, IOException, Throwable {
743            // might need to strip the .fss off f "f".
744            String[] tokens = new String [] {"link", join(dir, makeTestFileName(name))};
745            int rc = com.sun.fortress.Shell.subMain(tokens);
746            return rc;
747        }
748
749        @Override
750        public String tag() {
751            // TODO Auto-generated method stub
752            return "link";
753        }
754
755        public  String testFailed(String out, String err, String exc) {
756            return generalTestFailed("link_", props, out, err, exc);
757
758        }
759
760    }
761
762    public static class InterpreterTest extends SourceFileTest {
763
764        public InterpreterTest(String path, String d, String s, boolean unexpected_only, boolean knownFailure) {
765            super(path, d, s, unexpected_only, knownFailure, s.startsWith("XXX"));
766        }
767
768
769        /**
770         * @param repository
771         * @param apiname
772         * @throws FileNotFoundException
773         * @throws IOException
774         * @throws Throwable
775         */
776        protected int justTheTest()
777                throws FileNotFoundException, IOException, Throwable {
778            String s = f.replaceFirst(".*/", "");
779            APIName apiname = NodeFactory.makeAPIName(NodeFactory.testSpan, s);
780            GraphRepository repository = Shell.specificInterpreterRepository( ProjectProperties.SOURCE_PATH.prepend(path) );
781
782            ComponentIndex ci = repository.getLinkedComponent(apiname);
783
784            //Option<CompilationUnit> _p = ASTIO.parseToJavaAst(fssFile, in, false);
785
786            {
787                Component p = (Component) ci.ast();
788
789                // oldOut.print(" RUNNING"); oldOut.flush();
790                if (!unexpectedOnly) System.out.println();
791                // A demo file requiring arguments
792                if (name.equals("tennisRanking")) {
793                    ArrayList<String> args = new ArrayList<String>();
794                    args.add(dir + "/tennis050307");
795                    args.add(dir + "/tennis051707");
796                    args.add(dir + "/tennisGames");
797                    Driver.runProgram(repository, ci, args);
798                }
799                // Test files requiring "test" command
800                else if (name.equals("XXXTestTest") ||
801                         name.equals("natInference0") ||
802                         name.equals("testTest1") ||
803                         name.equals("testTest2")) {
804                    Driver.runTests(repository, ci, false);
805                }
806                else {
807                    Driver.runProgram(repository, ci, new ArrayList<String>());
808                }
809            }
810            return 0;
811        }
812
813
814        @Override
815        public String tag() {
816            // TODO Auto-generated method stub
817            return "interpret";
818        }
819
820    }
821    public static void main(String[] args) throws IOException {
822        junit.textui.TestRunner.run(FileTests.interpreterSuite("shelltests", true, false));
823        junit.textui.TestRunner.run(FileTests.interpreterSuite("tests", true, false));
824        junit.textui.TestRunner.run(FileTests.interpreterSuite("not_passing_yet", false, true));
825    }
826
827    public static TestSuite interpreterSuite(
828            String dir_name,
829            boolean failsOnly,
830            boolean expect_failure) throws IOException {
831
832        TestSuite suite = new TestSuite("Runs all tests in " + dir_name) {
833            public void run(TestResult result) {
834                super.run(result);
835                Init.allowForLeakChecks();
836            }
837        };
838
839        String dirname = ProjectProperties.backslashToSlash(dir_name);
840        File dir = directoryAsFile(dirname);
841        System.err.println(dir);
842
843        /* Many lines of random number generator seed nonsense. */
844
845        Iterable<String> shuffled = shuffledFileList(dir, true);
846
847        int testCount = testCount();
848        int i = testCount;
849
850        for(String s : shuffled){
851              if (i <= 0) {
852                  System.out.println("Early testing exit after " + testCount + " tests");
853                  break;
854              }
855              boolean decrement = true;
856              if (s.endsWith("Syntax.fss") || s.endsWith("DynamicSemantics.fss")) {
857                  System.out.println("Not compiling file " + s);
858                  decrement = false;
859              } else if (!s.startsWith(".")) {
860                  if (s.endsWith(".fss")) {
861                      int l = s.lastIndexOf(".fss");
862                      String testname = s.substring(0, l);
863                      suite.addTest(new InterpreterTest(dir.getCanonicalPath(), dirname, testname, failsOnly, expect_failure));
864                  } else if (s.endsWith(".sh")) {
865                      int l = s.lastIndexOf(".sh");
866                      String testname = s.substring(0, l);
867                      suite.addTest(new ShellTest(dir.getCanonicalPath(), dirname, testname, failsOnly, expect_failure));
868                  } else {
869                      System.out.println("Not compiling file " + s);
870                      decrement = false;
871                  }
872              }
873
874              if (decrement) {
875                  i--;
876              }
877
878        }
879        return suite;
880    }
881
882    /**
883     * Generates a suite of tests from directory dir_name, using "foo.test" files
884     * to determine the content of the test.  failsOnly means to only print failing
885     * tests (either normal tests that fail, or XXX tests that succeed).
886     *
887     * WARNING: expect_failure  is not treated consistently.
888     *
889     * It either means, "the test fails, and that is a good thing",
890     * or it means, "the test fails, it is a bad thing, but we are working on it
891     * and do not want to be bothered by something we already know is a problem".
892     *
893     * @param dir_name_from_user
894     * @param failsOnly
895     * @param expect_failure
896     * @return
897     * @throws IOException
898     */
899    public static TestSuite compilerSuite(String dir_name_from_user,
900                                          boolean shuffle,
901                                          boolean failsOnly,
902                                          boolean expect_failure) throws IOException {
903
904        String dir_name_slashes_normalized = ProjectProperties.backslashToSlash(dir_name_from_user);
905        File dir = directoryAsFile(dir_name_slashes_normalized);
906        System.err.println(dir);
907        String dir_name_canonical = dir.getCanonicalPath();
908
909        /* Many lines of random number generator seed nonsense. */
910
911        Iterable<String> shuffled = shuffledFileList(dir, shuffle);
912
913        return suiteFromListOfFiles(shuffled, dir_name_from_user,
914                dir_name_slashes_normalized, dir_name_canonical, failsOnly,
915                expect_failure);
916    }
917
918    /**
919     * @param shuffled
920     * @param dir_name_from_user
921     * @param dir_name_slashes_normalized
922     * @param dir_name_canonical
923     * @param failsOnly
924     * @param expect_failure
925     * @return
926     * @throws IOException
927     */
928    public static TestSuite suiteFromListOfFiles(Iterable<String> shuffled,
929            String dir_name_from_user, String dir_name_slashes_normalized,
930            String dir_name_canonical, boolean failsOnly, boolean expect_failure)
931            throws IOException {
932        int testCount = testCount();
933        int i = testCount;
934
935        TestSuite suite = new TestSuite("Runs all tests in " + dir_name_from_user) {
936            public void run(TestResult result) {
937                super.run(result);
938                Init.allowForLeakChecks();
939            }
940        };
941
942        List<Test> compileTests = new ArrayList<Test>();
943        List<Test> desugarTests = new ArrayList<Test>();
944        List<Test> linkTests = new ArrayList<Test>();
945        List<Test> runTests = new ArrayList<Test>();
946
947        for(String s : shuffled){
948              int slashi = s.lastIndexOf('/');
949              if (slashi != -1) {
950                  String candidatedir = s.substring(0,slashi);
951                  s = s.substring(slashi+1);
952                  dir_name_from_user = candidatedir;
953                  dir_name_slashes_normalized = candidatedir;
954                  dir_name_canonical =
955                      directoryAsFile(dir_name_slashes_normalized).getCanonicalPath();
956              }
957           
958           
959              if (i <= 0) {
960                  System.out.println("Early testing exit after " + testCount + " tests");
961                  break;
962              }
963              boolean decrement = true;
964              boolean shouldFail = s.startsWith("XXX");
965
966              if (s.endsWith(".fss") || s.endsWith(".fsi") ) {
967                  // do nothing
968                  decrement = false;
969              } else if (!s.startsWith(".")) {
970                  if (s.endsWith(".sh")) {
971                      int l = s.lastIndexOf(".sh");
972                      String testname = s.substring(0, l);
973                      suite.addTest(new ShellTest(dir_name_canonical, dir_name_slashes_normalized, testname, failsOnly, expect_failure));
974                  } else if (s.endsWith(".test")) { // need to define the test of tests.
975
976                      StringMap props = new StringMap.FromFileProps(join(dir_name_canonical, s));
977                      props = ProjectProperties.composedWith(props);
978
979                      int l = s.lastIndexOf(".test");
980                      String testname = s.substring(0, l);
981
982                      String testNames = props.get("tests");
983                      if (testNames == null)
984                          testNames = "";
985                      else
986                          testNames = testNames.trim();
987
988                      if (testNames.length() > 0) {
989                          StringTokenizer st = new StringTokenizer(testNames);
990                          while  (st.hasMoreTokens()) {
991                              String token = st.nextToken();
992                                  standardCompilerTests(props, dir_name_canonical, dir_name_slashes_normalized, token,
993                                                        expect_failure, shouldFail, failsOnly,
994                                                        compileTests, desugarTests,
995                                                        linkTests, runTests);
996                          }
997                      }
998                      else {
999                              standardCompilerTests(props, dir_name_canonical, dir_name_slashes_normalized, testname,
1000                                                    expect_failure, shouldFail, failsOnly,
1001                                                    compileTests, desugarTests,
1002                                                    linkTests, runTests);
1003                      }
1004                  } else {
1005                      System.out.println("Not compiling file " + s);
1006                      decrement = false;
1007                  }
1008              }
1009
1010              if (decrement) {
1011                  i--;
1012              }
1013
1014        }
1015        // Do all the larger tests
1016        if (i > 0) {
1017            for (Test test: compileTests)
1018                suite.addTest(test);
1019
1020            for (Test test: desugarTests)
1021                suite.addTest(test);
1022
1023            for (Test test: linkTests)
1024                suite.addTest(test);
1025
1026            for (Test test: runTests)
1027                suite.addTest(test);
1028        }
1029        return suite;
1030    }
1031
1032    /**
1033     * @param props
1034     * @param dir
1035     * @param dirname
1036     * @param testname
1037     * @param expect_not_passing Test does not pass yet
1038     * @param shouldFail Test passes, if it fails (e.g., is an error printed?)
1039     * @param failsOnly
1040     * @param compileTests
1041     * @param desugarTests
1042     * @param linkTests
1043     * @param runTests
1044     * @throws IOException
1045     */
1046    private static void standardCompilerTests(StringMap props, String canonicalDirName,
1047                                              String dirname, String testname,
1048                                              boolean expect_not_passing,
1049                                              boolean shouldFail,
1050                                              boolean failsOnly,
1051                                              List<Test> compileTests,
1052                                              List<Test> desugarTests,
1053                                              List<Test> linkTests,
1054                                              List<Test> runTests) throws IOException {
1055        if (props.get("compile") != null)
1056            compileTests.add(new CompileTest(props, canonicalDirName,
1057                                             dirname, testname, failsOnly,
1058                                             expect_not_passing, shouldFail));
1059        if (props.get("desugar") != null)
1060            desugarTests.add(new DesugarTest(props, canonicalDirName,
1061                                             dirname, testname, failsOnly,
1062                                             expect_not_passing, shouldFail));
1063        if (props.get("link") != null)
1064            linkTests.add(new LinkTest(props, canonicalDirName,
1065                                       dirname, testname, failsOnly,
1066                                       expect_not_passing, shouldFail));
1067        if (props.get("run") != null)
1068            runTests.add(new TestTest(props, canonicalDirName,
1069                                      dirname, testname, failsOnly,
1070                                      expect_not_passing, shouldFail));
1071    }
1072
1073    /**
1074     * @param dirname
1075     * @return
1076     * @throws FileNotFoundException
1077     */
1078    private static File directoryAsFile(String dirname)
1079            throws FileNotFoundException {
1080        File dir = new File(dirname);
1081        if (!dir.exists()) {
1082            System.err.println(dirname + " does not exist");
1083            throw new FileNotFoundException(dirname);
1084        }
1085        if (!dir.isDirectory()) {
1086            System.err.println(dirname + " exists but is not a directory");
1087            throw new IllegalArgumentException(dirname);
1088        }
1089        return dir;
1090    }
1091
1092    /**
1093     * @return
1094     */
1095    private static int testCount() {
1096        int testCount = Integer.MAX_VALUE;
1097        try {
1098            testCount = ProjectProperties.getInt("fortress.unittests.count",
1099                    Integer.MAX_VALUE);
1100        } catch (NumberFormatException ex) {
1101            System.err
1102                    .println("Failed to translate property fortress.unittests.count as an int, string = "
1103                            + ProjectProperties.get("fortress.unittests.count"));
1104            System.err.println("Expected a number in the form DIGITS (base 10) or DIGITS_BASE");
1105        }
1106
1107        /* Limited testing count, such as it is. */
1108        if (testCount != Integer.MAX_VALUE)
1109            System.err.println("Test count = " + testCount);
1110        return testCount;
1111    }
1112
1113    private static long default_seed = System.currentTimeMillis();
1114
1115    /**
1116     * @param files
1117     * @return
1118     */
1119    private static Iterable<String> shuffledFileList(File dir, boolean shuffle) {
1120        String[] files = dir.list();
1121
1122        long seed = default_seed;
1123        try {
1124            seed = ProjectProperties.getLong("fortress.unittests.seed",
1125                    default_seed);
1126        } catch (NumberFormatException ex) {
1127            System.err
1128                    .println("Failed to translate property fortress.unittests.seed as a long, string = "
1129                            + ProjectProperties.get("fortress.unittests.seed"));
1130            System.err.println("Expected a number in the form DIGITS (base 10) or DIGITS_BASE");
1131        }
1132        Random random = new java.util.Random(seed);
1133
1134        Iterable<String> shuffled = shuffle ? IterUtil.shuffle(Arrays.asList(files),
1135                random) : Arrays.asList(files);
1136
1137        System.err.println("Test shuffling seed env var = FORTRESS_UNITTESTS_SEED="
1138                + Long.toHexString(seed) + "_16");
1139        return shuffled;
1140    }
1141}
Note: See TracBrowser for help on using the browser.