/// <summary> /// Validates a session xml document. /// </summary> /// <param name="xdoc"></param> public static void ValidateSessionXml(XDocument xdoc, ValidationEventHandler validationHandler = null) { // First, make sure it's a testcase if (xdoc == null) { throw new ArgumentNullException("xdoc"); } if (xdoc.Root == null) { throw new ArgumentException("Xml document doesn't contain a root element.", "xdoc"); } if (xdoc.Root.Name != XSessionNames.Session) { throw new ArgumentException(String.Format("The root element should be \"{0}\" but is \"{1}\".", XSessionNames.Session, xdoc.Root.Name)); } XmlSchemaSet schemaSet = new XmlSchemaSet(); schemaSet.Add(UnitTestingSchemaUtil.GetConcurrencySchema()); schemaSet.Add(UnitTestingSchemaUtil.GetTestListSchema()); schemaSet.Add(UnitTestingSchemaUtil.GetChessSchema()); schemaSet.Add(XSessionUtil.GetSessionSchema()); schemaSet.Compile(); xdoc.Validate(schemaSet, validationHandler); }
/// <summary> /// Checks to see if a test result file exists and validates it. /// </summary> /// <param name="resultFilePath"></param> /// <returns> /// null if the result file doesn't exist; otherwise, a valid test result element. /// If the result file is invalid or could not be loaded properly, then an error result /// element is returned specifying the information. /// </returns> public static XElement CheckForResultFile(string resultFilePath) { if (!File.Exists(resultFilePath)) { return(null); } try { XDocument xdoc = XDocument.Load(resultFilePath); UnitTestingSchemaUtil.ValidateTestResultXml(xdoc); XElement xresult = xdoc.Root; xresult.Remove(); return(xresult); } catch (IOException ex) { // Sometimes, the file exists but is still being written and when we try to // open it, we get an IOException. Try to detect this specific case and then // return null so it can be looked for later. if (ex.Message.StartsWith("The process cannot access the file ", StringComparison.OrdinalIgnoreCase) && ex.Message.EndsWith(" because it is being used by another process.", StringComparison.OrdinalIgnoreCase) ) { //Console.WriteLine("Exception caught and ignored: {0}", ex.Message); return(null); } else // Otherwise, just report an error { return(TestResultUtil.CreateErrorXTestResult(ex)); } } catch (System.Xml.Schema.XmlSchemaValidationException ex) { return(TestResultUtil.CreateErrorXTestResult("Invalid test result xml: " + ex.Message)); } catch (System.Xml.XmlException ex) { return(TestResultUtil.CreateErrorXTestResult("Invalid test result xml: " + ex.Message)); } catch (Exception ex) { return(TestResultUtil.CreateErrorXTestResult(ex)); } }
/// <summary> /// Reads the test case xml from the file. If not specified, reads the xml from Console.In. /// </summary> /// <param name="testCaseFilePath"></param> /// <returns></returns> internal bool LoadTestCase(string testCaseFilePath) { // Read the test case xml XDocument testCaseXDoc = null; if (!String.IsNullOrEmpty(testCaseFilePath)) { try { testCaseXDoc = XDocument.Load(testCaseFilePath); } catch (Exception ex) { Error = "Could not load test case description file."; ErrorEx = ex; return(false); } } else { try { testCaseXDoc = XDocument.Load(Console.In); } catch (Exception ex) { Error = "Could not load test case description from the standard input stream."; ErrorEx = ex; return(false); } } //Validate the xml try { UnitTestingSchemaUtil.ValidateTestCaseXml(testCaseXDoc); } catch (Exception ex) { Error = "Invalid test case xml: " + ex.Message; return(false); } // Create the RunningTestCase instance try { metadata = new TestCaseMetadata(testCaseXDoc.Root); testController = CreateTestController(metadata.TestTypeName); if (testController == null) { return(false); } runner = testController.CreateRunner(); if (runner == null) { Error = testController.GetType().Name + ".CreateRunner didn't return a runner instance."; return(false); } } catch (Exception ex) { Error = "Error with test case."; ErrorEx = ex; return(false); } return(Error == null); }
// load document /// <summary> /// Loads the test container file. /// Always returns a non-null value, or else an exception is thrown. /// </summary> /// <param name="filename"></param> /// <param name="recursively"></param> /// <returns></returns> public static XElement LoadTestContainer(string filename, bool recursively) { // Normalize the path. string filePath = Path.GetFullPath(filename); XDocument doc; switch (Path.GetExtension(filePath).ToLower()) { case ".exe": case ".dll": doc = ReadTestContainerInSeperateProcess(filePath); if (doc.Root.Name == XNames.Error) { System.Diagnostics.Trace.WriteLine(doc.Root, "Error reading test assembly"); throw new Exception((string)doc.Root.Element(XNames.ErrorMessage)); } break; case ".csproj": if (!File.Exists(filePath)) { throw new Exception("can not load test project. \"" + filePath + "\" does not exist."); } // Create a new project entity xml with just the information we know. doc = new XDocument( new XElement(XNames.TestProject , new XAttribute(XNames.ALocation, filePath) // Loaded after attaching to a session //, MSBuild.MSBuildProject.ParseProjectFileToXElement(filePath) )); break; default: if (!File.Exists(filePath)) { throw new Exception("can not load testlist. \"" + filePath + "\" does not exist."); } doc = XDocument.Load(filePath, LoadOptions.SetLineInfo); break; } // Validate the test container xml try { UnitTestingSchemaUtil.ValidateTestListXml(doc); } catch (Exception ex) { throw new Exception("Invalid test container \"" + filePath + "\"." + ex.Message); } // detach from the document XElement xroot = doc.Root; xroot.Remove(); // For testlists that we load from the file system, allow them to be reloaded if (xroot.Name == XNames.Testlist) { xroot.SetAttributeValue(XNames.ALocation, filePath); // Always update just in case the file was moved from the current value } // replace @ character with directory string folderPath = Path.GetDirectoryName(filePath); foreach (XElement x in xroot.Descendants()) { if (x.Name == XNames.Executable || x.Name == XNames.WorkingDirectory || x.Name == XNames.Shellline || x.Name == XNames.Arg ) { string v = x.Value; if (v.Contains('@')) { x.Value = Path.GetFullPath(v.Replace("@", folderPath)); } } else if (x.Name == XNames.Include || x.Name == XNames.TestProject ) { XAttribute xloc = x.Attribute(XNames.ALocation); string v = xloc.Value; if (v.Contains('@')) { xloc.Value = Path.GetFullPath(v.Replace("@", folderPath)); } } foreach (XAttribute a in x.Attributes().Where(a => a.Name == XNames.AObservationFile || a.Name == XNames.AProject )) { string v = a.Value; if (v.Contains('@')) { a.Value = Path.GetFullPath(v.Replace("@", folderPath)); } } } if (recursively) { // replace <include location="filename"/> with contents XElement[] includes = xroot.Descendants(XNames.Include).ToArray(); foreach (XElement xinclude in includes) { // We've already fully resolved the location attribute to it's full path above string loc = (string)xinclude.Attribute(XNames.ALocation); try { var xcontainer = LoadTestContainer(loc, recursively); MergeInSettingsFromInclude(xcontainer, xinclude); xinclude.ReplaceWith(xcontainer); } catch (Exception ex) { xinclude.Add(XConcurrencyNames.CreateXError("Error trying to load included test container: " + ex.Message)); } } } return(xroot); }