<commit_before>﻿// Python Tools for Visual Studio
// Copyright(c) Microsoft Corporation
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the License); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED ON AN  *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
// MERCHANTABLITY OR NON-INFRINGEMENT.
//
// See the Apache Version 2.0 License for specific language governing
// permissions and limitations under the License.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;

namespace TestRunnerInterop {
    public sealed class VsTestContext : IDisposable {
        private readonly string _container, _className, _testDataRoot;
        private VsInstance _vs;

        private Dictionary<string, DateTime> _testDataFiles;

        public VsTestContext(
            string container,
            string className,
            string testDataRoot
        ) {
            _container = container;
            _className = className;
            _testDataRoot = testDataRoot ?? GetDefaultTestDataDirectory();
        }

        public void RunTest(string testName, params object[] arguments) {
            if (_vs == null) {
                throw new InvalidOperationException("TestInitialize was not called");
            }
            _vs.RunTest(_container, $"{_className}.{testName}", arguments);
        }

        public void Dispose() {
            if (_vs != null) {
                _vs.Dispose();
                _vs = null;
            }
        }

        public void TestInitialize(string deploymentDirectory) {
            _testDataFiles = GetAllFileInfo(_testDataRoot);

            if (_vs == null || !_vs.IsRunning) {
                _vs?.Dispose();
                _vs = new VsInstance();
                _vs.StartOrRestart(
                    @"C:\Program Files (x86)\Microsoft Visual Studio\Preview\Enterprise\Common7\IDE\devenv.exe",
                    "/rootSuffix Exp",
                    _testDataRoot,
                    Path.Combine(deploymentDirectory, "Temp")
                );
            }
        }

        public void TestCleanup() {
            // TODO: Reset VS state, or close and restart

            // Clean out any ".vs" folders that were created
            foreach (var vsDir in FileUtils.EnumerateDirectories(_testDataRoot)) {
                if (Path.GetFileName(vsDir) == ".vs") {
                    Console.WriteLine($"Deleting: {vsDir}");
                    FileUtils.DeleteDirectory(vsDir);
                }
            }

            // Validate that no files in TestData were modified
            var after = GetAllFileInfo(_testDataRoot);
            var deleted = new List<string>();
            var added = new List<string>();
            var modified = new List<string>();
            foreach (var kv in _testDataFiles) {
                if (after.TryGetValue(kv.Key, out DateTime m)) {<commit_msg>Updated detection of VS path.<commit_after>﻿// Python Tools for Visual Studio
// Copyright(c) Microsoft Corporation
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the License); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED ON AN  *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
// MERCHANTABLITY OR NON-INFRINGEMENT.
//
// See the Apache Version 2.0 License for specific language governing
// permissions and limitations under the License.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;

namespace TestRunnerInterop {
    public sealed class VsTestContext : IDisposable {
        private readonly string _container, _className, _testDataRoot;
        private VsInstance _vs;
        private string _devenvExe;

        private Dictionary<string, DateTime> _testDataFiles;

        public VsTestContext(
            string container,
            string className,
            string testDataRoot
        ) {
            _container = container;
            _className = className;
            _testDataRoot = testDataRoot ?? GetDefaultTestDataDirectory();
            if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("_TESTDATA_NO_ROOTSUFFIX"))) {
                RootSuffix = "Exp";
            }
        }

        public void RunTest(string testName, params object[] arguments) {
            if (_vs == null) {
                throw new InvalidOperationException("TestInitialize was not called");
            }
            _vs.RunTest(_container, $"{_className}.{testName}", arguments);
        }

        public void Dispose() {
            if (_vs != null) {
                _vs.Dispose();
                _vs = null;
            }
        }

        public string DevEnvExe {
            get {
                if (_devenvExe == null) {
                    foreach (var envVar in new string[] {
                        $"VisualStudio_IDE_{AssemblyVersionInfo.VSVersion}",
                        "VisualStudio_IDE",
                        "VSAPPIDDIR"
                    }) {
                        _devenvExe = Environment.GetEnvironmentVariable(envVar);
                        if (string.IsNullOrEmpty(_devenvExe)) {
                            continue;
                        }
                        _devenvExe = Path.Combine(_devenvExe, "devenv.exe");
                        if (File.Exists(_devenvExe)) {
                            return _devenvExe;
                        }

                        _devenvExe = Path.Combine(Path.GetDirectoryName(_devenvExe), "IDE", "Common7", "devenv.exe");
                        if (File.Exists(_devenvExe)) {
                            return _devenvExe;
                        }

                        _devenvExe = null;
                    }
                }
                return _devenvExe;
            }
            set {
                _devenvExe = value;
            }
        }

        public string RootSuffix { get; set; }

        public void TestInitialize(string deploymentDirectory) {
            _testDataFiles = GetAllFileInfo(_testDataRoot);

            if (_vs == null || !_vs.IsRunning) {
                _vs?.Dispose();
                _vs = new VsInstance();
                _vs.StartOrRestart(
                    DevEnvExe,
                    string.IsNullOrEmpty(RootSuffix) ? null : $"/rootSuffix {RootSuffix}",
                    _testDataRoot,
                    Path.Combine(deploymentDirectory, "Temp")
                );
            }
        }

        public void TestCleanup() {
            // TODO: Reset VS state, or close and restart

            // Clean out any ".vs" folders that were created
            foreach (var vsDir in FileUtils.EnumerateDirectories(_testDataRoot)) {
                if (Path.GetFileName(vsDir) == ".vs") {
                    Console.WriteLine($"Deleting: {vsDir}");
                    FileUtils.DeleteDirectory(vsDir);
                }
            }

            // Validate that no files in TestData were modified
            var after = GetAllFileInfo(_testDataRoot);
            var deleted = new List<string>();
            var added = new List<string>();
            var modified = new List<string>();
            foreach (var kv in _testDataFiles) {
                if (after.TryGetValue(kv.Key, out DateTime m)) {
{'fraction_non_alphanumeric': 0.08614564831261101, 'fraction_numerical': 0.0020299416391778738, 'mean_word_length': 1.7107977991746905, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '6605757', 'n_tokens_mistral': 1996, 'n_tokens_neox': 1926, 'n_words': 574}