/// <summary> /// Gets visual studio default format for specific configuration. /// </summary> /// <param name="confName">configuration name (E.g. Debug|Win32) for which to query, null if use this configuration</param> /// <returns>Default value</returns> public EDebugInformationFormat getDebugInformationFormatDefault(String confName) { String platform; if (confName != null) { platform = confName.Split('|')[1]; } else { platform = this.confName.Split('|')[1]; } if (platform.ToLower() == "win32" || platform == "x86") { return(EDebugInformationFormat.EditAndContinue); } if (platform == "x64") { return(EDebugInformationFormat.ProgramDatabase); } // Android projects does not have "default" configuration, so they needs to be specified anyway. if (platform == "ARM" || platform == "ARM64") { return(EDebugInformationFormat.Invalid); } if (SolutionProjectBuilder.isDeveloper()) { // Default needs to be checked from Visual studio. Debugger.Break(); } return(EDebugInformationFormat.ProgramDatabase); }
override public void InvokeTest(bool isLastMethod, TestResults localTestResults) { String testsDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Tests"); if (diffExe == null) { // // We use TortoiseMerge.exe if we have one (can copy paste changes in merge tool itself) // diffExe = @"C:\Program Files\TortoiseSVN\bin\TortoiseMerge.exe"; bool bTortoiseDiff = true; if (!File.Exists(diffExe)) { diffExe = Path.Combine(testsDir, "ExamDiff.exe"); bTortoiseDiff = false; } if (!File.Exists(diffExe)) { throw new Exception("Diff tool does not exists '" + diffExe + "'"); } // // Launch diff viewer. // if (!bTortoiseDiff) { // Change background color of comparison. RegistryKey key = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.CurrentUser, RegistryView.Registry64).CreateSubKey(@"Software\PrestoSoft\ExamDiff\Settings"); if (key != null && key.GetValue("TestInitialized") as String != "1") { key.SetValue("TestInitialized", "1"); key.SetValue("Back Changed Color", 0xb7b7ff); } } } int error = 0; String test = sourceCodePath; String dir = Path.GetDirectoryName(test); String logActual = ""; UpdateInfo.lastUpdateInfo = null; UpdateInfo.bTesting = true; // // We launch test via direct Invoke currently - it's just simpler to debug if there is a problem, // but this requires initializing static global variables back to default state. // // I've left here ExecCmd - but main problem is that even MessageBox shown from console application // is closed without any clear reason. // bool bIsBat = Path.GetExtension(test).ToLower() == ".bat"; String toolName = "syncProj"; if (bIsBat) { // Requires Android stuff preinstalled, we want to focus on syncProj testing. String[] excludeBats = new string[] { "gradlew", "getsigninfo" }; if (Array.IndexOf(excludeBats, Path.GetFileNameWithoutExtension(test).ToLower()) != -1) { return; } error = ExecCmd(test + " -x", ref logActual); toolName = "Batch"; } else { ConsoleWriter cw = new ConsoleWriter(); SolutionProjectBuilder.resetStatics(); var co = Console.Out; Console.SetOut(cw); error = syncProj.Main(new String[] { "-x", "-p", "out_", test }); bool bIsScript = Path.GetExtension(test).ToLower() == ".cs"; if (bIsScript) // By default it's executed by default destructor, here we need to launch it manually. { SolutionProjectBuilder.SaveGenerated(); } cw.Flush(); Console.SetOut(co); logActual = cw.sb.ToString(); } String errMsg; // Add command line tool error code into log itself. if (error == 0) { errMsg = toolName + " exited with no error"; } else { errMsg = toolName + " exited with ERROR: " + error; } logActual = errMsg + "\r\n" + logActual; Regex reOutFile = new Regex("\\\\" + Regex.Escape("out_" + Path.GetFileNameWithoutExtension(test)) + "(\\.|_cs)"); List <String> verifyFiles = Directory.GetFiles(dir, "*", SearchOption.AllDirectories).Where(x => reOutFile.Match(x).Success).ToList(); verifyFiles.Insert(0, test + ".accepted_log.txt"); Dictionary <String, bool> testedFiles = new Dictionary <string, bool>(); // // Collect all information about which files syncProj tried to save or check if they are up-to-date. // if (UpdateInfo.lastUpdateInfo != null) { verifyFiles.AddRange(UpdateInfo.lastUpdateInfo.filesUpdated); verifyFiles.AddRange(UpdateInfo.lastUpdateInfo.filesUpToDate); } // // iFile == 0 only for output of command line execution - rest of files are actually compared files. // for (int iFile = 0; iFile < verifyFiles.Count; iFile++) { String file = verifyFiles[iFile]; // Pick up only two last file extensions. test.sln.accepted_log.txt => "test.sln" + ".accepted_log.txt" var re = Regex.Match(file, @"(.*\\[^\\]+?)(\.[^\\\.]*\.[^\\\.]*)$"); String fPathBase; String dblExt; String ext = Path.GetExtension(file).ToLower(); if (re.Success) { fPathBase = re.Groups[1].ToString(); dblExt = re.Groups[2].ToString().ToLower(); } else { fPathBase = Path.GetDirectoryName(file) + "\\" + Path.GetFileNameWithoutExtension(file); dblExt = Path.GetExtension(file).ToLower(); } String logAcceptedFile = ""; String logActualFile = ""; if (ext == ".accepted") { // file which is expected to be generated logAcceptedFile = file; logActualFile = file.Substring(0, file.Length - ext.Length); } else { if (dblExt == ".accepted_log.txt") { // tool output logAcceptedFile = file; logActualFile = fPathBase + ".actual_log.txt"; } else { // actual file generated logAcceptedFile = file + ".accepted"; logActualFile = file; } } //if-else if (testedFiles.ContainsKey(logAcceptedFile)) { continue; } testedFiles[logAcceptedFile] = true; String testNameShort = test.Substring(testsDir.Length + 1); if (iFile != 0) { testNameShort += " for file '" + Path.GetFileName(file) + "'"; } // // Until we have decision made by developer. // while (true) { String logAccepted = ""; String errorMessage; bool bAcceptedFileExists = File.Exists(logAcceptedFile); if (!bAcceptedFileExists) { // First time acceptance errorMessage = "Test results for '" + testNameShort + "' does not yet exists."; } else { // Second time acceptance errorMessage = "Test on '" + testNameShort + "' failed, results differ."; logAccepted = File.ReadAllText(logAcceptedFile); } if (iFile != 0) { logActual = File.ReadAllText(logActualFile); } if (logActual == logAccepted) { localTestResults.files++; break; } DialogResult dr = MessageBox.Show( errorMessage + "\r\n" + "\r\n" + "Press:\r\n" + "- 'Yes' to accept current changes\r\n" + "- 'No' to view full file comparison\r\n" + "- 'Cancel' to abort and fix code\r\n" , "Test failed - " + testNameShort, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button3); if (dr == DialogResult.Cancel) { throw new OperationCanceledException("Testing aborted"); } // If first file (console output), save log file before performing move if (iFile == 0) { File.WriteAllText(logActualFile, logActual); } if (dr == DialogResult.Yes) { File.Copy(logActualFile, logAcceptedFile, true); } else { if (!bAcceptedFileExists) // Just a dummy file so comparison tool would not mind. { File.WriteAllText(logAcceptedFile, ""); } Process.Start(diffExe, "\"" + logAcceptedFile + "\" \"" + logActualFile + "\"").WaitForExit(); logActual = File.ReadAllText(logActualFile); } //if-else } //while (file is not the same) if (File.Exists(logActualFile)) { File.Delete(logActualFile); } } //for file }
/// <summary> /// Saves solution into .sln file. Where to save is defined by path. /// </summary> /// <param name="_path">path to .sln, null if use from 'path' variable.</param> /// <param name="uinfo">Update information</param> public void SaveSolution(UpdateInfo uinfo, String _path = null) { String slnPath = _path; if (_path == null) { slnPath = path; } // // For all projects which does not have uuid, we generated uuid based on project name. // SolutionProjectBuilder.externalproject(null); // Release any active project if we have one. if (fileFormatVersion >= 2017 && String.IsNullOrEmpty(SolutionGuid)) { SolutionProjectBuilder.uuid(name + "_solution" /* Add some uniqueness - just not to collise with project guids. */); } foreach (Project p in projects) { if (String.IsNullOrEmpty(p.ProjectGuid)) { SolutionProjectBuilder.m_project = p; SolutionProjectBuilder.uuid(p.ProjectName); SolutionProjectBuilder.m_project = null; } } //foreach StringBuilder o = new StringBuilder(); o.AppendLine(); int verTag = fileFormatVersion; if (verTag == 0) { verTag = 2015; } String formatVersion = "12.00"; if (verTag <= 2010) { formatVersion = "11.00"; } o.AppendLine("Microsoft Visual Studio Solution File, Format Version " + formatVersion); int verTag2; switch (verTag) { case 2015: verTag2 = 14; break; case 2017: verTag2 = 15; break; case 2019: verTag2 = 16; break; default: // Try to predict the future here... verTag2 = 14 + (verTag - 2015) / 2; break; } if (verTag2 >= 16) { o.AppendLine("# Visual Studio Version " + verTag2.ToString()); } else { o.AppendLine("# Visual Studio " + verTag2.ToString()); } // Must be specified, otherwise Visual studio will try to save project after load. if (fileFormatVersion >= 2017) { // Those numbers are pretty ugly to hardcode, but no other choice at the moment. String ver = VisualStudioVersion; if (ver == null) { switch (fileFormatVersion) { case 2017: ver = "15.0.28307.136"; break; default: case 2019: ver = "16.0.28315.86"; break; } } o.AppendLine("VisualStudioVersion = " + ver); } // Must be specified, otherwise Visual studio will try to save project after load. if (fileFormatVersion >= 2015) { String ver = MinimumVisualStudioVersion; if (ver == null) { ver = "10.0.40219.1"; } o.AppendLine("MinimumVisualStudioVersion = " + ver); } // Visual studio 2015 itself dumps also VisualStudioVersion & MinimumVisualStudioVersion - but we cannot support it, as it's targetted per visual studio toolset version. // // Dump projects. // foreach (Project p in projects) { o.AppendLine("Project(\"" + p.ProjectHostGuid + "\") = \"" + p.ProjectName + "\", \"" + p.getRelativePath() + "\", \"" + p.ProjectGuid.ToUpper() + "\""); // // Dump project dependencies. // if (p.ProjectDependencies != null) { o.AppendLine(" ProjectSection(ProjectDependencies) = postProject"); foreach (String depProjName in p.ProjectDependencies) { String guid = null; // Dependency specified by {guid} if (SolutionProjectBuilder.guidMatcher.Match(depProjName).Success) { guid = depProjName; } else { // Dependency specified by project name Project dproj = projects.Where(x => x.ProjectName == depProjName).FirstOrDefault(); if (dproj != null) { guid = dproj.ProjectGuid.ToUpper(); } } if (guid != null) { o.AppendLine(" "+ guid + " = " + guid); } } o.AppendLine(" EndProjectSection"); } //if o.AppendLine("EndProject"); } List <String> sortedConfs = Project.getSortedConfigurations(configurations, false, null, true); // // Dump configurations. // o.AppendLine("Global"); o.AppendLine(" GlobalSection(SolutionConfigurationPlatforms) = preSolution"); foreach (String cfg in sortedConfs) { o.AppendLine(" "+ cfg + " = " + cfg); } o.AppendLine(" EndGlobalSection"); // // Dump solution to project configuration mapping and whether or not to build specific project. // o.AppendLine(" GlobalSection(ProjectConfigurationPlatforms) = postSolution"); foreach (Project p in projects) { if (p.IsSubFolder()) // If sub-folder no need to list it here. { continue; } List <String> projConfs = p.getConfigurationNames(); List <String> projPlatforms = p.getPlatforms(); foreach (String conf in sortedConfs) { int iConf = configurations.IndexOf(conf); String mappedConf = conf; bool bPeformBuild = true; bool?bPerformDeploy = null; if (p.bIsPackagingProject) { bPerformDeploy = true; } if (p.slnConfigurations != null && iConf < p.slnConfigurations.Count) { // Mapped configuration item is specified. mappedConf = p.slnConfigurations[iConf]; } else { if (p.bDefinedAsExternal) { // Hack - assume one to one mapping for timebeing. mappedConf = conf; } else { // // Try to map configuration by ourselfs. Map x86 to Win32 automatically. // if (!p.configurations.Contains(conf)) { String[] confPlat = conf.Split('|'); if (projConfs.Contains(confPlat[0]) && confPlat[1] == "x86" && projPlatforms.Contains("Win32")) { mappedConf = confPlat[0] + '|' + "Win32"; } else { // Configuration cannot be mapped (E.g. Solution has "Debug|Arm", project supports only "Debug|Win32". // We disable project build, but try to map configuration anyway - otherwise Visual Studio will // try to save solution by itself. bPeformBuild = false; bPerformDeploy = null; mappedConf = p.configurations.Where(x => x.StartsWith(confPlat[0])).FirstOrDefault(); if (mappedConf == null) { mappedConf = p.configurations[0]; } } //if-else } //if } } if (p.slnBuildProject != null && iConf < p.slnBuildProject.Count) { bPeformBuild = p.slnBuildProject[iConf]; } if (p.slnDeployProject != null && iConf < p.slnConfigurations.Count) { bPerformDeploy = p.slnDeployProject[iConf]; } o.AppendLine(" "+ p.ProjectGuid.ToUpper() + "." + conf + ".ActiveCfg = " + mappedConf); if (bPeformBuild) { o.AppendLine(" "+ p.ProjectGuid.ToUpper() + "." + conf + ".Build.0 = " + mappedConf); } if (bPerformDeploy.HasValue && bPerformDeploy.Value) { o.AppendLine(" "+ p.ProjectGuid.ToUpper() + "." + conf + ".Deploy.0 = " + mappedConf); } } //for } //foreach o.AppendLine(" EndGlobalSection"); o.AppendLine(" GlobalSection(SolutionProperties) = preSolution"); o.AppendLine(" HideSolutionNode = FALSE"); o.AppendLine(" EndGlobalSection"); // // Dump project dependency hierarchy. // Project root = projects.FirstOrDefault(); if (root != null) { while (root.parent != null) { root = root.parent; } // // Flatten tree without recursion. // int treeIndex = 0; List <Project> projects2 = new List <Project>(); projects2.AddRange(root.nodes); for (; treeIndex < projects2.Count; treeIndex++) { if (projects2[treeIndex].nodes.Count == 0) { continue; } projects2.AddRange(projects2[treeIndex].nodes); } bool bDump = projects2.Count(x => x.parent.parent != null) != 0; if (bDump) { o.AppendLine(" GlobalSection(NestedProjects) = preSolution"); } foreach (Project p in projects2) { if (p.parent.parent == null) { continue; } o.AppendLine(" "+ p.ProjectGuid.ToUpper() + " = " + p.parent.ProjectGuid.ToUpper()); } if (bDump) { o.AppendLine(" EndGlobalSection"); } } //if if (SolutionGuid != null) { o.AppendLine(" GlobalSection(ExtensibilityGlobals) = postSolution"); o.AppendLine(" SolutionGuid = "+ SolutionGuid); o.AppendLine(" EndGlobalSection"); } o.AppendLine("EndGlobal"); String currentSln = ""; if (File.Exists(slnPath)) { currentSln = File.ReadAllText(slnPath); } String newSln = o.ToString(); // // Save only if needed. // if (currentSln == newSln) { uinfo.MarkFileUpdated(slnPath, false); } else { if (SolutionProjectBuilder.isDeveloper() && File.Exists(slnPath)) { File.Copy(slnPath, slnPath + ".bkp", true); } File.WriteAllText(slnPath, newSln, Encoding.UTF8); uinfo.MarkFileUpdated(slnPath, true); } //if-else } //SaveSolution