golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/html/render_test.go (about)

     1  // Copyright 2010 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package html
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"strings"
    11  	"testing"
    12  )
    13  
    14  func TestRenderer(t *testing.T) {
    15  	nodes := [...]*Node{
    16  		0: {
    17  			Type: ElementNode,
    18  			Data: "html",
    19  		},
    20  		1: {
    21  			Type: ElementNode,
    22  			Data: "head",
    23  		},
    24  		2: {
    25  			Type: ElementNode,
    26  			Data: "body",
    27  		},
    28  		3: {
    29  			Type: TextNode,
    30  			Data: "0<1",
    31  		},
    32  		4: {
    33  			Type: ElementNode,
    34  			Data: "p",
    35  			Attr: []Attribute{
    36  				{
    37  					Key: "id",
    38  					Val: "A",
    39  				},
    40  				{
    41  					Key: "foo",
    42  					Val: `abc"def`,
    43  				},
    44  			},
    45  		},
    46  		5: {
    47  			Type: TextNode,
    48  			Data: "2",
    49  		},
    50  		6: {
    51  			Type: ElementNode,
    52  			Data: "b",
    53  			Attr: []Attribute{
    54  				{
    55  					Key: "empty",
    56  					Val: "",
    57  				},
    58  			},
    59  		},
    60  		7: {
    61  			Type: TextNode,
    62  			Data: "3",
    63  		},
    64  		8: {
    65  			Type: ElementNode,
    66  			Data: "i",
    67  			Attr: []Attribute{
    68  				{
    69  					Key: "backslash",
    70  					Val: `\`,
    71  				},
    72  			},
    73  		},
    74  		9: {
    75  			Type: TextNode,
    76  			Data: "&4",
    77  		},
    78  		10: {
    79  			Type: TextNode,
    80  			Data: "5",
    81  		},
    82  		11: {
    83  			Type: ElementNode,
    84  			Data: "blockquote",
    85  		},
    86  		12: {
    87  			Type: ElementNode,
    88  			Data: "br",
    89  		},
    90  		13: {
    91  			Type: TextNode,
    92  			Data: "6",
    93  		},
    94  		14: {
    95  			Type: CommentNode,
    96  			Data: "comm",
    97  		},
    98  		15: {
    99  			Type: CommentNode,
   100  			Data: "x-->y", // Needs escaping.
   101  		},
   102  		16: {
   103  			Type: RawNode,
   104  			Data: "7<pre>8</pre>9",
   105  		},
   106  	}
   107  
   108  	// Build a tree out of those nodes, based on a textual representation.
   109  	// Only the ".\t"s are significant. The trailing HTML-like text is
   110  	// just commentary. The "0:" prefixes are for easy cross-reference with
   111  	// the nodes array.
   112  	treeAsText := [...]string{
   113  		0:  `<html>`,
   114  		1:  `.	<head>`,
   115  		2:  `.	<body>`,
   116  		3:  `.	.	"0&lt;1"`,
   117  		4:  `.	.	<p id="A" foo="abc&#34;def">`,
   118  		5:  `.	.	.	"2"`,
   119  		6:  `.	.	.	<b empty="">`,
   120  		7:  `.	.	.	.	"3"`,
   121  		8:  `.	.	.	<i backslash="\">`,
   122  		9:  `.	.	.	.	"&amp;4"`,
   123  		10: `.	.	"5"`,
   124  		11: `.	.	<blockquote>`,
   125  		12: `.	.	<br>`,
   126  		13: `.	.	"6"`,
   127  		14: `.	.	"<!--comm-->"`,
   128  		15: `.	.	"<!--x--&gt;y-->"`,
   129  		16: `.	.	"7<pre>8</pre>9"`,
   130  	}
   131  	if len(nodes) != len(treeAsText) {
   132  		t.Fatal("len(nodes) != len(treeAsText)")
   133  	}
   134  	var stack [8]*Node
   135  	for i, line := range treeAsText {
   136  		level := 0
   137  		for line[0] == '.' {
   138  			// Strip a leading ".\t".
   139  			line = line[2:]
   140  			level++
   141  		}
   142  		n := nodes[i]
   143  		if level == 0 {
   144  			if stack[0] != nil {
   145  				t.Fatal("multiple root nodes")
   146  			}
   147  			stack[0] = n
   148  		} else {
   149  			stack[level-1].AppendChild(n)
   150  			stack[level] = n
   151  			for i := level + 1; i < len(stack); i++ {
   152  				stack[i] = nil
   153  			}
   154  		}
   155  		// At each stage of tree construction, we check all nodes for consistency.
   156  		for j, m := range nodes {
   157  			if err := checkNodeConsistency(m); err != nil {
   158  				t.Fatalf("i=%d, j=%d: %v", i, j, err)
   159  			}
   160  		}
   161  	}
   162  
   163  	want := `<html><head></head><body>0&lt;1<p id="A" foo="abc&#34;def">` +
   164  		`2<b empty="">3</b><i backslash="\">&amp;4</i></p>` +
   165  		`5<blockquote></blockquote><br/>6<!--comm--><!--x--&gt;y-->7<pre>8</pre>9</body></html>`
   166  	b := new(bytes.Buffer)
   167  	if err := Render(b, nodes[0]); err != nil {
   168  		t.Fatal(err)
   169  	}
   170  	if got := b.String(); got != want {
   171  		t.Errorf("got vs want:\n%s\n%s\n", got, want)
   172  	}
   173  }
   174  
   175  func TestRenderTextNodes(t *testing.T) {
   176  	elements := []string{"style", "script", "xmp", "iframe", "noembed", "noframes", "plaintext", "noscript"}
   177  	for _, namespace := range []string{
   178  		"", // html
   179  		"svg",
   180  		"math",
   181  	} {
   182  		for _, e := range elements {
   183  			var namespaceOpen, namespaceClose string
   184  			if namespace != "" {
   185  				namespaceOpen, namespaceClose = fmt.Sprintf("<%s>", namespace), fmt.Sprintf("</%s>", namespace)
   186  			}
   187  			doc := fmt.Sprintf(`<html><head></head><body>%s<%s>&</%s>%s</body></html>`, namespaceOpen, e, e, namespaceClose)
   188  			n, err := Parse(strings.NewReader(doc))
   189  			if err != nil {
   190  				t.Fatal(err)
   191  			}
   192  			b := bytes.NewBuffer(nil)
   193  			if err := Render(b, n); err != nil {
   194  				t.Fatal(err)
   195  			}
   196  
   197  			expected := doc
   198  			if namespace != "" {
   199  				expected = strings.Replace(expected, "&", "&amp;", 1)
   200  			}
   201  
   202  			if b.String() != expected {
   203  				t.Errorf("unexpected output: got %q, want %q", b.String(), expected)
   204  			}
   205  		}
   206  	}
   207  }