protected override void ExecuteTask() { String baseFolder = this.CreateBaseDir(); DocSet docSet = this.CreateDocSet(); IEnumerable <Framework> frameworks = this.CreateFrameworks(docSet); TextWriter writer = null; if (this.Report != null) { writer = new StreamWriter(this.Report.ToString()); } foreach (var f in frameworks) { foreach (var e in f.GetEntities()) { if (!e.name.EndsWith(".Deprecated")) { continue; } this.MarkDeprecate(baseFolder, e, writer); } } if (this.Report != null) { writer.Close(); writer.Dispose(); } }
public void TruncatedExampleWithRequiredPropertiesTest() { DocSet docSet = new DocSet(); DocFile testFile = new DocFileForTesting(Resources.ExampleValidateResponse, "\test\test.md", "test.md", docSet); ValidationError[] detectedErrors; testFile.Scan(string.Empty, out detectedErrors); Assert.IsEmpty(detectedErrors.Where(x => x.IsError)); docSet.ResourceCollection.RegisterJsonResource(testFile.Resources.First()); HttpParser parser = new HttpParser(); var testMethod = testFile.Requests.First(); var expectedResponse = parser.ParseHttpResponse(testMethod.ExpectedResponse); var actualResponse = parser.ParseHttpResponse(testMethod.ActualResponse); testMethod.ValidateResponse(actualResponse, expectedResponse, null, out detectedErrors); Assert.AreEqual(1, detectedErrors.Length); var error = detectedErrors.First(); Assert.AreEqual(ValidationErrorCode.RequiredPropertiesMissing, error.Code); }
/// <summary> /// Executes the task. /// </summary> protected override void ExecuteTask() { String baseFolder = this.CreateBaseDir(); DocSet docSet = this.CreateDocSet(); IEnumerable <Framework> frameworks = this.CreateFrameworks(docSet); foreach (var f in frameworks) { if (f.source != DocumentOrigin.Doxygen) { continue; } this.Log(Level.Info, "Copying header files for '{0}'...", f.name); FileSet fileSet = new FileSet(); fileSet.BaseDirectory = new DirectoryInfo(f.path); fileSet.Includes.Add("**/*.h"); CopyTask copyTask = new CopyTask(); copyTask.Project = this.Project; copyTask.FailOnError = true; if (docSet != null) { copyTask.ToDirectory = new DirectoryInfo(Path.Combine(baseFolder, docSet.Name, f.name, DocumentType.Source.ToString())); } else { copyTask.ToDirectory = new DirectoryInfo(Path.Combine(baseFolder, f.name, DocumentType.Source.ToString())); } copyTask.CopyFileSet = fileSet; copyTask.Filters = this.Filters; copyTask.Execute(); } }
/// <summary> /// Perform internal consistency checks on the documentation, including verify that /// code blocks have proper formatting, that resources are used properly, and that expected /// responses and examples conform to the resource definitions. /// </summary> /// <param name="options"></param> /// <param name="docs"></param> /// <returns></returns> private static async Task <bool> CheckDocsAsync(BasicCheckOptions options, DocSet docs = null) { var docset = docs ?? await GetDocSetAsync(options); if (null == docset) { return(false); } FancyConsole.WriteLine(); var resultMethods = await CheckMethodsAsync(options, docset); CheckResults resultExamples = new CheckResults(); if (string.IsNullOrEmpty(options.MethodName)) { resultExamples = await CheckExamplesAsync(options, docset); } var combinedResults = resultMethods + resultExamples; if (options.IgnoreWarnings) { combinedResults.ConvertWarningsToSuccess(); } combinedResults.PrintToConsole(); return(combinedResults.FailureCount == 0); }
/// <summary> /// Parse the command line parameters into a set of methods that match the command line parameters. /// </summary> /// <param name="options"></param> /// <param name="docset"></param> /// <returns></returns> private static MethodDefinition[] FindTestMethods(BasicCheckOptions options, DocSet docset) { MethodDefinition[] methods = null; if (!string.IsNullOrEmpty(options.MethodName)) { var foundMethod = LookUpMethod(docset, options.MethodName); if (null == foundMethod) { FancyConsole.WriteLine(FancyConsole.ConsoleErrorColor, "Unable to locate method '{0}' in docset.", options.MethodName); Exit(failure: true); } methods = new MethodDefinition[] { LookUpMethod(docset, options.MethodName) }; } else if (!string.IsNullOrEmpty(options.FileName)) { var selectedFileQuery = from f in docset.Files where f.DisplayName == options.FileName select f; var selectedFile = selectedFileQuery.SingleOrDefault(); if (selectedFile == null) { FancyConsole.WriteLine(FancyConsole.ConsoleErrorColor, "Unable to locate file '{0}' in docset.", options.FileName); Exit(failure: true); } methods = selectedFile.Requests; } else { methods = docset.Methods; } return(methods); }
/// <summary> /// Print a list of the methods (request/responses) discovered in the documentation to the console. /// </summary> /// <param name="options"></param> /// <param name="docset"></param> /// <returns></returns> private static async Task PrintMethodsAsync(DocSetOptions options, DocSet docset) { docset = docset ?? await GetDocSetAsync(options); if (null == docset) { return; } FancyConsole.WriteLine(); FancyConsole.WriteLine(FancyConsole.ConsoleHeaderColor, "Defined methods:"); FancyConsole.WriteLine(); foreach (var method in docset.Methods) { FancyConsole.WriteLine(FancyConsole.ConsoleHeaderColor, "Method '{0}' in file '{1}'", method.Identifier, method.SourceFile.DisplayName); var requestMetadata = options.EnableVerboseOutput ? JsonConvert.SerializeObject(method.RequestMetadata) : string.Empty; FancyConsole.WriteLineIndented(" ", FancyConsole.ConsoleSubheaderColor, "Request: {0}", requestMetadata); FancyConsole.WriteLineIndented(" ", FancyConsole.ConsoleCodeColor, method.Request); if (options.EnableVerboseOutput) { FancyConsole.WriteLine(); var responseMetadata = JsonConvert.SerializeObject(method.ExpectedResponseMetadata); FancyConsole.WriteLineIndented(" ", FancyConsole.ConsoleSubheaderColor, "Expected Response: {0}", responseMetadata); FancyConsole.WriteLineIndented(" ", FancyConsole.ConsoleCodeColor, method.ExpectedResponse); FancyConsole.WriteLine(); } FancyConsole.WriteLine(); } }
public void TruncatedExampleSelectStatementOnChildrenExpectFailure() { DocSet docSet = new DocSet(); DocFile testFile = new DocFileForTesting(Resources.ExampleValidationSelectStatementFailure, "\test\test.md", "test.md", docSet); ValidationError[] detectedErrors; testFile.Scan(string.Empty, out detectedErrors); Assert.IsEmpty(detectedErrors.Where(x => x.IsError)); docSet.ResourceCollection.RegisterJsonResource(testFile.Resources.First()); HttpParser parser = new HttpParser(); var testMethod = testFile.Requests.First(); var expectedResponse = parser.ParseHttpResponse(testMethod.ExpectedResponse); var actualResponse = parser.ParseHttpResponse(testMethod.ActualResponse); testMethod.ValidateResponse(actualResponse, expectedResponse, null, out detectedErrors); Assert.AreEqual(2, detectedErrors.Length); Assert.IsTrue(detectedErrors.Any(x => x.Code == ValidationErrorCode.RequiredPropertiesMissing), "Error with Code = RequiredPropertiesMissing"); Assert.IsTrue( detectedErrors.Any(x => x.Code == ValidationErrorCode.SkippedSimilarErrors), "Error with Code = SkippedSimilarErrors"); }
public DocumentPublisherHtml(DocSet docs, IPublishOptions options) : base(docs, options) { TemplateHtmlFilename = options.TemplateFilename ?? "template.htm"; HtmlOutputExtension = options.OutputExtension ?? ".htm"; EnableHtmlTagPassThrough = options.AllowUnsafeHtmlContentInMarkdown; }
/// <summary> /// Print a list of the resources detected in the documentation set to the console. /// </summary> /// <param name="options"></param> /// <param name="docset"></param> /// <returns></returns> private static async Task PrintResourcesAsync(DocSetOptions options, DocSet docset) { docset = docset ?? await GetDocSetAsync(options); if (null == docset) { return; } FancyConsole.WriteLine(); FancyConsole.WriteLine(FancyConsole.ConsoleHeaderColor, "Defined resources:"); FancyConsole.WriteLine(); var sortedResources = docset.Resources.OrderBy(x => x.ResourceType); foreach (var resource in sortedResources) { if (options.EnableVerboseOutput) { string metadata = JsonConvert.SerializeObject(resource.Metadata); FancyConsole.Write(" "); FancyConsole.Write(FancyConsole.ConsoleHeaderColor, resource.ResourceType); FancyConsole.WriteLine(" flags: {1}", resource.ResourceType, metadata); } else { FancyConsole.WriteLineIndented(" ", FancyConsole.ConsoleHeaderColor, resource.ResourceType); } FancyConsole.WriteLineIndented(" ", FancyConsole.ConsoleCodeColor, resource.JsonExample); FancyConsole.WriteLine(); } }
private static DocSet GetDocSet(Options options, IssueLogger issues) { Logger.Info("Opening documentation from {0}", options.DocsRoot); DocSet docSet = null; try { docSet = new DocSet(options.DocsRoot + "\\api-reference\\v1.0\\"); } catch (System.IO.FileNotFoundException ex) { Logger.Error(ex.Message); return(null); } Logger.Info("Parsing documentation files"); var stopwatch = new Stopwatch(); stopwatch.Start(); docSet.ScanDocumentation(string.Empty, issues); stopwatch.Stop(); Logger.Info($"Took {stopwatch.Elapsed} to parse {docSet.Files.Length} source files."); return(docSet); }
/// <summary> /// Executes the task. /// </summary> protected override void ExecuteTask() { //String baseFolder = this.CreateBaseDir (); DocSet docSet = this.CreateDocSet(); IEnumerable <Framework> frameworks = this.CreateFrameworks(docSet); TextWriter writer = null; if (this.Report != null) { writer = new StreamWriter(this.Report.ToString()); } foreach (var f in frameworks) { foreach (var e in f.GetEntities()) { this.Log(Level.Verbose, String.Format("Processing '{0}'...", e.name)); // TODO } } if (this.Report != null) { writer.Close(); writer.Dispose(); } }
protected override void ExecuteTask() { String baseFolder = this.CreateBaseDir(); DocSet docSet = this.CreateDocSet(); IEnumerable <Framework> frameworks = this.CreateFrameworks(docSet); foreach (var f in frameworks) { foreach (var e in f.GetEntities()) { if (e.Patch == null) { continue; } var replacements = e.Patch.Where(p => p.type == this.Type).SelectMany(p => p.Replace); if (replacements.Count() == 0) { continue; } this.Patch(baseFolder, e, replacements); } } }
/// <summary> /// Executes the task. /// </summary> protected override void ExecuteTask() { String baseFolder = this.CreateBaseDir(); DocSet docSet = this.CreateDocSet(); IEnumerable <Framework> frameworks = this.CreateFrameworks(docSet); foreach (var f in frameworks) { foreach (var e in f.GetEntities()) { this.Log(Level.Verbose, String.Format("Processing '{0}'...", e.name)); String sourcePath = e.GetPath(baseFolder, DocumentType.Html); String destinationPath = e.GetPath(baseFolder, DocumentType.Xhtml); if (sourcePath == null || !File.Exists(sourcePath)) { continue; } if (sourcePath.IsYoungerThan(destinationPath)) { this.Log(Level.Info, String.Format("Converting '{0}'...", e.name)); Convert(sourcePath, destinationPath); } else { this.Log(Level.Debug, String.Format("Skipping '{0}'...", e.name)); } } } }
/// <summary> /// Applies annotations to CSDL file. /// </summary> /// <param name="options">The typewriter input options.</param> /// <param name="pathToCleanMetadata">Optional. Contains the path to a clean metadata to use when applying annotations. Overrides Option.Metadata.</param> /// <returns>An annotated metadata file.</returns> internal async static Task <string> ApplyAnnotationsToCsdl(Options options, string pathToCleanMetadata = null) { DocSet docs = GetDocSet(options, new IssueLogger()); var csdlWriterOptions = new CsdlWriterOptions() { DocumentationSetPath = options.DocsRoot + "\\api-reference\\v1.0\\", Annotations = AnnotationOptions.Properties, SkipMetadataGeneration = true, Formats = MetadataFormat.EdmxInput }; // We only intend to use the source metadata when we don't pass in a CSDL. if (string.IsNullOrEmpty(pathToCleanMetadata)) { csdlWriterOptions.SourceMetadataPath = options.Metadata; } else { csdlWriterOptions.SourceMetadataPath = pathToCleanMetadata; } DocAnnotationWriter docWriter = new DocAnnotationWriter(docs, csdlWriterOptions); return(await docWriter.PublishToStringAsync(new IssueLogger())); }
protected void PatchDiscussion(String baseFolder, DocSet docSet, Framework f, FrameworkEntity entity) { String path = entity.GetPath(baseFolder, this.Type); if (path == null || !File.Exists(path)) { return; } String contents = File.ReadAllText(path); bool modified = false; // Search for discussion parts int index = 0; int beginning = 0; int ending = 0; while ((beginning = contents.IndexOf(DISCUSSION_BEGIN, index)) != -1) { ending = contents.IndexOf(DISCUSSION_END, beginning); String content = contents.Substring(beginning, ending + DISCUSSION_END.Length - beginning); String replacement = content; // Count opening and closing paragraphs int opening = DISCUSSION_OPENING_REGEX.Matches(replacement).Count; int closing = DISCUSSION_CLOSING_REGEX.Matches(replacement).Count; if (opening < closing) { throw new NotSupportedException(); } if (opening > closing) { replacement = replacement.Replace("<!-- begin discussion -->", String.Empty); replacement = replacement.Replace("<!-- end discussion -->", String.Empty); for (int i = closing; i < opening; i++) { replacement += "</p>"; } replacement = "<!-- begin discussion -->" + replacement; replacement = replacement + "<!-- end discussion -->"; contents = contents.Replace(content, replacement); modified |= true; } index = beginning + replacement.Length; } if (modified) { this.Log(Level.Info, String.Format("Patching {0} for '{1}'...", this.Type, entity.name)); File.WriteAllText(path, contents); } else { this.Log(Level.Debug, String.Format("Skipping {0} for '{1}'...", this.Type, entity.name)); } }
public DocFileForTesting(string contentsOfFile, string fullPath, string displayName, DocSet parent) : base() { this.contentsOfFile = contentsOfFile; this.FullPath = fullPath; this.DisplayName = displayName; this.Parent = parent; }
private static MethodDefinition LookUpMethod(DocSet docset, string methodName) { var query = from m in docset.Methods where m.Identifier.Equals(methodName, StringComparison.OrdinalIgnoreCase) select m; return(query.FirstOrDefault()); }
public DocumentPublisherHtml(DocSet docs, IPublishOptions options) : base(docs, options) { TemplateHtmlFilename = options.TemplateFilename ?? "template.htm"; HtmlOutputExtension = options.OutputExtension ?? ".htm"; EnableHtmlTagPassThrough = options.AllowUnsafeHtmlContentInMarkdown; PageParameters = options.PageParameterDict; }
public void EnsureDocSet() { if (docs == null) { docs = new DocSet(this.pathToDocs); docs.ScanDocumentation(String.Empty, issues); } }
public DocFile(string basePath, string relativePath, DocSet parent) : this() { this.BasePath = basePath; this.FullPath = Path.Combine(basePath, relativePath.Substring(1)); this.DisplayName = relativePath; this.Parent = parent; this.DocumentHeaders = new List<Config.DocumentHeader>(); }
public DocumentPublisherHtml(DocSet docs, IPublishOptions options) : base(docs, options) { TemplateHtmlFilename = options.TemplateFilename ?? "template.htm"; HtmlOutputExtension = options.OutputExtension ?? ".htm"; EnableHtmlTagPassThrough = options.AllowUnsafeHtmlContentInMarkdown; PageParameters = options.PageParameterDict; RespectOrderedListValues = options.RespectOrderedListValues; }
protected IEnumerable <Framework> CreateFrameworks(DocSet docSet) { List <Framework> frameworks = this.FrameworkSet.CreateFrameworks().ToList(); foreach (var f in frameworks.Where(f => f.source == DocumentOrigin.DocSet)) { f.DocSet = docSet; } return(frameworks); }
public CsdlWriter(DocSet docs, string[] namespacesToExport, string baseUrl, string preexistingEdmxFile, MetadataFormat format = MetadataFormat.Default, bool sortOutput = false) : base(docs) { this.options = new CsdlWriterOptions() { Namespaces = namespacesToExport, BaseUrl = baseUrl, SourceMetadataPath = preexistingEdmxFile, Formats = format, Sort = sortOutput }; }
static DocFile GetDocFile() { DocSet docSet = new DocSet(); DocFile testFile = new DocFileForTesting(Resources.ExampleResources, "\resources.md", "\resources.md", docSet); ValidationError[] detectedErrors; testFile.Scan(string.Empty, out detectedErrors); Assert.IsFalse(detectedErrors.WereWarningsOrErrors(), "Detected warnings or errors when reading the example markdown file."); return(testFile); }
private DocFile GetDocFileForComplexType(ComplexType testType) { string markDown = this.documentationGenerator.GetMarkDownForType(this.entityFramework, testType); DocSet docSet = new DocSet(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)); DocFile testFile = new DocFileForTesting(markDown, @"\resources.md", @"\resources.md", docSet); ValidationError[] errors = null; testFile.Scan(string.Empty, out errors); Assert.IsFalse(errors.WereWarningsOrErrors(), "Expected no validation warnings/errors: {0}", errors.ErrorsToString()); return(testFile); }
protected string RelativeUrlFromCurrentPage(DocFile docFile, string destinationFile, string rootDestinationFolder, string optionalBookmark = null) { string linkDestinationRelative = docFile.DisplayName.TrimStart(new char[] { '\\', '/' }); var relativeLinkToDocFile = DocSet.RelativePathToRootFromFile(destinationFile, Path.Combine(rootDestinationFolder, linkDestinationRelative), true); var result = this.QualifyUrl(relativeLinkToDocFile); if (optionalBookmark != null) { result += optionalBookmark; } return(result); }
public override void GetText(TextWriter writer, Dictionary <string, object> arguments, Scope context) { var filenameToReplace = arguments["filename"] as string; if (null != filenameToReplace) { var relativeFileUrl = DocSet.RelativePathToRootFromFile( this.DestinationFile, Path.Combine(this.RootDestinationFolder, filenameToReplace), true); writer.Write(relativeFileUrl); } }
static DocFile GetDocFile() { DocSet docSet = new DocSet(); DocFile testFile = new DocFileForTesting(Resources.ExampleResources, "resources.md", "resources.md", docSet); var issues = new IssueLogger(); testFile.Scan(string.Empty, issues); Assert.IsFalse(issues.Issues.WereWarningsOrErrors(), "Detected warnings or errors when reading the example markdown file."); return(testFile); }
private DocFile GetDocFileForComplexType(ComplexType testType) { string markDown = this.documentationGenerator.GetMarkDownForType(this.entityFramework, testType); DocSet docSet = new DocSet(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)); DocSet.SchemaConfig.DefaultNamespace = "microsoft.graph"; DocFile testFile = new DocFileForTesting(markDown, @"\resources.md", @"\resources.md", docSet); var issues = new IssueLogger(); testFile.Scan(string.Empty, issues.For("testFile")); Assert.IsFalse(issues.Issues.WereWarningsOrErrors(), "Expected no validation warnings/errors: {0}", issues.Issues.ErrorsToString()); return(testFile); }
protected DocumentPublisher(DocSet docset, IPublishOptions options = null) { this.Documents = docset; this.Options = options ?? new DefaultPublishOptions(); this.RootPath = new DirectoryInfo(docset.SourceFolderPath).FullName; if (!this.RootPath.EndsWith(Path.DirectorySeparatorChar.ToString())) this.RootPath = string.Concat(this.RootPath, Path.DirectorySeparatorChar); this.SourceFileExtensions = ".md,.mdown"; this.SkipPaths = "\\.git;\\.gitignore;\\.gitattributes"; this.OutputLineEndings = LineEndings.Default; this.Messages = new BindingList<ValidationError>(); }
private static HttpRequest HttpRequestForCannedRequest(string requestName, DocSet docset) { var queryForRequest = from m in docset.CannedRequests where m.Name == requestName select m; var foundRequest = queryForRequest.FirstOrDefault(); if (null == foundRequest) { throw new Exception(string.Format("Failed to find canned response {0} in the docset.", requestName)); } return(GetHttpRequest(foundRequest, docset)); }
/// <summary> /// Executes the task. /// </summary> protected override void ExecuteTask() { if (!this.DoxygenBinary.Exists) { this.Log(Level.Error, "Doxygen cannot be found."); return; } String baseFolder = this.CreateBaseDir(); DocSet docSet = this.CreateDocSet(); IEnumerable <Framework> frameworks = this.CreateFrameworks(docSet); foreach (var f in frameworks) { if (f.source != DocumentOrigin.Doxygen) { continue; } String configuration; if (docSet != null) { configuration = Path.Combine(baseFolder, docSet.Name, f.name, "doxygen.cfg"); } else { configuration = Path.Combine(baseFolder, f.name, "doxygen.cfg"); } if (File.Exists(configuration)) { continue; } this.Log(Level.Info, "Generating Doxygen files for '{0}'...", f.name); ExportConfiguration(configuration); ExecTask execTask = new ExecTask(); execTask.Project = this.Project; execTask.FailOnError = true; execTask.FileName = this.DoxygenBinary.ToString(); execTask.CommandLineArguments = Path.GetFileName(configuration); execTask.WorkingDirectory = new DirectoryInfo(Path.GetDirectoryName(configuration)); execTask.Execute(); GenerateDescriptor(baseFolder, f); } }
public async Task <string> PublishToStringAsync(IssueLogger issues) { string outputFilenameSuffix = ""; Logger.Info("Begin creating metadata file with documentation annotations."); // Step 1: Generate an EntityFramework OM from the documentation and/or template file EntityFramework framework = CreateEntityFrameworkFromDocs(issues); if (null == framework) { return(string.Empty); } // Step 1a: Apply an transformations that may be defined in the documentation if (!string.IsNullOrEmpty(options.TransformOutput)) { PublishSchemaChangesConfigFile transformations = DocSet.TryLoadConfigurationFiles <PublishSchemaChangesConfigFile>(options.DocumentationSetPath).Where(x => x.SchemaChanges.TransformationName == options.TransformOutput).FirstOrDefault(); if (null == transformations) { throw new KeyNotFoundException($"Unable to locate a transformation set named {options.TransformOutput}. Aborting."); } string[] versionsToPublish = options.Version?.Split(new char[] { ',', ' ' }); framework.ApplyTransformation(transformations.SchemaChanges, versionsToPublish); if (!string.IsNullOrEmpty(options.Version)) { outputFilenameSuffix += $"-{options.Version}"; } } if (options.Sort) { // Sorts the objects in collections, so that we have consistent output regardless of input framework.SortObjectGraph(); } if (options.ValidateSchema) { framework.ValidateSchemaTypes(); } // Step 2: Generate XML representation of EDMX string xmlData = ODataParser.Serialize <EntityFramework>(framework, options.AttributesOnNewLines); Logger.Info("Finish creating metadata file with documentation annotations."); return(xmlData); }
/// <summary> /// Apply the HTML template to the parameters and write the file to the destination. /// </summary> /// <param name="bodyHtml"></param> /// <param name="page"></param> /// <param name="destinationFile"></param> /// <param name="rootDestinationFolder"></param> /// <returns></returns> protected virtual async Task WriteHtmlDocumentAsync(string bodyHtml, DocFile page, string destinationFile, string rootDestinationFolder) { List <string> variablesToReplace = new List <string>(); string pageHtml = null; if (this.TemplateHtml != null) { var matches = ExtensionMethods.PathVariableRegex.Matches(this.TemplateHtml); variablesToReplace.AddRange(from Match match in matches select match.Groups[0].Value); string templateHtmlForThisPage = this.TemplateHtml; foreach (var key in variablesToReplace.ToArray()) { if (key == "{page.title}") { templateHtmlForThisPage = templateHtmlForThisPage.Replace(key, page.Annotation.Title); } else if (key == "{body.html}") { templateHtmlForThisPage = templateHtmlForThisPage.Replace(key, bodyHtml); } else if (key.StartsWith("{if ")) { string value = this.ParseDocumentIfStatement(key, destinationFile); templateHtmlForThisPage = templateHtmlForThisPage.Replace(key, value); } else { string filename = key.Substring(1, key.Length - 2); string value = DocSet.RelativePathToRootFromFile(destinationFile, Path.Combine(rootDestinationFolder, filename), true); templateHtmlForThisPage = templateHtmlForThisPage.Replace(key, value); } } pageHtml = templateHtmlForThisPage; } else { pageHtml = string.Concat(string.Format(HtmlHeader, page.Annotation.Title, HtmlStyles), bodyHtml, HtmlFooter); } pageHtml = await this.ConvertLineEndingsAsync(pageHtml, this.OutputLineEndings); using (var outputWriter = new StreamWriter(destinationFile)) { await outputWriter.WriteAsync(pageHtml); } }
/// <summary> /// Locate the Http.HttpRequest instance for this request definition either by /// parsing the RawHttpRequest or resolving MethodName into a request. /// </summary> /// <param name="definition"></param> /// <param name="documents"></param> /// <returns></returns> public static HttpRequest GetHttpRequest(this BasicRequestDefinition definition, DocSet documents) { HttpRequest foundRequest = null; if (!string.IsNullOrEmpty(definition.RawHttpRequest)) { foundRequest = ParseHttpRequest(definition.RawHttpRequest); } else if (!string.IsNullOrEmpty(definition.MethodName)) { foundRequest = LookupHttpRequestForMethod(definition.MethodName, documents); } else if (!string.IsNullOrEmpty(definition.CannedRequestName)) { foundRequest = HttpRequestForCannedRequest(definition.CannedRequestName, documents); } return foundRequest; }
private static HttpRequest HttpRequestForCannedRequest(string requestName, DocSet docset) { var queryForRequest = from m in docset.CannedRequests where m.Name == requestName select m; var foundRequest = queryForRequest.FirstOrDefault(); if (null == foundRequest) { throw new Exception(string.Format("Failed to find canned response {0} in the docset.", requestName)); } return GetHttpRequest(foundRequest, docset); }
public MarkdownPublisher(DocSet docset) : base (docset) { this.SourceFileExtensions = ".md,.mdown"; this.SkipPaths = "\\internal;\\.git;\\legacy;\\generate_html_docs;\\.gitignore;\\.gitattributes"; }
public DocumentPublisherHtml(DocSet docs, IPublishOptions options) : base(docs, options) { TemplateHtmlFilename = options.TemplateFilename ?? "template.htm"; HtmlOutputExtension = options.OutputExtension ?? ".htm"; }
/// <summary> /// Make a call to the HttpRequest and populate the Value property of /// every PlaceholderValue in Values based on the result. /// </summary> /// <param name="storedValues"></param> /// <param name="documents"></param> /// <param name="scenario"></param> /// <param name="account"></param> /// <param name="parentOutputValues"></param> /// <returns></returns> public async Task<ValidationResult<bool>> MakeSetupRequestAsync(Dictionary<string, string> storedValues, DocSet documents, ScenarioDefinition scenario, IServiceAccount account, Dictionary<string, string> parentOutputValues = null) { // Copy the output values from parentOutputValues into our own if (null != parentOutputValues) { foreach (var key in parentOutputValues.Keys) { this.OutputValues.Add(key, parentOutputValues[key]); } } var errors = new List<ValidationError>(); if (!string.IsNullOrEmpty(this.CannedRequestName)) { // We need to make a canned request setup request instead. Look up the canned request and then execute it, returning the results here. var cannedRequest = (from cr in documents.CannedRequests where cr.Name == this.CannedRequestName select cr) .FirstOrDefault(); if (null == cannedRequest) { errors.Add(new ValidationError(ValidationErrorCode.InvalidRequestFormat, null, "Couldn't locate the canned-request named: {0}", this.CannedRequestName)); return new ValidationResult<bool>(false, errors); } // Need to make a copy of the canned request here so that our state doesn't continue to pile up var cannedRequestInstance = cannedRequest.CopyInstance(); return await cannedRequestInstance.MakeSetupRequestAsync(storedValues, documents, scenario, account, this.OutputValues); } // Get the HttpRequest, either from MethodName or by parsing HttpRequest HttpRequest request; try { request = this.GetHttpRequest(documents); } catch (Exception ex) { errors.Add(new ValidationError(ValidationErrorCode.InvalidRequestFormat, null, "An error occured creating the http request: {0}", ex.Message)); return new ValidationResult<bool>(false, errors); } MethodDefinition.AddTestHeaderToRequest(scenario, request); MethodDefinition.AddAdditionalHeadersToRequest(account, request); // If this is a canned request, we need to merge the parameters / placeholders here var placeholderValues = this.RequestParameters.ToPlaceholderValuesArray(storedValues); // Update the request with the parameters in request-parameters try { request.RewriteRequestWithParameters(placeholderValues); } catch (Exception ex) { errors.Add(new ValidationError(ValidationErrorCode.ParameterParserError, SourceName, "Error rewriting the request with parameters from the scenario: {0}", ex.Message)); return new ValidationResult<bool>(false, errors); } MethodDefinition.AddAccessTokenToRequest(account.CreateCredentials(), request); errors.Add(new ValidationMessage(null, "Test-setup request:\n{0}", request.FullHttpText())); try { var response = await request.GetResponseAsync(account.BaseUrl); if (response.RetryCount > 0) { errors.Add(new ValidationWarning(ValidationErrorCode.RequestWasRetried, null, "HTTP request was retried {0} times.", response.RetryCount)); } errors.Add(new ValidationMessage(null, "HTTP Response:\n{0}\n\n", response.FullText())); // Check to see if this request is "successful" or not if ( (this.AllowedStatusCodes == null && response.WasSuccessful) || (this.AllowedStatusCodes != null && this.AllowedStatusCodes.Contains(response.StatusCode))) { string expectedContentType = (null != this.OutputValues) ? ExpectedResponseContentType(this.OutputValues.Values) : null; // Check for content type mismatch if (string.IsNullOrEmpty(response.ContentType) && expectedContentType != null) { return new ValidationResult<bool>(false, new ValidationError(ValidationErrorCode.UnsupportedContentType, SourceName, "No Content-Type found for a non-204 response")); } // Load requested values into stored values if (null != this.OutputValues) { foreach (var outputKey in this.OutputValues.Keys) { var source = this.OutputValues[outputKey]; storedValues[outputKey] = response.ValueForKeyedIdentifier(source); } } return new ValidationResult<bool>(!errors.Any(x => x.IsError), errors); } else { if ((this.AllowedStatusCodes != null && !this.AllowedStatusCodes.Contains(response.StatusCode)) || !response.WasSuccessful) { string expectedCodes = "200-299"; if (this.AllowedStatusCodes != null) expectedCodes = this.AllowedStatusCodes.ComponentsJoinedByString(","); errors.Add(new ValidationError(ValidationErrorCode.HttpStatusCodeDifferent, SourceName, "Http response status code {0} didn't match expected values: {1}", response.StatusCode, expectedCodes)); } else { errors.Add(new ValidationError(ValidationErrorCode.HttpStatusCodeDifferent, SourceName, "Http response content type was invalid: {0}", response.ContentType)); } return new ValidationResult<bool>(false, errors); } } catch (Exception ex) { errors.Add(new ValidationError(ValidationErrorCode.Unknown, SourceName, "Exception while making request: {0}", ex.Message)); return new ValidationResult<bool>(false, errors); } }
public void TruncatedExampleSelectStatementOnChildrenExpectFailure() { DocSet docSet = new DocSet(); DocFile testFile = new DocFileForTesting(Resources.ExampleValidationSelectStatementFailure, "\test\test.md", "test.md", docSet); ValidationError[] detectedErrors; testFile.Scan(string.Empty, out detectedErrors); Assert.IsEmpty(detectedErrors.Where(x => x.IsError)); docSet.ResourceCollection.RegisterJsonResource(testFile.Resources.First()); HttpParser parser = new HttpParser(); var testMethod = testFile.Requests.First(); var expectedResponse = parser.ParseHttpResponse(testMethod.ExpectedResponse); var actualResponse = parser.ParseHttpResponse(testMethod.ActualResponse); testMethod.ValidateResponse(actualResponse, expectedResponse, null, out detectedErrors); Assert.AreEqual(2, detectedErrors.Length); Assert.IsTrue(detectedErrors.Any(x => x.Code == ValidationErrorCode.RequiredPropertiesMissing), "Error with Code = RequiredPropertiesMissing"); Assert.IsTrue( detectedErrors.Any(x => x.Code == ValidationErrorCode.SkippedSimilarErrors), "Error with Code = SkippedSimilarErrors"); }
public void TruncatedExampleWithRequiredPropertiesTest() { DocSet docSet = new DocSet(); DocFile testFile = new DocFileForTesting(Resources.ExampleValidateResponse, "\test\test.md", "test.md", docSet); ValidationError[] detectedErrors; testFile.Scan(string.Empty, out detectedErrors); Assert.IsEmpty(detectedErrors.Where(x => x.IsError)); docSet.ResourceCollection.RegisterJsonResource(testFile.Resources.First()); HttpParser parser = new HttpParser(); var testMethod = testFile.Requests.First(); var expectedResponse = parser.ParseHttpResponse(testMethod.ExpectedResponse); var actualResponse = parser.ParseHttpResponse(testMethod.ActualResponse); testMethod.ValidateResponse(actualResponse, expectedResponse, null, out detectedErrors); Assert.AreEqual(1, detectedErrors.Length); var error = detectedErrors.First(); Assert.AreEqual(ValidationErrorCode.RequiredPropertiesMissing, error.Code); }
private static HttpRequest LookupHttpRequestForMethod(string methodName, DocSet docset) { var queryForMethod = from m in docset.Methods where m.Identifier == methodName select m; var foundMethod = queryForMethod.FirstOrDefault(); if (null == foundMethod) { throw new Exception(string.Format("Failed to locate method {0} in the docset.", methodName)); } return ParseHttpRequest(foundMethod.Request); }
static DocFile GetDocFile() { DocSet docSet = new DocSet(); DocFile testFile = new DocFileForTesting(Resources.ExampleResources, "\resources.md", "\resources.md", docSet); ValidationError[] detectedErrors; testFile.Scan(string.Empty, out detectedErrors); Assert.IsFalse(detectedErrors.WereWarningsOrErrors(), "Detected warnings or errors when reading the example markdown file."); return testFile; }
/// <summary> /// Take a scenario definition and convert the prototype request into a fully formed request. This includes appending /// the base URL to the request URL, executing any test-setup requests, and replacing the placeholders in the prototype /// request with proper values. /// </summary> /// <param name="scenario"></param> /// <param name="documents"></param> /// <param name="account"></param> /// <returns></returns> public async Task<ValidationResult<HttpRequest>> GenerateMethodRequestAsync(ScenarioDefinition scenario, DocSet documents, IServiceAccount account) { var parser = new HttpParser(); var request = parser.ParseHttpRequest(this.Request); AddAccessTokenToRequest(account.CreateCredentials(), request); AddTestHeaderToRequest(scenario, request); AddAdditionalHeadersToRequest(account, request); List<ValidationError> errors = new List<ValidationError>(); if (null != scenario) { var storedValuesForScenario = new Dictionary<string, string>(); if (null != scenario.TestSetupRequests) { foreach (var setupRequest in scenario.TestSetupRequests) { var result = await setupRequest.MakeSetupRequestAsync(storedValuesForScenario, documents, scenario, account); errors.AddRange(result.Messages); if (result.IsWarningOrError) { // If we can an error or warning back from a setup method, we fail the whole request. return new ValidationResult<HttpRequest>(null, errors); } } } try { var placeholderValues = scenario.RequestParameters.ToPlaceholderValuesArray(storedValuesForScenario); request.RewriteRequestWithParameters(placeholderValues); } catch (Exception ex) { // Error when applying parameters to the request errors.Add( new ValidationError( ValidationErrorCode.RewriteRequestFailure, "GenerateMethodRequestAsync", ex.Message)); return new ValidationResult<HttpRequest>(null, errors); } if (scenario.StatusCodesToRetry != null) { request.RetryOnStatusCode = (from status in scenario.StatusCodesToRetry select (System.Net.HttpStatusCode)status).ToList(); } } if (string.IsNullOrEmpty(request.Accept)) { if (!string.IsNullOrEmpty(ValidationConfig.ODataMetadataLevel)) { request.Accept = MimeTypeJson + "; " + ValidationConfig.ODataMetadataLevel; } else { request.Accept = MimeTypeJson; } } return new ValidationResult<HttpRequest>(request, errors); }