<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NUnit.Framework;
using System.Threading;
using GitHub.Unity;
using System.Threading.Tasks.Schedulers;
using System.IO;
using NSubstitute;

namespace IntegrationTests
{
    class BaseTest
    {
        public BaseTest()
        {
            Logger = Logging.GetLogger(GetType());
        }

        protected ILogging Logger { get; }

        protected ITaskManager TaskManager { get; set; }
        protected IProcessManager ProcessManager { get; set; }
        protected NPath TestBasePath { get; private set; }
        protected CancellationToken Token => TaskManager.Token;
        protected NPath TestApp => System.Reflection.Assembly.GetExecutingAssembly().Location.ToNPath().Combine("TestApp.exe");

        [TestFixtureSetUp]
        public void OneTimeSetup()
        {
            GitHub.Unity.Guard.InUnitTestRunner = true;
            Logging.LogAdapter = new MultipleLogAdapter(new FileLogAdapter($"..\\{DateTime.UtcNow.ToString("yyyyMMddHHmmss")}-tasksystem-tests.log"));
            //Logging.TracingEnabled = true;
            TaskManager = new TaskManager();
            var syncContext = new ThreadSynchronizationContext(Token);
            TaskManager.UIScheduler = new SynchronizationContextTaskScheduler(syncContext);

            var env = new DefaultEnvironment();
            TestBasePath = NPath.CreateTempDirectory("integration-tests");
            env.FileSystem.SetCurrentDirectory(TestBasePath);

            var repo = Substitute.For<IRepository>();
            repo.LocalPath.Returns(TestBasePath);
            env.Repository = repo;

            var platform = new Platform(env);
            ProcessManager = new ProcessManager(env, platform.GitEnvironment, Token);
            var processEnv = platform.GitEnvironment;
            var path = new ProcessTask<NPath>(TaskManager.Token, new FirstLineIsPathOutputProcessor())
                .Configure(ProcessManager, env.IsWindows ? "where" : "which", "git")
                .Start().Result;
            env.GitExecutablePath = path ?? "git".ToNPath();
        }

        [TestFixtureTearDown]
        public void OneTimeTearDown()
        {
            TaskManager?.Dispose();
            try
            {
                TestBasePath.DeleteIfExists();
            }
            catch { }
        }

        [SetUp]
        public void Setup()
        {
        }

        [TearDown]
        public void Teardown()
        {
        }
    }

    [TestFixture]
    class ProcessTaskTests : BaseTest
    {
        [Test]
        public async Task ProcessReadsFromStandardInput()
        {
            var input = new List<string> {
                "Hello",
                "World\u001A"
            };

            var expectedOutput = "Hello";

            var procTask = new FirstNonNullLineProcessTask(Token, TestApp, @"-s 100 -i")
                .Configure(ProcessManager, true);

            procTask.OnStartProcess += proc =>
            {
                foreach (var item in input)
                {
                    proc.StandardInput.WriteLine(item);
                }
                proc.StandardInput.Close();
            };

            var chain = procTask
                .Finally((s, e, d) => d);

            var output = await chain.StartAsAsync();

            Assert.AreEqual(expectedOutput, output);
        }

