using Xunit; using Semmle.Autobuild; using System.Collections.Generic; using System; using System.Linq; using Microsoft.Build.Construction; namespace Semmle.Extraction.Tests { /// /// Test class to script Autobuilder scenarios. /// For most methods, it uses two fields: /// - an IList to capture the the arguments passed to it /// - an IDictionary of possible return values. /// class TestActions : IBuildActions { /// /// List of strings passed to FileDelete. /// public IList FileDeleteIn = new List(); void IBuildActions.FileDelete(string file) { FileDeleteIn.Add(file); } public IList FileExistsIn = new List(); public IDictionary FileExists = new Dictionary(); bool IBuildActions.FileExists(string file) { FileExistsIn.Add(file); if (FileExists.TryGetValue(file, out var ret)) return ret; throw new ArgumentException("Missing FileExists " + file); } public IList RunProcessIn = new List(); public IDictionary RunProcess = new Dictionary(); public IDictionary RunProcessOut = new Dictionary(); public IDictionary RunProcessWorkingDirectory = new Dictionary(); int IBuildActions.RunProcess(string cmd, string args, string workingDirectory, IDictionary env, out IList stdOut) { var pattern = cmd + " " + args; RunProcessIn.Add(pattern); if (RunProcessOut.TryGetValue(pattern, out var str)) stdOut = str.Split("\n"); else throw new ArgumentException("Missing RunProcessOut " + pattern); RunProcessWorkingDirectory.TryGetValue(pattern, out var wd); if (wd != workingDirectory) throw new ArgumentException("Missing RunProcessWorkingDirectory " + pattern); if (RunProcess.TryGetValue(pattern, out var ret)) return ret; throw new ArgumentException("Missing RunProcess " + pattern); } int IBuildActions.RunProcess(string cmd, string args, string workingDirectory, IDictionary env) { var pattern = cmd + " " + args; RunProcessIn.Add(pattern); RunProcessWorkingDirectory.TryGetValue(pattern, out var wd); if (wd != workingDirectory) throw new ArgumentException("Missing RunProcessWorkingDirectory " + pattern); if (RunProcess.TryGetValue(pattern, out var ret)) return ret; throw new ArgumentException("Missing RunProcess " + pattern); } public IList DirectoryDeleteIn = new List(); void IBuildActions.DirectoryDelete(string dir, bool recursive) { DirectoryDeleteIn.Add(dir); } public IDictionary DirectoryExists = new Dictionary(); public IList DirectoryExistsIn = new List(); bool IBuildActions.DirectoryExists(string dir) { DirectoryExistsIn.Add(dir); if (DirectoryExists.TryGetValue(dir, out var ret)) return ret; throw new ArgumentException("Missing DirectoryExists " + dir); } public IDictionary GetEnvironmentVariable = new Dictionary(); string IBuildActions.GetEnvironmentVariable(string name) { if (GetEnvironmentVariable.TryGetValue(name, out var ret)) return ret; throw new ArgumentException("Missing GetEnvironmentVariable " + name); } public string GetCurrentDirectory; string IBuildActions.GetCurrentDirectory() { return GetCurrentDirectory; } public IDictionary EnumerateFiles = new Dictionary(); IEnumerable IBuildActions.EnumerateFiles(string dir) { if (EnumerateFiles.TryGetValue(dir, out var str)) return str.Split("\n"); throw new ArgumentException("Missing EnumerateFiles " + dir); } public IDictionary EnumerateDirectories = new Dictionary(); IEnumerable IBuildActions.EnumerateDirectories(string dir) { if (EnumerateDirectories.TryGetValue(dir, out var str)) return string.IsNullOrEmpty(str) ? Enumerable.Empty() : str.Split("\n"); throw new ArgumentException("Missing EnumerateDirectories " + dir); } public bool IsWindows; bool IBuildActions.IsWindows() => IsWindows; string IBuildActions.PathCombine(params string[] parts) { return string.Join('\\', parts); } void IBuildActions.WriteAllText(string filename, string contents) { } } /// /// A fake solution to build. /// class TestSolution : ISolution { public IEnumerable Projects => throw new NotImplementedException(); public IEnumerable Configurations => throw new NotImplementedException(); public string DefaultConfigurationName => "Release"; public string DefaultPlatformName => "x86"; public string Path { get; set; } public int ProjectCount => throw new NotImplementedException(); public Version ToolsVersion => new Version("14.0"); public TestSolution(string path) { Path = path; } } public class BuildScriptTests { TestActions Actions = new TestActions(); // Records the arguments passed to StartCallback. IList StartCallbackIn = new List(); void StartCallback(string s) { StartCallbackIn.Add(s); } // Records the arguments passed to EndCallback IList EndCallbackIn = new List(); IList EndCallbackReturn = new List(); void EndCallback(int ret, string s) { EndCallbackReturn.Add(ret); EndCallbackIn.Add(s); } [Fact] public void TestBuildCommand() { var cmd = BuildScript.Create("abc", "def ghi", null, null); Actions.RunProcess["abc def ghi"] = 1; cmd.Run(Actions, StartCallback, EndCallback); Assert.Equal("abc def ghi", Actions.RunProcessIn[0]); Assert.Equal("abc def ghi", StartCallbackIn[0]); Assert.Equal("", EndCallbackIn[0]); Assert.Equal(1, EndCallbackReturn[0]); } [Fact] public void TestAnd1() { var cmd = BuildScript.Create("abc", "def ghi", null, null) & BuildScript.Create("odasa", null, null, null); Actions.RunProcess["abc def ghi"] = 1; cmd.Run(Actions, StartCallback, EndCallback); Assert.Equal("abc def ghi", Actions.RunProcessIn[0]); Assert.Equal("abc def ghi", StartCallbackIn[0]); Assert.Equal("", EndCallbackIn[0]); Assert.Equal(1, EndCallbackReturn[0]); } [Fact] public void TestAnd2() { var cmd = BuildScript.Create("odasa", null, null, null) & BuildScript.Create("abc", "def ghi", null, null); Actions.RunProcess["abc def ghi"] = 1; Actions.RunProcess["odasa "] = 0; cmd.Run(Actions, StartCallback, EndCallback); Assert.Equal("odasa ", Actions.RunProcessIn[0]); Assert.Equal("odasa ", StartCallbackIn[0]); Assert.Equal("", EndCallbackIn[0]); Assert.Equal(0, EndCallbackReturn[0]); Assert.Equal("abc def ghi", Actions.RunProcessIn[1]); Assert.Equal("abc def ghi", StartCallbackIn[1]); Assert.Equal("", EndCallbackIn[1]); Assert.Equal(1, EndCallbackReturn[1]); } [Fact] public void TestOr1() { var cmd = BuildScript.Create("odasa", null, null, null) | BuildScript.Create("abc", "def ghi", null, null); Actions.RunProcess["abc def ghi"] = 1; Actions.RunProcess["odasa "] = 0; cmd.Run(Actions, StartCallback, EndCallback); Assert.Equal("odasa ", Actions.RunProcessIn[0]); Assert.Equal("odasa ", StartCallbackIn[0]); Assert.Equal("", EndCallbackIn[0]); Assert.Equal(0, EndCallbackReturn[0]); Assert.Equal(1, EndCallbackReturn.Count); } [Fact] public void TestOr2() { var cmd = BuildScript.Create("abc", "def ghi", null, null) | BuildScript.Create("odasa", null, null, null); Actions.RunProcess["abc def ghi"] = 1; Actions.RunProcess["odasa "] = 0; cmd.Run(Actions, StartCallback, EndCallback); Assert.Equal("abc def ghi", Actions.RunProcessIn[0]); Assert.Equal("abc def ghi", StartCallbackIn[0]); Assert.Equal("", EndCallbackIn[0]); Assert.Equal(1, EndCallbackReturn[0]); Assert.Equal("odasa ", Actions.RunProcessIn[1]); Assert.Equal("odasa ", StartCallbackIn[1]); Assert.Equal("", EndCallbackIn[1]); Assert.Equal(0, EndCallbackReturn[1]); } [Fact] public void TestSuccess() { Assert.Equal(0, BuildScript.Success.Run(Actions, StartCallback, EndCallback)); } [Fact] public void TestFailure() { Assert.NotEqual(0, BuildScript.Failure.Run(Actions, StartCallback, EndCallback)); } [Fact] public void TestDeleteDirectorySuccess() { Actions.DirectoryExists["trap"] = true; Assert.Equal(0, BuildScript.DeleteDirectory("trap").Run(Actions, StartCallback, EndCallback)); Assert.Equal("trap", Actions.DirectoryDeleteIn[0]); } [Fact] public void TestDeleteDirectoryFailure() { Actions.DirectoryExists["trap"] = false; Assert.NotEqual(0, BuildScript.DeleteDirectory("trap").Run(Actions, StartCallback, EndCallback)); } [Fact] public void TestDeleteFileSuccess() { Actions.FileExists["csharp.log"] = true; Assert.Equal(0, BuildScript.DeleteFile("csharp.log").Run(Actions, StartCallback, EndCallback)); Assert.Equal("csharp.log", Actions.FileExistsIn[0]); Assert.Equal("csharp.log", Actions.FileDeleteIn[0]); } [Fact] public void TestDeleteFileFailure() { Actions.FileExists["csharp.log"] = false; Assert.NotEqual(0, BuildScript.DeleteFile("csharp.log").Run(Actions, StartCallback, EndCallback)); Assert.Equal("csharp.log", Actions.FileExistsIn[0]); } [Fact] public void TestTry() { Assert.Equal(0, BuildScript.Try(BuildScript.Failure).Run(Actions, StartCallback, EndCallback)); } Autobuilder CreateAutoBuilder(string lgtmLanguage, bool isWindows, string buildless=null, string solution=null, string buildCommand=null, string ignoreErrors=null, string msBuildArguments=null, string msBuildPlatform=null, string msBuildConfiguration=null, string msBuildTarget=null, string dotnetArguments=null, string dotnetVersion=null, string vsToolsVersion=null, string nugetRestore=null, string allSolutions=null, string cwd=@"C:\Project") { Actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa"; Actions.GetEnvironmentVariable["SEMMLE_JAVA_HOME"] = @"C:\odasa\tools\java"; Actions.GetEnvironmentVariable["LGTM_PROJECT_LANGUAGE"] = lgtmLanguage; Actions.GetEnvironmentVariable["SEMMLE_PLATFORM_TOOLS"] = @"C:\odasa\tools"; Actions.GetEnvironmentVariable["LGTM_INDEX_VSTOOLS_VERSION"] = vsToolsVersion; Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_ARGUMENTS"] = msBuildArguments; Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_PLATFORM"] = msBuildPlatform; Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_CONFIGURATION"] = msBuildConfiguration; Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_TARGET"] = msBuildTarget; Actions.GetEnvironmentVariable["LGTM_INDEX_DOTNET_ARGUMENTS"] = dotnetArguments; Actions.GetEnvironmentVariable["LGTM_INDEX_DOTNET_VERSION"] = dotnetVersion; Actions.GetEnvironmentVariable["LGTM_INDEX_BUILD_COMMAND"] = buildCommand; Actions.GetEnvironmentVariable["LGTM_INDEX_SOLUTION"] = solution; Actions.GetEnvironmentVariable["LGTM_INDEX_IGNORE_ERRORS"] = ignoreErrors; Actions.GetEnvironmentVariable["LGTM_INDEX_BUILDLESS"] = buildless; Actions.GetEnvironmentVariable["LGTM_INDEX_ALL_SOLUTIONS"] = allSolutions; Actions.GetEnvironmentVariable["LGTM_INDEX_NUGET_RESTORE"] = nugetRestore; Actions.GetEnvironmentVariable["ProgramFiles(x86)"] = isWindows ? @"C:\Program Files (x86)" : null; Actions.GetCurrentDirectory = cwd; Actions.IsWindows = isWindows; var options = new AutobuildOptions(); options.ReadEnvironment(Actions); return new Autobuilder(Actions, options); } [Fact] public void TestDefaultCSharpAutoBuilder() { Actions.RunProcess["cmd.exe /C dotnet --info"] = 0; Actions.RunProcess["cmd.exe /C dotnet clean"] = 0; Actions.RunProcess["cmd.exe /C dotnet restore"] = 0; Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --auto dotnet build --no-incremental /p:UseSharedCompilation=false"] = 0; Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0; Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config"] = 0; Actions.FileExists["csharp.log"] = true; Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null; Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null; Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\nbar.cs"; Actions.EnumerateDirectories[@"C:\Project"] = ""; var autobuilder = CreateAutoBuilder("csharp", true); TestAutobuilderScript(autobuilder, 0, 6); } [Fact] public void TestLinuxCSharpAutoBuilder() { Actions.RunProcess["dotnet --info"] = 0; Actions.RunProcess["dotnet clean"] = 0; Actions.RunProcess["dotnet restore"] = 0; Actions.RunProcess[@"C:\odasa\tools\odasa index --auto dotnet build --no-incremental /p:UseSharedCompilation=false"] = 0; Actions.RunProcess[@"C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0; Actions.RunProcess[@"C:\odasa\tools\odasa index --xml --extensions config"] = 0; Actions.FileExists["csharp.log"] = true; Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null; Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null; Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs"; Actions.EnumerateDirectories[@"C:\Project"] = ""; var autobuilder = CreateAutoBuilder("csharp", false); TestAutobuilderScript(autobuilder, 0, 6); } [Fact] public void TestLinuxCSharpAutoBuilderExtractorFailed() { Actions.RunProcess["dotnet --info"] = 0; Actions.RunProcess["dotnet clean"] = 0; Actions.RunProcess["dotnet restore"] = 0; Actions.RunProcess[@"C:\odasa\tools\odasa index --auto dotnet build --no-incremental /p:UseSharedCompilation=false"] = 0; Actions.FileExists["csharp.log"] = false; Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null; Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null; Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs"; Actions.EnumerateDirectories[@"C:\Project"] = ""; var autobuilder = CreateAutoBuilder("csharp", false); TestAutobuilderScript(autobuilder, 1, 4); } [Fact] public void TestDefaultCppAutobuilder() { Actions.EnumerateFiles[@"C:\Project"] = ""; Actions.EnumerateDirectories[@"C:\Project"] = ""; var autobuilder = CreateAutoBuilder("cpp", true); var script = autobuilder.GetBuildScript(); // Fails due to no solutions present. Assert.NotEqual(0, script.Run(Actions, StartCallback, EndCallback)); } [Fact] public void TestCppAutobuilderSuccess() { Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore C:\Project\test.sln"] = 1; Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program Files ^(x86^)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat^"" && C:\odasa\tools\odasa index --auto msbuild C:\Project\test.sln /p:UseSharedCompilation=false /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"" /p:MvcBuildViews=true"] = 0; Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = ""; Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 1; Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0; Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = ""; Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = true; Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true; Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = true; Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true; Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = true; Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.slx"; Actions.EnumerateDirectories[@"C:\Project"] = ""; var autobuilder = CreateAutoBuilder("cpp", true); var solution = new TestSolution(@"C:\Project\test.sln"); autobuilder.SolutionsToBuild.Add(solution); TestAutobuilderScript(autobuilder, 0, 2); } [Fact] public void TestVsWhereSucceeded() { Actions.GetEnvironmentVariable["ProgramFiles(x86)"] = @"C:\Program Files (x86)"; Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = true; Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 0; Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = "C:\\VS1\nC:\\VS2"; Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = "10.0\n11.0"; Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0; var candidates = BuildTools.GetCandidateVcVarsFiles(Actions).ToArray(); Assert.Equal("C:\\VS1\\VC\\vcvarsall.bat", candidates[0].Path); Assert.Equal(10, candidates[0].ToolsVersion); Assert.Equal("C:\\VS2\\VC\\vcvarsall.bat", candidates[1].Path); Assert.Equal(11, candidates[1].ToolsVersion); } [Fact] public void TestVsWhereNotExist() { Actions.GetEnvironmentVariable["ProgramFiles(x86)"] = @"C:\Program Files (x86)"; Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; var candidates = BuildTools.GetCandidateVcVarsFiles(Actions).ToArray(); Assert.Equal(4, candidates.Length); } [Fact] public void TestVcVarsAllBatFiles() { Actions.GetEnvironmentVariable["ProgramFiles(x86)"] = @"C:\Program Files (x86)"; Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = true; Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = false; Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = true; Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = false; var vcvarsfiles = BuildTools.VcVarsAllBatFiles(Actions).ToArray(); Assert.Equal(2, vcvarsfiles.Length); } [Fact] public void TestLinuxBuildlessExtractionSuccess() { Actions.RunProcess[@"C:\odasa\tools\csharp\Semmle.Extraction.CSharp.Standalone --references:."] = 0; Actions.RunProcess[@"C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0; Actions.RunProcess[@"C:\odasa\tools\odasa index --xml --extensions config"] = 0; Actions.FileExists["csharp.log"] = true; Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null; Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null; Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; Actions.EnumerateDirectories[@"C:\Project"] = ""; var autobuilder = CreateAutoBuilder("csharp", false, buildless:"true"); TestAutobuilderScript(autobuilder, 0, 3); } [Fact] public void TestLinuxBuildlessExtractionFailed() { Actions.RunProcess[@"C:\odasa\tools\csharp\Semmle.Extraction.CSharp.Standalone --references:."] = 10; Actions.RunProcess[@"C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0; Actions.RunProcess[@"C:\odasa\tools\odasa index --xml --extensions config"] = 0; Actions.FileExists["csharp.log"] = true; Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null; Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null; Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; Actions.EnumerateDirectories[@"C:\Project"] = ""; var autobuilder = CreateAutoBuilder("csharp", false, buildless: "true"); TestAutobuilderScript(autobuilder, 10, 1); } [Fact] public void TestLinuxBuildlessExtractionSolution() { Actions.RunProcess[@"C:\odasa\tools\csharp\Semmle.Extraction.CSharp.Standalone foo.sln --references:."] = 0; Actions.RunProcess[@"C:\odasa\tools\java\bin\java -jar C:\odasa\tools\extractor-asp.jar ."] = 0; Actions.RunProcess[@"C:\odasa\tools\odasa index --xml --extensions config"] = 0; Actions.FileExists["csharp.log"] = true; Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null; Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null; Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; Actions.EnumerateDirectories[@"C:\Project"] = ""; var autobuilder = CreateAutoBuilder("csharp", false, buildless: "true", solution: "foo.sln"); TestAutobuilderScript(autobuilder, 0, 3); } void SkipVsWhere() { Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false; Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = false; Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = false; Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = false; } void TestAutobuilderScript(Autobuilder autobuilder, int expectedOutput, int commandsRun) { Assert.Equal(expectedOutput, autobuilder.GetBuildScript().Run(Actions, StartCallback, EndCallback)); // Check expected commands actually ran Assert.Equal(commandsRun, StartCallbackIn.Count); Assert.Equal(commandsRun, EndCallbackIn.Count); Assert.Equal(commandsRun, EndCallbackReturn.Count); var action = Actions.RunProcess.GetEnumerator(); for(int cmd=0; cmd