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