import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

import com.redhat.ceylon.compiler.js.JsCompiler;
import com.redhat.ceylon.compiler.js.JsModuleCompiler;
import com.redhat.ceylon.compiler.typechecker.TypeChecker;
import com.redhat.ceylon.compiler.typechecker.TypeCheckerBuilder;
import com.redhat.ceylon.compiler.typechecker.context.PhasedUnit;
import com.redhat.ceylon.compiler.typechecker.model.Package;

/**
 * Some hack before a proper unit test harness is put in place
 *
 * @author Emmanuel Bernard <emmanuel@hibernate.org>
 */
public class MainForJsTest {
    
    private static final class JsTestCompiler extends JsModuleCompiler {

        private JsTestCompiler(TypeChecker tc) {
            super(tc);
        }

        @Override
        protected Writer getModuleWriter(PhasedUnit pu) throws IOException {
            Package pkg = pu.getPackage();
            File file = new File("build/test/node_modules", toOutputPath(pkg));
            file.getParentFile().mkdirs();
            if (file.exists()) file.delete();
            file.createNewFile();
            return new FileWriter(file);
        }

    }

    static boolean opt = false;

    public static void main(String[] args) throws Exception {
        for (String arg: args) { 
            if (arg.equals("optimize")) {
                System.out.println("performance optimized code");
                opt=true; 
            }
        }

        TypeChecker typeChecker = new TypeCheckerBuilder()
                .verbose(false)
                .addSrcDirectory(new File("src/test/ceylon"))
                .addSrcDirectory(new File("../ceylon.language/test"))
                .getTypeChecker();
        typeChecker.process();
        if (typeChecker.getErrors() > 0) {
            System.exit(1);
        }
        JsCompiler jsc = new JsTestCompiler(typeChecker).optimize(opt).stopOnErrors(false);
        if (jsc.generate()) {
            validateOutput(typeChecker);
        } else {
            jsc.printErrors(System.out);
            System.out.println("Skipping output validation.");
        }
    }

    static void validateOutput(TypeChecker typeChecker)
            throws FileNotFoundException, IOException {
        int count=0;
        for (PhasedUnit pu: typeChecker.getPhasedUnits().getPhasedUnits()) {
            Package pkg = pu.getPackage();
            File generated = new File("build/test/node_modules/" + toOutputPath(pkg));
            File test = new File("src/test/ceylon/"+ toTestPath(pkg));
            if (test.exists()) {
                BufferedReader reader = new BufferedReader(new FileReader(test));
                BufferedReader outputReader = new BufferedReader(new FileReader(generated));
                int i=0;
                while (reader.ready() && outputReader.ready()) {
                    i++;
                    String actual = outputReader.readLine();
                    String expected = reader.readLine();
                    if (!expected.equals(actual) && !expected.trim().startsWith("//")) {
                        System.err.println("error at " + test.getPath() + ":" + i); 
                        System.err.println("expected: " + expected);
                        System.err.println("  actual: " + actual);
                        break;
                    }
                }
                count++;
            }
        }
        System.out.println("ran " + count + " tests");
    }
    
    private static String toOutputPath(Package pkg) {
        String pkgName = pkg.getNameAsString();
        if (pkgName.isEmpty()) pkgName = "default";
        String modName = pkg.getModule().getNameAsString();
        return modName.replace('.', '/') +
                (pkg.getModule().isDefault() ? 
                        "/" : "/" + pkg.getModule().getVersion() ) +
                pkgName + ".js";
    }

    private static String toTestPath(Package pkg) {
        String pkgName = pkg.getNameAsString();
        if (pkgName.isEmpty()) pkgName = "default";
        return pkgName.replace('.', '/') + "/" + pkgName + (opt? ".jsopt" : "") + ".js";
    }
}

@@ -75,32 +75,65 @@
 FoundException;%0A
+import java.io.FileOutputStream;%0A
 import java.io.F
@@ -190,32 +190,67 @@
 io.IOException;%0A
+import java.io.OutputStreamWriter;%0A
 import java.io.W
@@ -1300,23 +1300,62 @@
 new 
-FileWriter(file
+OutputStreamWriter(new FileOutputStream(file), %22UTF-8%22
 );%0A 
@@ -3641,36 +3641,33 @@
 rint
-ln
+f
 (%22ran 
-%22 + count + %22 tests%22
+%25d tests%25n%22, count
 );%0A 

Write output files using UTF-8