        [Test]
        public async Task ProcessReturningErrorThrowsException()
        {
            var success = false;
            Exception thrown = null;
            var output = new List<string>();
            var expectedOutput = new List<string> { "one name" };

            var task = new FirstNonNullLineProcessTask(Token, TestApp, @"-s 100 -d ""one name""").Configure(ProcessManager)
                .Catch(ex => thrown = ex)
                .Then((s, d) => output.Add(d))
                .Then(new FirstNonNullLineProcessTask(Token, TestApp, @"-e kaboom -r -1").Configure(ProcessManager))
                .Catch(ex => thrown = ex)<commit_msg>Adding a task integration test that demonstrates the execution order of OnStart and OnEnd<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NUnit.Framework;
using System.Threading;
using GitHub.Unity;
using System.Threading.Tasks.Schedulers;
using System.IO;
using NSubstitute;

namespace IntegrationTests
{
    class BaseTest
    {
        public BaseTest()
        {
            Logger = Logging.GetLogger(GetType());
        }

        protected ILogging Logger { get; }

        protected ITaskManager TaskManager { get; set; }
        protected IProcessManager ProcessManager { get; set; }
        protected NPath TestBasePath { get; private set; }
        protected CancellationToken Token => TaskManager.Token;
        protected NPath TestApp => System.Reflection.Assembly.GetExecutingAssembly().Location.ToNPath().Combine("TestApp.exe");

        [TestFixtureSetUp]
        public void OneTimeSetup()
        {
            GitHub.Unity.Guard.InUnitTestRunner = true;
            Logging.LogAdapter = new MultipleLogAdapter(new FileLogAdapter($"..\\{DateTime.UtcNow.ToString("yyyyMMddHHmmss")}-tasksystem-tests.log"));
            //Logging.TracingEnabled = true;
            TaskManager = new TaskManager();
            var syncContext = new ThreadSynchronizationContext(Token);
            TaskManager.UIScheduler = new SynchronizationContextTaskScheduler(syncContext);

            var env = new DefaultEnvironment();
            TestBasePath = NPath.CreateTempDirectory("integration-tests");
            env.FileSystem.SetCurrentDirectory(TestBasePath);

            var repo = Substitute.For<IRepository>();
            repo.LocalPath.Returns(TestBasePath);
            env.Repository = repo;

            var platform = new Platform(env);
            ProcessManager = new ProcessManager(env, platform.GitEnvironment, Token);
            var processEnv = platform.GitEnvironment;
            var path = new ProcessTask<NPath>(TaskManager.Token, new FirstLineIsPathOutputProcessor())
                .Configure(ProcessManager, env.IsWindows ? "where" : "which", "git")
                .Start().Result;
            env.GitExecutablePath = path ?? "git".ToNPath();
        }

        [TestFixtureTearDown]
        public void OneTimeTearDown()
        {
            TaskManager?.Dispose();
            try
            {
                TestBasePath.DeleteIfExists();
            }
            catch { }
        }

        [SetUp]
        public void Setup()
        {
        }

        [TearDown]
        public void Teardown()
        {
        }
    }

    [TestFixture]
    class ProcessTaskTests : BaseTest
    {
        [Test]
        public async Task ProcessReadsFromStandardInput()
        {
            var input = new List<string> {
                "Hello",
                "World\u001A"
            };

            var expectedOutput = "Hello";

            var procTask = new FirstNonNullLineProcessTask(Token, TestApp, @"-s 100 -i")
                .Configure(ProcessManager, true);

            procTask.OnStartProcess += proc =>
            {
                foreach (var item in input)
                {
                    proc.StandardInput.WriteLine(item);
                }
                proc.StandardInput.Close();
            };

            var chain = procTask
                .Finally((s, e, d) => d);

            var output = await chain.StartAsAsync();

            Assert.AreEqual(expectedOutput, output);
        }

        [Test]
        public async Task ProcessOnStartOnEndTaskOrder()
        {
            var values = new List<string>();
            string process1Value = null;
            string process2Value = null;

            var process1Task = new FirstNonNullLineProcessTask(Token, TestApp, @"-s 100 -d process1")
                .Configure(ProcessManager, true).Then((b, s) => {
                    process1Value = s;
                    values.Add(s);
                });

            var process2Task = new FirstNonNullLineProcessTask(Token, TestApp, @"-s 100 -d process2")
                .Configure(ProcessManager, true).Then((b, s) => {
                    process2Value = s;
                    values.Add(s);
                });

            var combinedTask = process1Task
                .Then(process2Task);

            combinedTask.OnStart += task => {
                values.Add("OnStart");
            };

            combinedTask.OnEnd += task => {
                values.Add("OnEnd");
            };

            await combinedTask
                .StartAsAsync();

            Assert.AreEqual(process1Value, "process1");
            Assert.AreEqual(process2Value, "process2");
            Assert.True(values.SequenceEqual(new []{ "process1", "OnStart", "process2", "OnEnd" }));
        }

        [Test]
        public async Task ProcessReturningErrorThrowsException()
        {
            var success = false;
            Exception thrown = null;
            var output = new List<string>();
            var expectedOutput = new List<string> { "one name" };

            var task = new FirstNonNullLineProcessTask(Token, TestApp, @"-s 100 -d ""one name""").Configure(ProcessManager)
                .Catch(ex => thrown = ex)
                .Then((s, d) => output.Add(d))
                .Then(new FirstNonNullLineProcessTask(Token, TestApp, @"-e kaboom -r -1").Configure(ProcessManager))
                .Catch(ex => thrown = ex)
{'fraction_non_alphanumeric': 0.10130684788290643, 'fraction_numerical': 0.004391008886565604, 'mean_word_length': 1.8563750373245744, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 32, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3739825', 'n_tokens_mistral': 2541, 'n_tokens_neox': 2416, 'n_words': 541}