| 
 | 1 | +// Licensed to Elasticsearch B.V under one or more agreements.  | 
 | 2 | +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.  | 
 | 3 | +// See the LICENSE file in the project root for more information  | 
 | 4 | + | 
 | 5 | +namespace authoring  | 
 | 6 | + | 
 | 7 | +open System  | 
 | 8 | +open System.Diagnostics  | 
 | 9 | +open System.IO  | 
 | 10 | +open AngleSharp.Diffing  | 
 | 11 | +open AngleSharp.Diffing.Core  | 
 | 12 | +open AngleSharp.Html  | 
 | 13 | +open AngleSharp.Html.Parser  | 
 | 14 | +open DiffPlex.DiffBuilder  | 
 | 15 | +open DiffPlex.DiffBuilder.Model  | 
 | 16 | +open JetBrains.Annotations  | 
 | 17 | +open Xunit.Sdk  | 
 | 18 | + | 
 | 19 | +[<AutoOpen>]  | 
 | 20 | +module HtmlAssertions =  | 
 | 21 | + | 
 | 22 | +    let htmlDiffString (diffs: seq<IDiff>) =  | 
 | 23 | +        let NodeName (source:ComparisonSource) = source.Node.NodeType.ToString().ToLowerInvariant();  | 
 | 24 | +        let htmlText (source:IDiff) =  | 
 | 25 | +            let formatter = PrettyMarkupFormatter();  | 
 | 26 | +            let nodeText (control: ComparisonSource) =  | 
 | 27 | +                use sw = new StringWriter()  | 
 | 28 | +                control.Node.ToHtml(sw, formatter)  | 
 | 29 | +                sw.ToString()  | 
 | 30 | +            let attrText (control: AttributeComparisonSource) =  | 
 | 31 | +                use sw = new StringWriter()  | 
 | 32 | +                control.Attribute.ToHtml(sw, formatter)  | 
 | 33 | +                sw.ToString()  | 
 | 34 | +            let nodeDiffText (control: ComparisonSource option) (test: ComparisonSource option) =  | 
 | 35 | +                let actual = match test with Some t -> nodeText t | None -> "missing"  | 
 | 36 | +                let expected = match control with Some t -> nodeText t | None -> "missing"  | 
 | 37 | +                $"""  | 
 | 38 | +
  | 
 | 39 | +expected: {expected}  | 
 | 40 | +actual: {actual}  | 
 | 41 | +"""  | 
 | 42 | +            let attrDiffText (control: AttributeComparisonSource option) (test: AttributeComparisonSource option) =  | 
 | 43 | +                let actual = match test with Some t -> attrText t | None -> "missing"  | 
 | 44 | +                let expected = match control with Some t -> attrText t | None -> "missing"  | 
 | 45 | +                $"""  | 
 | 46 | +
  | 
 | 47 | +expected: {expected}  | 
 | 48 | +actual: {actual}  | 
 | 49 | +"""  | 
 | 50 | + | 
 | 51 | +            match source with  | 
 | 52 | +            | :? NodeDiff as diff -> nodeDiffText <| Some diff.Control <| Some diff.Test  | 
 | 53 | +            | :? AttrDiff as diff -> attrDiffText <| Some diff.Control <| Some diff.Test  | 
 | 54 | +            | :? MissingNodeDiff as diff -> nodeDiffText <| Some diff.Control <| None  | 
 | 55 | +            | :? MissingAttrDiff as diff -> attrDiffText <| Some diff.Control <| None  | 
 | 56 | +            | :? UnexpectedNodeDiff as diff -> nodeDiffText None <| Some diff.Test  | 
 | 57 | +            | :? UnexpectedAttrDiff as diff -> attrDiffText None <| Some diff.Test  | 
 | 58 | +            | _ -> failwith $"Unknown diff type detected: {source.GetType()}"  | 
 | 59 | + | 
 | 60 | +        diffs  | 
 | 61 | +        |> Seq.map (fun diff ->  | 
 | 62 | + | 
 | 63 | +            match diff with  | 
 | 64 | +            | :? NodeDiff as diff when diff.Target = DiffTarget.Text && diff.Control.Path.Equals(diff.Test.Path, StringComparison.Ordinal)  | 
 | 65 | +                -> $"The text in {diff.Control.Path} is different."  | 
 | 66 | +            | :? NodeDiff as diff when diff.Target = DiffTarget.Text  | 
 | 67 | +                -> $"The expected {NodeName(diff.Control)} at {diff.Control.Path} and the actual {NodeName(diff.Test)} at {diff.Test.Path} is different."  | 
 | 68 | +            | :? NodeDiff as diff when diff.Control.Path.Equals(diff.Test.Path, StringComparison.Ordinal)  | 
 | 69 | +                -> $"The {NodeName(diff.Control)}s at {diff.Control.Path} are different."  | 
 | 70 | +            | :? NodeDiff as diff -> $"The expected {NodeName(diff.Control)} at {diff.Control.Path} and the actual {NodeName(diff.Test)} at {diff.Test.Path} are different."  | 
 | 71 | +            | :? AttrDiff as diff when diff.Control.Path.Equals(diff.Test.Path, StringComparison.Ordinal)  | 
 | 72 | +                -> $"The values of the attributes at {diff.Control.Path} are different."  | 
 | 73 | +            | :? AttrDiff as diff -> $"The value of the attribute {diff.Control.Path} and actual attribute {diff.Test.Path} are different."  | 
 | 74 | +            | :? MissingNodeDiff as diff -> $"The {NodeName(diff.Control)} at {diff.Control.Path} is missing."  | 
 | 75 | +            | :? MissingAttrDiff as diff -> $"The attribute at {diff.Control.Path} is missing."  | 
 | 76 | +            | :? UnexpectedNodeDiff as diff -> $"The {NodeName(diff.Test)} at {diff.Test.Path} was not expected."  | 
 | 77 | +            | :? UnexpectedAttrDiff as diff -> $"The attribute at {diff.Test.Path} was not expected."  | 
 | 78 | +            | _ -> failwith $"Unknown diff type detected: {diff.GetType()}"  | 
 | 79 | +            +  | 
 | 80 | +            htmlText diff  | 
 | 81 | +        )  | 
 | 82 | +        |> String.concat "\n"  | 
 | 83 | + | 
 | 84 | +    let private prettyHtml (html:string) =  | 
 | 85 | +        let parser = HtmlParser()  | 
 | 86 | +        let document = parser.ParseDocument(html)  | 
 | 87 | +        use sw = new StringWriter()  | 
 | 88 | +        document.Body.Children  | 
 | 89 | +        |> Seq.iter _.ToHtml(sw, PrettyMarkupFormatter())  | 
 | 90 | +        sw.ToString()  | 
 | 91 | + | 
 | 92 | +    [<DebuggerStepThrough>]  | 
 | 93 | +    let convertsToHtml ([<LanguageInjection("html")>]expected: string) (actual: GenerateResult) =  | 
 | 94 | +        let diffs =  | 
 | 95 | +            DiffBuilder  | 
 | 96 | +                .Compare(actual.Html)  | 
 | 97 | +                .WithTest(expected)  | 
 | 98 | +                .Build()  | 
 | 99 | + | 
 | 100 | +        let diff = htmlDiffString diffs  | 
 | 101 | +        match diff with  | 
 | 102 | +        | s when String.IsNullOrEmpty s -> ()  | 
 | 103 | +        | s ->  | 
 | 104 | +            let expectedHtml = prettyHtml expected  | 
 | 105 | +            let actualHtml = prettyHtml actual.Html  | 
 | 106 | +            let textDiff =  | 
 | 107 | +                InlineDiffBuilder.Diff(expectedHtml, actualHtml).Lines  | 
 | 108 | +                |> Seq.map(fun l ->  | 
 | 109 | +                    match l.Type with  | 
 | 110 | +                    | ChangeType.Deleted -> "- " + l.Text  | 
 | 111 | +                    | ChangeType.Modified -> "+ " + l.Text  | 
 | 112 | +                    | ChangeType.Inserted -> "+ " + l.Text  | 
 | 113 | +                    | _ -> " " + l.Text  | 
 | 114 | +                )  | 
 | 115 | +                |> String.concat "\n"  | 
 | 116 | +            let msg = $"""Html was not equal  | 
 | 117 | +{textDiff}  | 
 | 118 | +
  | 
 | 119 | +{diff}  | 
 | 120 | +"""  | 
 | 121 | +            raise (XunitException(msg))  | 
 | 122 | + | 
 | 123 | + | 
0 commit comments