...

Source file src/github.com/alecthomas/chroma/formatters/html/html_test.go

Documentation: github.com/alecthomas/chroma/formatters/html

     1  package html
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  
    12  	"github.com/alecthomas/chroma"
    13  	"github.com/alecthomas/chroma/lexers"
    14  	"github.com/alecthomas/chroma/styles"
    15  )
    16  
    17  func TestCompressStyle(t *testing.T) {
    18  	style := "color: #888888; background-color: #faffff"
    19  	actual := compressStyle(style)
    20  	expected := "color:#888;background-color:#faffff"
    21  	assert.Equal(t, expected, actual)
    22  }
    23  
    24  func BenchmarkHTMLFormatter(b *testing.B) {
    25  	formatter := New()
    26  	b.ResetTimer()
    27  	for i := 0; i < b.N; i++ {
    28  		it, err := lexers.Get("go").Tokenise(nil, "package main\nfunc main()\n{\nprintln(`hello world`)\n}\n")
    29  		assert.NoError(b, err)
    30  		err = formatter.Format(ioutil.Discard, styles.Fallback, it)
    31  		assert.NoError(b, err)
    32  	}
    33  }
    34  
    35  func TestSplitTokensIntoLines(t *testing.T) {
    36  	in := []chroma.Token{
    37  		{Value: "hello", Type: chroma.NameKeyword},
    38  		{Value: " world\nwhat?\n", Type: chroma.NameKeyword},
    39  	}
    40  	expected := [][]chroma.Token{
    41  		{
    42  			{Type: chroma.NameKeyword, Value: "hello"},
    43  			{Type: chroma.NameKeyword, Value: " world\n"},
    44  		},
    45  		{
    46  			{Type: chroma.NameKeyword, Value: "what?\n"},
    47  		},
    48  	}
    49  	actual := chroma.SplitTokensIntoLines(in)
    50  	assert.Equal(t, expected, actual)
    51  }
    52  
    53  func TestFormatterStyleToCSS(t *testing.T) {
    54  	builder := styles.Get("github").Builder()
    55  	builder.Add(chroma.LineHighlight, "bg:#ffffcc")
    56  	builder.Add(chroma.LineNumbers, "bold")
    57  	style, err := builder.Build()
    58  	if err != nil {
    59  		t.Error(err)
    60  	}
    61  	formatter := New(WithClasses(true))
    62  	css := formatter.styleToCSS(style)
    63  	for _, s := range css {
    64  		if strings.HasPrefix(strings.TrimSpace(s), ";") {
    65  			t.Errorf("rule starts with semicolon - expected valid css rule without semicolon: %v", s)
    66  		}
    67  	}
    68  }
    69  
    70  func TestClassPrefix(t *testing.T) {
    71  	wantPrefix := "some-prefix-"
    72  	withPrefix := New(WithClasses(true), ClassPrefix(wantPrefix))
    73  	noPrefix := New(WithClasses(true))
    74  	for st := range chroma.StandardTypes {
    75  		if noPrefix.class(st) == "" {
    76  			if got := withPrefix.class(st); got != "" {
    77  				t.Errorf("Formatter.class(%v): prefix shouldn't be added to empty classes", st)
    78  			}
    79  		} else if got := withPrefix.class(st); !strings.HasPrefix(got, wantPrefix) {
    80  			t.Errorf("Formatter.class(%v): %q should have a class prefix", st, got)
    81  		}
    82  	}
    83  
    84  	var styleBuf bytes.Buffer
    85  	err := withPrefix.WriteCSS(&styleBuf, styles.Fallback)
    86  	assert.NoError(t, err)
    87  	if !strings.Contains(styleBuf.String(), ".some-prefix-chroma ") {
    88  		t.Error("Stylesheets should have a class prefix")
    89  	}
    90  }
    91  
    92  func TestTableLineNumberNewlines(t *testing.T) {
    93  	f := New(WithClasses(true), WithLineNumbers(true), LineNumbersInTable(true))
    94  	it, err := lexers.Get("go").Tokenise(nil, "package main\nfunc main()\n{\nprintln(`hello world`)\n}\n")
    95  	assert.NoError(t, err)
    96  
    97  	var buf bytes.Buffer
    98  	err = f.Format(&buf, styles.Fallback, it)
    99  	assert.NoError(t, err)
   100  
   101  	// Don't bother testing the whole output, just verify it's got line numbers
   102  	// in a <pre>-friendly format.
   103  	// Note: placing the newlines inside the <span> lets browser selections look
   104  	// better, instead of "skipping" over the span margin.
   105  	assert.Contains(t, buf.String(), `<span class="lnt">2
   106  </span><span class="lnt">3
   107  </span><span class="lnt">4
   108  </span>`)
   109  }
   110  
   111  func TestWrapLongLines(t *testing.T) {
   112  	f := New(WithClasses(false), WrapLongLines(true))
   113  	it, err := lexers.Get("go").Tokenise(nil, "package main\nfunc main()\n{\nprintln(\"hello world\")\n}\n")
   114  	assert.NoError(t, err)
   115  
   116  	var buf bytes.Buffer
   117  	err = f.Format(&buf, styles.Fallback, it)
   118  	assert.NoError(t, err)
   119  
   120  	assert.Regexp(t, `<pre.*style=".*white-space:pre-wrap;word-break:break-word;`, buf.String())
   121  }
   122  
   123  func TestHighlightLines(t *testing.T) {
   124  	f := New(WithClasses(true), HighlightLines([][2]int{{4, 5}}))
   125  	it, err := lexers.Get("go").Tokenise(nil, "package main\nfunc main()\n{\nprintln(\"hello world\")\n}\n")
   126  	assert.NoError(t, err)
   127  
   128  	var buf bytes.Buffer
   129  	err = f.Format(&buf, styles.Fallback, it)
   130  	assert.NoError(t, err)
   131  
   132  	assert.Contains(t, buf.String(), `<span class="line hl"><span class="cl">`)
   133  }
   134  
   135  func TestLineNumbers(t *testing.T) {
   136  	f := New(WithClasses(true), WithLineNumbers(true))
   137  	it, err := lexers.Get("bash").Tokenise(nil, "echo FOO")
   138  	assert.NoError(t, err)
   139  
   140  	var buf bytes.Buffer
   141  	err = f.Format(&buf, styles.Fallback, it)
   142  	assert.NoError(t, err)
   143  
   144  	assert.Contains(t, buf.String(), `<span class="line"><span class="ln">1</span><span class="cl"><span class="nb">echo</span> FOO</span></span>`)
   145  }
   146  
   147  func TestPreWrapper(t *testing.T) {
   148  	f := New(Standalone(true), WithClasses(true))
   149  	it, err := lexers.Get("bash").Tokenise(nil, "echo FOO")
   150  	assert.NoError(t, err)
   151  
   152  	var buf bytes.Buffer
   153  	err = f.Format(&buf, styles.Fallback, it)
   154  	assert.NoError(t, err)
   155  
   156  	assert.Regexp(t, "<body class=\"bg\">\n<pre.*class=\"chroma\"><code><span class=\"line\"><span class=\"cl\"><span class=\"nb\">echo</span> FOO</span></span></code></pre>\n</body>\n</html>", buf.String())
   157  	assert.Regexp(t, `\.bg { .+ }`, buf.String())
   158  	assert.Regexp(t, `\.chroma { .+ }`, buf.String())
   159  }
   160  
   161  func TestLinkeableLineNumbers(t *testing.T) {
   162  	f := New(WithClasses(true), WithLineNumbers(true), LinkableLineNumbers(true, "line"))
   163  	it, err := lexers.Get("go").Tokenise(nil, "package main\nfunc main()\n{\nprintln(\"hello world\")\n}\n")
   164  	assert.NoError(t, err)
   165  
   166  	var buf bytes.Buffer
   167  	err = f.Format(&buf, styles.Fallback, it)
   168  	assert.NoError(t, err)
   169  
   170  	assert.Contains(t, buf.String(), `id="line1"><a style="outline: none; text-decoration:none; color:inherit" href="#line1">1</a>`)
   171  	assert.Contains(t, buf.String(), `id="line5"><a style="outline: none; text-decoration:none; color:inherit" href="#line5">5</a>`)
   172  }
   173  
   174  func TestTableLinkeableLineNumbers(t *testing.T) {
   175  	f := New(WithClasses(true), WithLineNumbers(true), LineNumbersInTable(true), LinkableLineNumbers(true, "line"))
   176  	it, err := lexers.Get("go").Tokenise(nil, "package main\nfunc main()\n{\nprintln(`hello world`)\n}\n")
   177  	assert.NoError(t, err)
   178  
   179  	var buf bytes.Buffer
   180  	err = f.Format(&buf, styles.Fallback, it)
   181  	assert.NoError(t, err)
   182  
   183  	assert.Contains(t, buf.String(), `id="line1"><a style="outline: none; text-decoration:none; color:inherit" href="#line1">1</a>`)
   184  	assert.Contains(t, buf.String(), `id="line5"><a style="outline: none; text-decoration:none; color:inherit" href="#line5">5</a>`)
   185  }
   186  
   187  func TestTableLineNumberSpacing(t *testing.T) {
   188  	testCases := []struct {
   189  		baseLineNumber int
   190  		expectedBuf    string
   191  	}{{
   192  		7,
   193  		`<span class="lnt"> 7
   194  </span><span class="lnt"> 8
   195  </span><span class="lnt"> 9
   196  </span><span class="lnt">10
   197  </span><span class="lnt">11
   198  </span>`,
   199  	}, {
   200  		6,
   201  		`<span class="lnt"> 6
   202  </span><span class="lnt"> 7
   203  </span><span class="lnt"> 8
   204  </span><span class="lnt"> 9
   205  </span><span class="lnt">10
   206  </span>`,
   207  	}, {
   208  		5,
   209  		`<span class="lnt">5
   210  </span><span class="lnt">6
   211  </span><span class="lnt">7
   212  </span><span class="lnt">8
   213  </span><span class="lnt">9
   214  </span>`,
   215  	}}
   216  	for i, testCase := range testCases {
   217  		f := New(
   218  			WithClasses(true),
   219  			WithLineNumbers(true),
   220  			LineNumbersInTable(true),
   221  			BaseLineNumber(testCase.baseLineNumber),
   222  		)
   223  		it, err := lexers.Get("go").Tokenise(nil, "package main\nfunc main()\n{\nprintln(`hello world`)\n}\n")
   224  		assert.NoError(t, err)
   225  		var buf bytes.Buffer
   226  		err = f.Format(&buf, styles.Fallback, it)
   227  		assert.NoError(t, err, "Test Case %d", i)
   228  		assert.Contains(t, buf.String(), testCase.expectedBuf, "Test Case %d", i)
   229  	}
   230  }
   231  
   232  func TestWithPreWrapper(t *testing.T) {
   233  	wrapper := preWrapper{
   234  		start: func(code bool, styleAttr string) string {
   235  			return fmt.Sprintf("<foo%s id=\"code-%t\">", styleAttr, code)
   236  		},
   237  		end: func(code bool) string {
   238  			return fmt.Sprintf("</foo>")
   239  		},
   240  	}
   241  
   242  	format := func(f *Formatter) string {
   243  		it, err := lexers.Get("bash").Tokenise(nil, "echo FOO")
   244  		assert.NoError(t, err)
   245  
   246  		var buf bytes.Buffer
   247  		err = f.Format(&buf, styles.Fallback, it)
   248  		assert.NoError(t, err)
   249  
   250  		return buf.String()
   251  	}
   252  
   253  	t.Run("Regular", func(t *testing.T) {
   254  		s := format(New(WithClasses(true)))
   255  		assert.Equal(t, s, `<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="nb">echo</span> FOO</span></span></code></pre>`)
   256  	})
   257  
   258  	t.Run("PreventSurroundingPre", func(t *testing.T) {
   259  		s := format(New(PreventSurroundingPre(true), WithClasses(true)))
   260  		assert.Equal(t, s, `<span class="line"><span class="cl"><span class="nb">echo</span> FOO</span></span>`)
   261  	})
   262  
   263  	t.Run("Wrapper", func(t *testing.T) {
   264  		s := format(New(WithPreWrapper(wrapper), WithClasses(true)))
   265  		assert.Equal(t, s, `<foo class="chroma" id="code-true"><span class="line"><span class="cl"><span class="nb">echo</span> FOO</span></span></foo>`)
   266  	})
   267  
   268  	t.Run("Wrapper, LineNumbersInTable", func(t *testing.T) {
   269  		s := format(New(WithPreWrapper(wrapper), WithClasses(true), WithLineNumbers(true), LineNumbersInTable(true)))
   270  
   271  		assert.Equal(t, s, `<div class="chroma">
   272  <table class="lntable"><tr><td class="lntd">
   273  <foo class="chroma" id="code-false"><span class="lnt">1
   274  </span></foo></td>
   275  <td class="lntd">
   276  <foo class="chroma" id="code-true"><span class="line"><span class="cl"><span class="nb">echo</span> FOO</span></span></foo></td></tr></table>
   277  </div>
   278  `)
   279  	})
   280  }
   281  
   282  func TestReconfigureOptions(t *testing.T) {
   283  	options := []Option{
   284  		WithClasses(true),
   285  		WithLineNumbers(true),
   286  	}
   287  
   288  	options = append(options, WithLineNumbers(false))
   289  
   290  	f := New(options...)
   291  
   292  	it, err := lexers.Get("bash").Tokenise(nil, "echo FOO")
   293  	assert.NoError(t, err)
   294  
   295  	var buf bytes.Buffer
   296  	err = f.Format(&buf, styles.Fallback, it)
   297  
   298  	assert.NoError(t, err)
   299  	assert.Equal(t, `<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="nb">echo</span> FOO</span></span></code></pre>`, buf.String())
   300  }
   301  
   302  func TestWriteCssWithAllClasses(t *testing.T) {
   303  	formatter := New()
   304  	formatter.allClasses = true
   305  
   306  	var buf bytes.Buffer
   307  	err := formatter.WriteCSS(&buf, styles.Fallback)
   308  
   309  	assert.NoError(t, err)
   310  	assert.NotContains(t, buf.String(), ".chroma . {", "Generated css doesn't contain invalid css")
   311  }
   312  

View as plain text