github.com/anakojm/hugo-katex@v0.0.0-20231023141351-42d6f5de9c0b/markup/asciidocext/convert_test.go (about) 1 // Copyright 2023 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 asciidocext converts AsciiDoc to HTML using Asciidoctor 15 // external binary. The `asciidoc` module is reserved for a future golang 16 // implementation. 17 18 package asciidocext_test 19 20 import ( 21 "path/filepath" 22 "testing" 23 24 "github.com/gohugoio/hugo/common/collections" 25 "github.com/gohugoio/hugo/common/hexec" 26 "github.com/gohugoio/hugo/common/loggers" 27 "github.com/gohugoio/hugo/config" 28 "github.com/gohugoio/hugo/config/security" 29 "github.com/gohugoio/hugo/config/testconfig" 30 "github.com/gohugoio/hugo/markup/asciidocext" 31 "github.com/gohugoio/hugo/markup/asciidocext/internal" 32 "github.com/gohugoio/hugo/markup/converter" 33 "github.com/gohugoio/hugo/markup/markup_config" 34 "github.com/spf13/afero" 35 36 qt "github.com/frankban/quicktest" 37 ) 38 39 func TestAsciidoctorDefaultArgs(t *testing.T) { 40 c := qt.New(t) 41 cfg := config.New() 42 conf := testconfig.GetTestConfig(afero.NewMemMapFs(), cfg) 43 44 p, err := asciidocext.Provider.New( 45 converter.ProviderConfig{ 46 Conf: conf, 47 Logger: loggers.NewDefault(), 48 }, 49 ) 50 c.Assert(err, qt.IsNil) 51 52 conv, err := p.New(converter.DocumentContext{}) 53 c.Assert(err, qt.IsNil) 54 55 ac := conv.(*internal.AsciidocConverter) 56 c.Assert(ac, qt.Not(qt.IsNil)) 57 58 args := ac.ParseArgs(converter.DocumentContext{}) 59 expected := []string{"--no-header-footer"} 60 c.Assert(args, qt.DeepEquals, expected) 61 } 62 63 func TestAsciidoctorNonDefaultArgs(t *testing.T) { 64 c := qt.New(t) 65 mconf := markup_config.Default 66 mconf.AsciidocExt.Backend = "manpage" 67 mconf.AsciidocExt.NoHeaderOrFooter = false 68 mconf.AsciidocExt.SafeMode = "safe" 69 mconf.AsciidocExt.SectionNumbers = true 70 mconf.AsciidocExt.Verbose = true 71 mconf.AsciidocExt.Trace = false 72 mconf.AsciidocExt.FailureLevel = "warn" 73 74 conf := testconfig.GetTestConfigSectionFromStruct("markup", mconf) 75 76 p, err := asciidocext.Provider.New( 77 converter.ProviderConfig{ 78 Conf: conf, 79 Logger: loggers.NewDefault(), 80 }, 81 ) 82 c.Assert(err, qt.IsNil) 83 84 conv, err := p.New(converter.DocumentContext{}) 85 c.Assert(err, qt.IsNil) 86 87 ac := conv.(*internal.AsciidocConverter) 88 c.Assert(ac, qt.Not(qt.IsNil)) 89 90 args := ac.ParseArgs(converter.DocumentContext{}) 91 expected := []string{"-b", "manpage", "--section-numbers", "--verbose", "--failure-level", "warn", "--safe-mode", "safe"} 92 c.Assert(args, qt.DeepEquals, expected) 93 } 94 95 func TestAsciidoctorDisallowedArgs(t *testing.T) { 96 c := qt.New(t) 97 mconf := markup_config.Default 98 mconf.AsciidocExt.Backend = "disallowed-backend" 99 mconf.AsciidocExt.Extensions = []string{"./disallowed-extension"} 100 mconf.AsciidocExt.Attributes = map[string]string{"outdir": "disallowed-attribute"} 101 mconf.AsciidocExt.SafeMode = "disallowed-safemode" 102 mconf.AsciidocExt.FailureLevel = "disallowed-failurelevel" 103 104 conf := testconfig.GetTestConfigSectionFromStruct("markup", mconf) 105 106 p, err := asciidocext.Provider.New( 107 converter.ProviderConfig{ 108 Conf: conf, 109 Logger: loggers.NewDefault(), 110 }, 111 ) 112 c.Assert(err, qt.IsNil) 113 114 conv, err := p.New(converter.DocumentContext{}) 115 c.Assert(err, qt.IsNil) 116 117 ac := conv.(*internal.AsciidocConverter) 118 c.Assert(ac, qt.Not(qt.IsNil)) 119 120 args := ac.ParseArgs(converter.DocumentContext{}) 121 expected := []string{"--no-header-footer"} 122 c.Assert(args, qt.DeepEquals, expected) 123 } 124 125 func TestAsciidoctorArbitraryExtension(t *testing.T) { 126 c := qt.New(t) 127 mconf := markup_config.Default 128 mconf.AsciidocExt.Extensions = []string{"arbitrary-extension"} 129 conf := testconfig.GetTestConfigSectionFromStruct("markup", mconf) 130 p, err := asciidocext.Provider.New( 131 converter.ProviderConfig{ 132 Conf: conf, 133 Logger: loggers.NewDefault(), 134 }, 135 ) 136 c.Assert(err, qt.IsNil) 137 138 conv, err := p.New(converter.DocumentContext{}) 139 c.Assert(err, qt.IsNil) 140 141 ac := conv.(*internal.AsciidocConverter) 142 c.Assert(ac, qt.Not(qt.IsNil)) 143 144 args := ac.ParseArgs(converter.DocumentContext{}) 145 expected := []string{"-r", "arbitrary-extension", "--no-header-footer"} 146 c.Assert(args, qt.DeepEquals, expected) 147 } 148 149 func TestAsciidoctorDisallowedExtension(t *testing.T) { 150 c := qt.New(t) 151 152 for _, disallowedExtension := range []string{ 153 `foo-bar//`, 154 `foo-bar\\ `, 155 `../../foo-bar`, 156 `/foo-bar`, 157 `C:\foo-bar`, 158 `foo-bar.rb`, 159 `foo.bar`, 160 } { 161 mconf := markup_config.Default 162 mconf.AsciidocExt.Extensions = []string{disallowedExtension} 163 conf := testconfig.GetTestConfigSectionFromStruct("markup", mconf) 164 p, err := asciidocext.Provider.New( 165 converter.ProviderConfig{ 166 Conf: conf, 167 Logger: loggers.NewDefault(), 168 }, 169 ) 170 c.Assert(err, qt.IsNil) 171 172 conv, err := p.New(converter.DocumentContext{}) 173 c.Assert(err, qt.IsNil) 174 175 ac := conv.(*internal.AsciidocConverter) 176 c.Assert(ac, qt.Not(qt.IsNil)) 177 178 args := ac.ParseArgs(converter.DocumentContext{}) 179 expected := []string{"--no-header-footer"} 180 c.Assert(args, qt.DeepEquals, expected) 181 } 182 } 183 184 func TestAsciidoctorWorkingFolderCurrent(t *testing.T) { 185 c := qt.New(t) 186 cfg := config.FromTOMLConfigString(` 187 [markup] 188 [markup.asciidocext] 189 workingFolderCurrent = true 190 trace = false 191 `) 192 193 conf := testconfig.GetTestConfig(afero.NewMemMapFs(), cfg) 194 195 p, err := asciidocext.Provider.New( 196 converter.ProviderConfig{ 197 Conf: conf, 198 Logger: loggers.NewDefault(), 199 }, 200 ) 201 c.Assert(err, qt.IsNil) 202 203 ctx := converter.DocumentContext{Filename: "/tmp/hugo_asciidoc_ddd/docs/chapter2/index.adoc", DocumentName: "chapter2/index.adoc"} 204 conv, err := p.New(ctx) 205 c.Assert(err, qt.IsNil) 206 207 ac := conv.(*internal.AsciidocConverter) 208 c.Assert(ac, qt.Not(qt.IsNil)) 209 210 args := ac.ParseArgs(ctx) 211 c.Assert(len(args), qt.Equals, 5) 212 c.Assert(args[0], qt.Equals, "--base-dir") 213 c.Assert(filepath.ToSlash(args[1]), qt.Matches, "/tmp/hugo_asciidoc_ddd/docs/chapter2") 214 c.Assert(args[2], qt.Equals, "-a") 215 c.Assert(args[3], qt.Matches, `outdir=.*chapter2`) 216 c.Assert(args[4], qt.Equals, "--no-header-footer") 217 } 218 219 func TestAsciidoctorWorkingFolderCurrentAndExtensions(t *testing.T) { 220 c := qt.New(t) 221 cfg := config.FromTOMLConfigString(` 222 [markup] 223 [markup.asciidocext] 224 backend = "html5s" 225 workingFolderCurrent = true 226 trace = false 227 noHeaderOrFooter = true 228 extensions = ["asciidoctor-html5s", "asciidoctor-diagram"] 229 `) 230 conf := testconfig.GetTestConfig(afero.NewMemMapFs(), cfg) 231 232 p, err := asciidocext.Provider.New( 233 converter.ProviderConfig{ 234 Conf: conf, 235 Logger: loggers.NewDefault(), 236 }, 237 ) 238 c.Assert(err, qt.IsNil) 239 240 conv, err := p.New(converter.DocumentContext{}) 241 c.Assert(err, qt.IsNil) 242 243 ac := conv.(*internal.AsciidocConverter) 244 c.Assert(ac, qt.Not(qt.IsNil)) 245 246 args := ac.ParseArgs(converter.DocumentContext{}) 247 c.Assert(len(args), qt.Equals, 11) 248 c.Assert(args[0], qt.Equals, "-b") 249 c.Assert(args[1], qt.Equals, "html5s") 250 c.Assert(args[2], qt.Equals, "-r") 251 c.Assert(args[3], qt.Equals, "asciidoctor-html5s") 252 c.Assert(args[4], qt.Equals, "-r") 253 c.Assert(args[5], qt.Equals, "asciidoctor-diagram") 254 c.Assert(args[6], qt.Equals, "--base-dir") 255 c.Assert(args[7], qt.Equals, ".") 256 c.Assert(args[8], qt.Equals, "-a") 257 c.Assert(args[9], qt.Contains, "outdir=") 258 c.Assert(args[10], qt.Equals, "--no-header-footer") 259 } 260 261 func TestAsciidoctorAttributes(t *testing.T) { 262 c := qt.New(t) 263 cfg := config.FromTOMLConfigString(` 264 [markup] 265 [markup.asciidocext] 266 trace = false 267 [markup.asciidocext.attributes] 268 my-base-url = "https://gohugo.io/" 269 my-attribute-name = "my value" 270 `) 271 conf := testconfig.GetTestConfig(nil, cfg) 272 p, err := asciidocext.Provider.New( 273 converter.ProviderConfig{ 274 Conf: conf, 275 Logger: loggers.NewDefault(), 276 }, 277 ) 278 c.Assert(err, qt.IsNil) 279 280 conv, err := p.New(converter.DocumentContext{}) 281 c.Assert(err, qt.IsNil) 282 283 ac := conv.(*internal.AsciidocConverter) 284 c.Assert(ac, qt.Not(qt.IsNil)) 285 286 expectedValues := map[string]bool{ 287 "my-base-url=https://gohugo.io/": true, 288 "my-attribute-name=my value": true, 289 } 290 291 args := ac.ParseArgs(converter.DocumentContext{}) 292 c.Assert(len(args), qt.Equals, 5) 293 c.Assert(args[0], qt.Equals, "-a") 294 c.Assert(expectedValues[args[1]], qt.Equals, true) 295 c.Assert(args[2], qt.Equals, "-a") 296 c.Assert(expectedValues[args[3]], qt.Equals, true) 297 c.Assert(args[4], qt.Equals, "--no-header-footer") 298 } 299 300 func getProvider(c *qt.C, mConfStr string) converter.Provider { 301 confStr := ` 302 [security] 303 [security.exec] 304 allow = ['asciidoctor'] 305 ` 306 confStr += mConfStr 307 308 cfg := config.FromTOMLConfigString(confStr) 309 conf := testconfig.GetTestConfig(nil, cfg) 310 securityConfig := conf.GetConfigSection("security").(security.Config) 311 312 p, err := asciidocext.Provider.New( 313 converter.ProviderConfig{ 314 Logger: loggers.NewDefault(), 315 Conf: conf, 316 Exec: hexec.New(securityConfig), 317 }, 318 ) 319 c.Assert(err, qt.IsNil) 320 return p 321 } 322 323 func TestConvert(t *testing.T) { 324 if !asciidocext.Supports() { 325 t.Skip("asciidoctor not installed") 326 } 327 c := qt.New(t) 328 329 p := getProvider(c, "") 330 331 conv, err := p.New(converter.DocumentContext{}) 332 c.Assert(err, qt.IsNil) 333 334 b, err := conv.Convert(converter.RenderContext{Src: []byte("testContent")}) 335 c.Assert(err, qt.IsNil) 336 c.Assert(string(b.Bytes()), qt.Equals, "<div class=\"paragraph\">\n<p>testContent</p>\n</div>\n") 337 } 338 339 func TestTableOfContents(t *testing.T) { 340 if !asciidocext.Supports() { 341 t.Skip("asciidoctor not installed") 342 } 343 c := qt.New(t) 344 p := getProvider(c, "") 345 346 conv, err := p.New(converter.DocumentContext{}) 347 c.Assert(err, qt.IsNil) 348 r, err := conv.Convert(converter.RenderContext{Src: []byte(`:toc: macro 349 :toclevels: 4 350 toc::[] 351 352 === Introduction 353 354 == Section 1 355 356 === Section 1.1 357 358 ==== Section 1.1.1 359 360 === Section 1.2 361 362 testContent 363 364 == Section 2 365 `)}) 366 c.Assert(err, qt.IsNil) 367 toc, ok := r.(converter.TableOfContentsProvider) 368 c.Assert(ok, qt.Equals, true) 369 370 c.Assert(toc.TableOfContents().Identifiers, qt.DeepEquals, collections.SortedStringSlice{"_introduction", "_section_1", "_section_1_1", "_section_1_1_1", "_section_1_2", "_section_2"}) 371 c.Assert(string(r.Bytes()), qt.Not(qt.Contains), "<div id=\"toc\" class=\"toc\">") 372 } 373 374 func TestTableOfContentsWithCode(t *testing.T) { 375 if !asciidocext.Supports() { 376 t.Skip("asciidoctor not installed") 377 } 378 c := qt.New(t) 379 p := getProvider(c, "") 380 conv, err := p.New(converter.DocumentContext{}) 381 c.Assert(err, qt.IsNil) 382 r, err := conv.Convert(converter.RenderContext{Src: []byte(`:toc: auto 383 384 == Some ` + "`code`" + ` in the title 385 `)}) 386 c.Assert(err, qt.IsNil) 387 toc, ok := r.(converter.TableOfContentsProvider) 388 c.Assert(ok, qt.Equals, true) 389 c.Assert(toc.TableOfContents().HeadingsMap["_some_code_in_the_title"].Title, qt.Equals, "Some <code>code</code> in the title") 390 c.Assert(string(r.Bytes()), qt.Not(qt.Contains), "<div id=\"toc\" class=\"toc\">") 391 } 392 393 func TestTableOfContentsPreserveTOC(t *testing.T) { 394 if !asciidocext.Supports() { 395 t.Skip("asciidoctor not installed") 396 } 397 c := qt.New(t) 398 confStr := ` 399 [markup] 400 [markup.asciidocExt] 401 preserveTOC = true 402 ` 403 p := getProvider(c, confStr) 404 405 conv, err := p.New(converter.DocumentContext{}) 406 c.Assert(err, qt.IsNil) 407 r, err := conv.Convert(converter.RenderContext{Src: []byte(`:toc: 408 :idprefix: 409 :idseparator: - 410 411 == Some title 412 `)}) 413 c.Assert(err, qt.IsNil) 414 toc, ok := r.(converter.TableOfContentsProvider) 415 c.Assert(ok, qt.Equals, true) 416 417 c.Assert(toc.TableOfContents().Identifiers, qt.DeepEquals, collections.SortedStringSlice{"some-title"}) 418 c.Assert(string(r.Bytes()), qt.Contains, "<div id=\"toc\" class=\"toc\">") 419 }