/*
 * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/* @test
 * @bug 5006520
 * @summary Check many different ways to run Windows programs
 * @author Martin Buchholz
 */

import java.io.*;
import java.util.*;
import static java.lang.System.*;

class StreamDrainer extends Thread {
    private final InputStream is;
    private final ByteArrayOutputStream os = new ByteArrayOutputStream();
    public StreamDrainer(InputStream is) { this.is = is; }
    public void run() {
        try {
            int i;
            while ((i = is.read()) >= 0)
                os.write(i);
        } catch (Exception e) {}
    }
    public String toString() { return os.toString(); }
}

class CommandRunner {
    private static Random generator = new Random();
    public final int exitValue;
    public final String out;
    public final String err;
    CommandRunner(String... args) throws Exception {
        Process p = (generator.nextInt(2) == 0)
            ? new ProcessBuilder(args).start()
            : Runtime.getRuntime().exec(args);
        StreamDrainer d1 = new StreamDrainer(p.getInputStream());
        StreamDrainer d2 = new StreamDrainer(p.getErrorStream());
        d1.start();
        d2.start();
        p.waitFor();
        d1.join();
        d2.join();
        this.exitValue = p.exitValue();
        this.out = d1.toString();
        this.err = d2.toString();
    }
}

public class WinCommand {
    private static int failed = 0;

    private static void fail(String msg) {
        err.printf("FAIL: %s%n", msg);
        failed++;
    }

    private static String outputOf(String... args) {
        try {
            CommandRunner cr = new CommandRunner(args);
            if (cr.exitValue != 0)
                fail("exitValue != 0");
            if (! cr.err.equals(""))
                fail("stderr: " + cr.err);
            return cr.out.replaceFirst("[\r\n]+$", "");
        } catch (Exception e) {
            fail(e.toString());
            return "";
        }
    }

    private static void checkCD(String... filespecs) {
        String firstCD = null;
        for (String filespec : filespecs) {
            String CD = outputOf(filespec, "/C", "CD");
            out.printf("%s CD ==> %s%n", filespec, CD);
            if (firstCD == null) {
                firstCD = CD;
                checkDir(CD);
            }
            if (! CD.equals(firstCD)) {
                fail("Inconsistent result from CD subcommand");
                checkDir(CD);
            }
        }
    }

    private static void checkDir(String dirname) {
        if (! new File(dirname).isDirectory())
            fail(String.format("Not a directory: %s%n", dirname));
    }

    private static void writeFile(String filename, String contents) {
        try {
            FileOutputStream fos = new FileOutputStream(filename);
            fos.write(contents.getBytes());
            fos.close();
        } catch (Exception e) {
            fail("Unexpected exception" + e.toString());
        }
    }

    public static void main(String[] args) throws Exception {
        File systemRoot =
            getenv("SystemRoot") != null ? new File(getenv("SystemRoot")) :
            getenv("WINDIR")     != null ? new File(getenv ("WINDIR")) :
            null;
        if (systemRoot == null || ! systemRoot.isDirectory())
            return; // Not Windows as we know it

        String systemDirW = new File(systemRoot, "System32").getPath();
        String systemDirM = systemDirW.replace('\\', '/');
        out.printf("systemDirW=%s%n", systemDirW);
        out.printf("systemDirM=%s%n", systemDirM);

        // Win9x systems don't have a cmd.exe
        if (new File(systemDirW, "cmd.exe").exists()) {
            out.println("Running cmd.exe tests...");
            writeFile("cdcmd.cmd", "@echo off\r\nCD\r\n");
            writeFile("cdbat.bat", "@echo off\r\nCD\r\n");
            checkCD("cmd",
                    "cmd.exe",
                    systemDirW + "\\cmd.exe",
                    // Only the ".exe" extension can be omitted
                    systemDirW + "\\cmd",
                    systemDirM + "/cmd.exe",
                    systemDirM + "/cmd",
                    "/" + systemDirM + "/cmd",
                    "cdcmd.cmd", "./cdcmd.cmd", ".\\cdcmd.cmd",
                    "cdbat.bat", "./cdbat.bat", ".\\cdbat.bat");
        }

        // 16-bit apps like command.com must have a console;
        // fix this someday...

//      // Win64 systems don't have a command.com
//      if (new File(systemDirW, "command.com").exists()
//          // no output if running without a console;
//          // fix this in Mustang
//          && ! outputOf("command.com", "/C", "CD").equals("")) {
//          out.println("Running command.com tests...");
//          checkCD("command.com",
//                  systemDirM + "/command.com",
//                  systemDirW + "\\command.com");
//      }

        // Win9x systems have a %SYSTEMDRIVE%\command.com
//      if (new File("C:\\COMMAND.COM").exists()
//          && ! outputOf("COMMAND.COM", "/C", "CD").equals("")) {
//          out.println("Running COMMAND.COM tests...");
//          checkCD("C:/command.com",
//                  "C:\\command.com");
//      }

        if (failed > 0)
            throw new Exception(failed + " tests failed");
    }
}
