public IEnumerator TestUpdatePackagesWithOneUpgrade()
        {
            using (Py.GIL())
            {
                dynamic shlex = PythonEngine.ImportModule("shlex");

                using (var env = new PyTestVenv())
                {
#if UNITY_EDITOR_WIN
                    string pythonVenvInterpreter = Path.Combine(env.path, "Scripts", "python.exe");
                    // CallPipFreeze, PYTHONPATH limited to py venv path
                    string pythonPath = Path.Combine(env.path, "Lib", "site-packages");
#else
                    string pythonVenvInterpreter = Path.Combine(env.path, "bin", "python3");
                    string pythonPath            = Path.Combine(env.path, "lib", "site-packages", "python3.7", "site-packages");
#endif
                    // Install toml 0.9.0 into the py venv
                    var     argsStr = new PyString("-m pip install toml==0.9.0");
                    var     args    = shlex.split(argsStr);
                    dynamic proc    = spawn(pythonVenvInterpreter, args,
                                            wantLogging: false);
                    yield return(WaitForProcessEnd(proc, 20));

                    // Need to update pip, piptools requires pip._internal.commands.create_command, which is not available witout updating
                    argsStr = new PyString(" -m pip install pip -U");
                    args    = shlex.split(argsStr);
                    dynamic envOverride = new PyDict();
                    envOverride["PYTHONPATH"] = new PyString(pythonPath);
                    dynamic proc2 = spawn(pythonVenvInterpreter, args,
                                          env_override: envOverride,
                                          wantLogging: false);
                    yield return(WaitForProcessEnd(proc2, 20));

                    // Call UpdatePackages with a requirements.txt file containing only a requirement to toml 0.10.0
                    var testRequirementFile = Path.Combine(TestsPath, "test_requirements_1.txt");
                    PipPackages.UpdatePackages(testRequirementFile, pythonVenvInterpreter);

                    // NOTE:
                    // in this case, this not pip-tools diff/sync funcs that remove toml 9 for toml 10,
                    // it is pip that sees another version of the same package exists and then uninstall
                    // the current version before installing the required one

                    // Check that the only package in the py venv is toml 0.10.0
                    var output = CallPipFreeze(pythonVenvInterpreter, pythonPath);
                    Assert.That(output, Is.EqualTo("toml==0.10.0\n"));
                }
            }
        }
        public IEnumerator TestUpdatePackagesWithOneDowngrade()
        {
            using (Py.GIL())
            {
                dynamic shlex = PythonEngine.ImportModule("shlex");

                using (var env = new PyTestVenv())
                {
#if UNITY_EDITOR_WIN
                    string pythonVenvInterpreter = Path.Combine(env.path, "Scripts", "python.exe");
                    // CallPipFreeze, PYTHONPATH limited to py venv path
                    string pythonPath = Path.Combine(env.path, "Lib", "site-packages");
#else
                    string pythonVenvInterpreter = Path.Combine(env.path, "bin", "python3");
                    string pythonPath            = Path.Combine(env.path, "lib", "site-packages", "python3.7", "site-packages");
#endif
                    // Install toml 0.10.0 into the py venv
                    var     argsStr = new PyString("-m pip install toml==0.10.0");
                    var     args    = shlex.split(argsStr);
                    dynamic proc    = spawn(pythonVenvInterpreter, args,
                                            wantLogging: false);
                    yield return(WaitForProcessEnd(proc, 20));

                    argsStr = new PyString(" -m pip install pip -U");
                    args    = shlex.split(argsStr);
                    dynamic envOverride = new PyDict();
                    envOverride["PYTHONPATH"] = new PyString(pythonPath);
                    dynamic proc2 = spawn(pythonVenvInterpreter, args,
                                          env_override: envOverride,
                                          wantLogging: false);
                    yield return(WaitForProcessEnd(proc2, 20));

                    // Call UpdatePackages with a requirements.txt file containing only a requirement to toml 0.9.0
                    var testRequirementFile = Path.Combine(TestsPath, "test_requirements_2.txt");
                    PipPackages.UpdatePackages(testRequirementFile, pythonVenvInterpreter);

                    // Check that the only package in the py venv is toml 0.9.0

                    var output = CallPipFreeze(pythonVenvInterpreter, pythonPath);
                    Assert.That(output, Is.EqualTo("toml==0.9.0\n"));
                }
            }
        }
        public void TestIsInterestingWarning()
        {
            string unwantedWarningMsg1 = "WARNING: The scripts coverage-3.7.exe, coverage.exe and coverage3.exe are installed in 'D:\\UnityProjects\\Python 3 - Copy\\Library\\PythonInstall\\Scripts' which is not on PATH.";
            string unwantedWarningMsg2 = "Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.";
            string unwantedWarningMsg3 = "WARNING: You are using pip version 20.0.2; however, version 20.1 is available.";
            string unwantedWarningMsg4 = "You should consider upgrading via the 'D:\\UnityProjects\\Python 3 - Copy\\Library\\PythonInstall\\python.exe -m pip install --upgrade pip' command.";

            string wantedWarningMsg = "Command \"python setup.py egg_info\" failed with error code 1 in C:\\Users\\foo\\AppData\\Local\\Temp\\pip-install-ws21otxr\\psycopg2\\";

            Assert.That(PipPackages.IsInterestingWarning(unwantedWarningMsg1), Is.False);
            Assert.That(PipPackages.IsInterestingWarning(unwantedWarningMsg2), Is.False);
            Assert.That(PipPackages.IsInterestingWarning(unwantedWarningMsg3), Is.False);
            Assert.That(PipPackages.IsInterestingWarning(unwantedWarningMsg4), Is.False);

            Assert.That(PipPackages.IsInterestingWarning(wantedWarningMsg), Is.True);

            // try with null or empty message
            Assert.That(PipPackages.IsInterestingWarning(null), Is.False);
            Assert.That(PipPackages.IsInterestingWarning(""), Is.False);
        }
        public IEnumerator TestUpdatePackagesWithSeveralPackages()
        {
            using (Py.GIL())
            {
                dynamic shlex = PythonEngine.ImportModule("shlex");

                using (var env = new PyTestVenv())
                {
#if UNITY_EDITOR_WIN
                    string pythonVenvInterpreter = Path.Combine(env.path, "Scripts", "python.exe");
                    // CallPipFreeze, PYTHONPATH limited to py venv path
                    string pythonPath = Path.Combine(env.path, "Lib", "site-packages");
#else
                    string pythonVenvInterpreter = Path.Combine(env.path, "bin", "python3");
                    string pythonPath            = Path.Combine(env.path, "lib", "site-packages", "python3.7", "site-packages");
#endif
                    // Install several packages:
                    // numpy & vg have no dependencies
                    // UnityPy depends on Brotli colorama lz4 Pillow termcolor
                    var     argsStr = new PyString("-m pip install numpy==1.17.5  vg==1.6.0 UnityPy==1.2.4.8");
                    var     args    = shlex.split(argsStr);
                    dynamic proc    = spawn(pythonVenvInterpreter, args,
                                            wantLogging: false);
                    yield return(WaitForProcessEnd(proc, 60));

                    // Check installations went as expected, to ensure our test is properly set
                    string output = CallPipFreeze(pythonVenvInterpreter, pythonPath);
                    // requested packages with specific versions
                    Assert.That(output, Contains.Substring("numpy==1.17.5"));
                    Assert.That(output, Contains.Substring("vg==1.6.0"));
                    Assert.That(output, Contains.Substring("UnityPy==1.2.4.8"));
                    // dependent packages, we don't know the version number
                    Assert.That(output, Contains.Substring("Brotli"));
                    Assert.That(output, Contains.Substring("colorama"));
                    Assert.That(output, Contains.Substring("lz4"));
                    Assert.That(output, Contains.Substring("Pillow"));
                    Assert.That(output, Contains.Substring("termcolor"));
                    // we should not have any more packages
                    var newLineRegex = new Regex(@"\r\n|\n|\r");
                    var lines        = newLineRegex.Split(output);
                    Assert.That(lines.Length, Is.EqualTo(9)); // 8 package lines + 1 empty line

                    argsStr = new PyString(" -m pip install pip -U");
                    args    = shlex.split(argsStr);

                    dynamic envOverride = new PyDict();
                    envOverride["PYTHONPATH"] = new PyString(pythonPath);
                    dynamic proc2 = spawn(pythonVenvInterpreter, args,
                                          env_override: envOverride,
                                          wantLogging: false);
                    yield return(WaitForProcessEnd(proc2, 20));

                    // Call UpdatePackages with a requirements.txt file containing:
                    // numpy==1.18.2
                    // vg==1.7.0
                    // Brotli==1.0.7
                    var testRequirementFile = Path.Combine(TestsPath, "test_requirements_3.txt");
                    PipPackages.UpdatePackages(testRequirementFile, pythonVenvInterpreter);

                    var output2 = CallPipFreeze(pythonVenvInterpreter, pythonPath);
                    Assert.That(output2, Contains.Substring("numpy==1.18.2"));
                    Assert.That(output2, Contains.Substring("vg==1.7.0"));
                    Assert.That(output2, Contains.Substring("Brotli==1.0.7"));
                    var lines2 = newLineRegex.Split(output2);
                    Assert.That(lines2.Length, Is.EqualTo(4));
                }
            }
        }