package com.ruoyi.generator.service.front;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

public class RunPreviewProcessKillerTest
{
    @Rule
    public TemporaryFolder temporaryFolder = new TemporaryFolder();

    @Test
    public void stopRequestsWholeTreeTerminationForManagedProcess() throws Exception
    {
        File pidFile = temporaryFolder.newFile("preview.pid");
        Files.write(pidFile.toPath(), "4321".getBytes(StandardCharsets.UTF_8));
        FakeProcess delegate = new FakeProcess();
        ManagedPreviewProcess process = new ManagedPreviewProcess(delegate, pidFile);
        RecordingProcessKiller killer = new RecordingProcessKiller();

        killer.stop(process, null);

        assertEquals(Long.valueOf(4321L), killer.killedPid);
        assertTrue(delegate.destroyed);
        assertFalse(pidFile.exists());
    }

    @Test
    public void stopFallsBackWhenManagedProcessHasNoPid()
    {
        File missingPidFile = new File(temporaryFolder.getRoot(), "missing.pid");
        FakeProcess delegate = new FakeProcess();
        ManagedPreviewProcess process = new ManagedPreviewProcess(delegate, missingPidFile);
        RecordingProcessKiller killer = new RecordingProcessKiller();

        killer.stop(process, null);

        assertNull(killer.killedPid);
        assertTrue(delegate.destroyed);
    }

    private static class RecordingProcessKiller extends RunPreviewProcessKiller
    {
        private Long killedPid;

        @Override
        protected boolean killWindowsProcessTree(long pid)
        {
            killedPid = Long.valueOf(pid);
            return true;
        }
    }

    private static class FakeProcess extends Process
    {
        private boolean alive = true;
        private boolean destroyed;

        @Override
        public OutputStream getOutputStream()
        {
            return new ByteArrayOutputStream();
        }

        @Override
        public InputStream getInputStream()
        {
            return new ByteArrayInputStream(new byte[0]);
        }

        @Override
        public InputStream getErrorStream()
        {
            return new ByteArrayInputStream(new byte[0]);
        }

        @Override
        public int waitFor()
        {
            alive = false;
            return 0;
        }

        @Override
        public int exitValue()
        {
            if (alive)
            {
                throw new IllegalThreadStateException();
            }
            return 0;
        }

        @Override
        public void destroy()
        {
            alive = false;
            destroyed = true;
        }

        @Override
        public boolean isAlive()
        {
            return alive;
        }
    }
}
