github.com/kovansky/hugo@v0.92.3-0.20220224232819-63076e4ff19f/markup/goldmark/integration_test.go (about)

     1  // Copyright 2021 The Hugo Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package goldmark_test
    15  
    16  import (
    17  	"fmt"
    18  	"strings"
    19  	"testing"
    20  
    21  	"github.com/gohugoio/hugo/hugolib"
    22  )
    23  
    24  // Issue 9463
    25  func TestAttributeExclusion(t *testing.T) {
    26  	t.Parallel()
    27  
    28  	files := `
    29  -- config.toml --
    30  [markup.goldmark.renderer]
    31  	unsafe = false
    32  [markup.goldmark.parser.attribute]
    33  	block = true
    34  	title = true
    35  -- content/p1.md --
    36  ---
    37  title: "p1"
    38  ---
    39  ## Heading {class="a" onclick="alert('heading')"}
    40  
    41  > Blockquote
    42  {class="b" ondblclick="alert('blockquote')"}
    43  
    44  ~~~bash {id="c" onmouseover="alert('code fence')" LINENOS=true}
    45  foo
    46  ~~~
    47  -- layouts/_default/single.html --
    48  {{ .Content }}
    49  `
    50  
    51  	b := hugolib.NewIntegrationTestBuilder(
    52  		hugolib.IntegrationTestConfig{
    53  			T:           t,
    54  			TxtarString: files,
    55  			NeedsOsFS:   false,
    56  		},
    57  	).Build()
    58  
    59  	b.AssertFileContent("public/p1/index.html", `
    60  		<h2 class="a" id="heading">
    61  		<blockquote class="b">
    62  		<div class="highlight" id="c">
    63  	`)
    64  }
    65  
    66  // Issue 9511
    67  func TestAttributeExclusionWithRenderHook(t *testing.T) {
    68  	t.Parallel()
    69  
    70  	files := `
    71  -- content/p1.md --
    72  ---
    73  title: "p1"
    74  ---
    75  ## Heading {onclick="alert('renderhook')" data-foo="bar"}
    76  -- layouts/_default/single.html --
    77  {{ .Content }}
    78  -- layouts/_default/_markup/render-heading.html --
    79  <h{{ .Level }}
    80    {{- range $k, $v := .Attributes -}}
    81      {{- printf " %s=%q" $k $v | safeHTMLAttr -}}
    82    {{- end -}}
    83  >{{ .Text | safeHTML }}</h{{ .Level }}>
    84  `
    85  
    86  	b := hugolib.NewIntegrationTestBuilder(
    87  		hugolib.IntegrationTestConfig{
    88  			T:           t,
    89  			TxtarString: files,
    90  			NeedsOsFS:   false,
    91  		},
    92  	).Build()
    93  
    94  	b.AssertFileContent("public/p1/index.html", `
    95  		<h2 data-foo="bar" id="heading">Heading</h2>
    96  	`)
    97  }
    98  
    99  func TestAttributesDefaultRenderer(t *testing.T) {
   100  	t.Parallel()
   101  
   102  	files := `
   103  -- content/p1.md --
   104  ---
   105  title: "p1"
   106  ---
   107  ## Heading Attribute Which Needs Escaping { class="a < b" }
   108  -- layouts/_default/single.html --
   109  {{ .Content }}
   110  `
   111  
   112  	b := hugolib.NewIntegrationTestBuilder(
   113  		hugolib.IntegrationTestConfig{
   114  			T:           t,
   115  			TxtarString: files,
   116  			NeedsOsFS:   false,
   117  		},
   118  	).Build()
   119  
   120  	b.AssertFileContent("public/p1/index.html", `
   121  class="a &lt; b"
   122  	`)
   123  }
   124  
   125  // Issue 9558.
   126  func TestAttributesHookNoEscape(t *testing.T) {
   127  	t.Parallel()
   128  
   129  	files := `
   130  -- content/p1.md --
   131  ---
   132  title: "p1"
   133  ---
   134  ## Heading Attribute Which Needs Escaping { class="Smith & Wesson" }
   135  -- layouts/_default/_markup/render-heading.html --
   136  plain: |{{- range $k, $v := .Attributes -}}{{ $k }}: {{ $v }}|{{ end }}|
   137  safeHTML: |{{- range $k, $v := .Attributes -}}{{ $k }}: {{ $v | safeHTML }}|{{ end }}|
   138  -- layouts/_default/single.html --
   139  {{ .Content }}
   140  `
   141  
   142  	b := hugolib.NewIntegrationTestBuilder(
   143  		hugolib.IntegrationTestConfig{
   144  			T:           t,
   145  			TxtarString: files,
   146  			NeedsOsFS:   false,
   147  		},
   148  	).Build()
   149  
   150  	b.AssertFileContent("public/p1/index.html", `
   151  plain: |class: Smith &amp; Wesson|id: heading-attribute-which-needs-escaping|
   152  safeHTML: |class: Smith & Wesson|id: heading-attribute-which-needs-escaping|
   153  	`)
   154  }
   155  
   156  // Issue 9504
   157  func TestLinkInTitle(t *testing.T) {
   158  	t.Parallel()
   159  
   160  	files := `
   161  -- config.toml --
   162  -- content/p1.md --
   163  ---
   164  title: "p1"
   165  ---
   166  ## Hello [Test](https://example.com)
   167  -- layouts/_default/single.html --
   168  {{ .Content }}
   169  -- layouts/_default/_markup/render-heading.html --
   170  <h{{ .Level }} id="{{ .Anchor | safeURL }}">
   171    {{ .Text | safeHTML }}
   172    <a class="anchor" href="#{{ .Anchor | safeURL }}">#</a>
   173  </h{{ .Level }}>
   174  -- layouts/_default/_markup/render-link.html --
   175  <a href="{{ .Destination | safeURL }}"{{ with .Title}} title="{{ . }}"{{ end }}>{{ .Text | safeHTML }}</a>
   176  
   177  `
   178  
   179  	b := hugolib.NewIntegrationTestBuilder(
   180  		hugolib.IntegrationTestConfig{
   181  			T:           t,
   182  			TxtarString: files,
   183  			NeedsOsFS:   false,
   184  		},
   185  	).Build()
   186  
   187  	b.AssertFileContent("public/p1/index.html",
   188  		"<h2 id=\"hello-testhttpsexamplecom\">\n  Hello <a href=\"https://example.com\">Test</a>\n\n  <a class=\"anchor\" href=\"#hello-testhttpsexamplecom\">#</a>\n</h2>",
   189  	)
   190  }
   191  
   192  func TestHighlight(t *testing.T) {
   193  	t.Parallel()
   194  
   195  	files := `
   196  -- config.toml --
   197  [markup]
   198  [markup.highlight]
   199  anchorLineNos = false
   200  codeFences = true
   201  guessSyntax = false
   202  hl_Lines = ''
   203  lineAnchors = ''
   204  lineNoStart = 1
   205  lineNos = false
   206  lineNumbersInTable = true
   207  noClasses = false
   208  style = 'monokai'
   209  tabWidth = 4
   210  -- layouts/_default/single.html --
   211  {{ .Content }}
   212  -- content/p1.md --
   213  ---
   214  title: "p1"
   215  ---
   216  
   217  ## Code Fences
   218  
   219  §§§bash
   220  LINE1
   221  §§§
   222  
   223  ## Code Fences No Lexer
   224  
   225  §§§moo
   226  LINE1
   227  §§§
   228  
   229  ## Code Fences Simple Attributes
   230  
   231  §§A§bash { .myclass id="myid" }
   232  LINE1
   233  §§A§
   234  
   235  ## Code Fences Line Numbers
   236  
   237  §§§bash {linenos=table,hl_lines=[8,"15-17"],linenostart=199}
   238  LINE1
   239  LINE2
   240  LINE3
   241  LINE4
   242  LINE5
   243  LINE6
   244  LINE7
   245  LINE8
   246  §§§
   247  
   248  
   249  
   250  
   251  `
   252  
   253  	// Code fences
   254  	files = strings.ReplaceAll(files, "§§§", "```")
   255  
   256  	b := hugolib.NewIntegrationTestBuilder(
   257  		hugolib.IntegrationTestConfig{
   258  			T:           t,
   259  			TxtarString: files,
   260  		},
   261  	).Build()
   262  
   263  	b.AssertFileContent("public/p1/index.html",
   264  		"<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-bash\" data-lang=\"bash\"><span class=\"line\"><span class=\"cl\">LINE1\n</span></span></code></pre></div>",
   265  		"Code Fences No Lexer</h2>\n<pre tabindex=\"0\"><code class=\"language-moo\" data-lang=\"moo\">LINE1\n</code></pre>",
   266  		"lnt",
   267  	)
   268  }
   269  
   270  func BenchmarkRenderHooks(b *testing.B) {
   271  	files := `
   272  -- config.toml --
   273  -- layouts/_default/_markup/render-heading.html --
   274  <h{{ .Level }} id="{{ .Anchor | safeURL }}">
   275  	{{ .Text | safeHTML }}
   276  	<a class="anchor" href="#{{ .Anchor | safeURL }}">#</a>
   277  </h{{ .Level }}>
   278  -- layouts/_default/_markup/render-link.html --
   279  <a href="{{ .Destination | safeURL }}"{{ with .Title}} title="{{ . }}"{{ end }}>{{ .Text | safeHTML }}</a>
   280  -- layouts/_default/single.html --
   281  {{ .Content }}
   282  `
   283  
   284  	content := `
   285  
   286  ## Hello1 [Test](https://example.com)
   287  
   288  A.
   289  
   290  ## Hello2 [Test](https://example.com)
   291  
   292  B.
   293  
   294  ## Hello3 [Test](https://example.com)
   295  
   296  C.
   297  
   298  ## Hello4 [Test](https://example.com)
   299  
   300  D.
   301  
   302  [Test](https://example.com)
   303  
   304  ## Hello5
   305  
   306  
   307  `
   308  
   309  	for i := 1; i < 100; i++ {
   310  		files += fmt.Sprintf("\n-- content/posts/p%d.md --\n"+content, i+1)
   311  	}
   312  
   313  	cfg := hugolib.IntegrationTestConfig{
   314  		T:           b,
   315  		TxtarString: files,
   316  	}
   317  	builders := make([]*hugolib.IntegrationTestBuilder, b.N)
   318  
   319  	for i := range builders {
   320  		builders[i] = hugolib.NewIntegrationTestBuilder(cfg)
   321  	}
   322  
   323  	b.ResetTimer()
   324  
   325  	for i := 0; i < b.N; i++ {
   326  		builders[i].Build()
   327  	}
   328  }
   329  
   330  func BenchmarkCodeblocks(b *testing.B) {
   331  	files := `
   332  -- config.toml --
   333  [markup]
   334    [markup.highlight]
   335      anchorLineNos = false
   336      codeFences = true
   337      guessSyntax = false
   338      hl_Lines = ''
   339      lineAnchors = ''
   340      lineNoStart = 1
   341      lineNos = false
   342      lineNumbersInTable = true
   343      noClasses = true
   344      style = 'monokai'
   345      tabWidth = 4
   346  -- layouts/_default/single.html --
   347  {{ .Content }}
   348  `
   349  
   350  	content := `
   351  
   352  FENCEgo
   353  package main
   354  import "fmt"
   355  func main() {
   356      fmt.Println("hello world")
   357  }
   358  FENCE
   359  
   360  FENCEbash
   361  #!/bin/bash
   362  # Usage: Hello World Bash Shell Script Using Variables
   363  # Author: Vivek Gite
   364  # -------------------------------------------------
   365   
   366  # Define bash shell variable called var 
   367  # Avoid spaces around the assignment operator (=)
   368  var="Hello World"
   369   
   370  # print it 
   371  echo "$var"
   372   
   373  # Another way of printing it
   374  printf "%s\n" "$var"
   375  FENCE
   376  `
   377  
   378  	content = strings.ReplaceAll(content, "FENCE", "```")
   379  
   380  	for i := 1; i < 100; i++ {
   381  		files += fmt.Sprintf("\n-- content/posts/p%d.md --\n"+content, i+1)
   382  	}
   383  
   384  	cfg := hugolib.IntegrationTestConfig{
   385  		T:           b,
   386  		TxtarString: files,
   387  	}
   388  	builders := make([]*hugolib.IntegrationTestBuilder, b.N)
   389  
   390  	for i := range builders {
   391  		builders[i] = hugolib.NewIntegrationTestBuilder(cfg)
   392  	}
   393  
   394  	b.ResetTimer()
   395  
   396  	for i := 0; i < b.N; i++ {
   397  		builders[i].Build()
   398  	}
   399  }