2014-09-10 13:30:03 -04:00
|
|
|
|
package helpers
|
|
|
|
|
|
|
|
|
|
import (
|
2015-03-29 15:12:13 -04:00
|
|
|
|
"bytes"
|
2015-01-20 11:44:35 -05:00
|
|
|
|
"github.com/stretchr/testify/assert"
|
2015-03-29 15:12:13 -04:00
|
|
|
|
"io/ioutil"
|
2014-12-26 15:18:26 -05:00
|
|
|
|
"reflect"
|
2015-01-07 15:40:35 -05:00
|
|
|
|
"strings"
|
2014-09-10 13:30:03 -04:00
|
|
|
|
"testing"
|
|
|
|
|
)
|
|
|
|
|
|
2015-01-20 11:44:35 -05:00
|
|
|
|
func TestGuessType(t *testing.T) {
|
|
|
|
|
for i, this := range []struct {
|
|
|
|
|
in string
|
|
|
|
|
expect string
|
|
|
|
|
}{
|
|
|
|
|
{"md", "markdown"},
|
|
|
|
|
{"markdown", "markdown"},
|
|
|
|
|
{"mdown", "markdown"},
|
Experimental AsciiDoc support with external helpers
See #470
* Based on existing support for reStructuredText files
* Handles content files with extensions `.asciidoc` and `.ad`
* Pipes content through `asciidoctor --safe -`.
If `asciidoctor` is not installed, then `asciidoc --safe -`.
* To make sure `asciidoctor` or `asciidoc` is found, after adding
a piece of AsciiDoc content, run `hugo` with the `-v` flag
and look for this message:
INFO: 2015/01/23 Rendering with /usr/bin/asciidoctor ...
Caveats:
* The final "Last updated" timestamp is currently not stripped.
* When `hugo` is run with `-v`, you may see a lot of these messages
INFO: 2015/01/23 Rendering with /usr/bin/asciidoctor ...
if you have lots of `*.ad`, `*.adoc` or `*.asciidoc` files.
* Some versions of `asciidoc` may have trouble with its safe mode.
To test if you are affected, try this:
$ echo "Hello" | asciidoc --safe -
asciidoc: ERROR: unsafe: ifeval invalid
asciidoc: FAILED: ifeval invalid safe document
If so, I recommend that you install `asciidoctor` instead.
Feedback and patches welcome!
Ideally, we should be using https://github.com/VonC/asciidocgo,
@VonC's wonderful Go implementation of Asciidoctor. However,
there is still a bit of work needed for asciidocgo to expose
its API so that Hugo can actually use it.
Until then, hope this "experimental AsciiDoc support through external
helpers" can serve as a stopgap solution for our community. :-)
2015-01-30: Updated for the replaceShortcodeTokens() syntax change
2015-02-21: Add `.adoc` extension as suggested by @Fale
Conflicts:
helpers/content.go
2015-01-23 13:59:14 -05:00
|
|
|
|
{"asciidoc", "asciidoc"},
|
|
|
|
|
{"adoc", "asciidoc"},
|
|
|
|
|
{"ad", "asciidoc"},
|
2015-01-20 11:44:35 -05:00
|
|
|
|
{"rst", "rst"},
|
2015-01-30 09:17:50 -05:00
|
|
|
|
{"mmark", "mmark"},
|
2015-01-20 11:44:35 -05:00
|
|
|
|
{"html", "html"},
|
|
|
|
|
{"htm", "html"},
|
|
|
|
|
{"excel", "unknown"},
|
|
|
|
|
} {
|
|
|
|
|
result := GuessType(this.in)
|
|
|
|
|
if result != this.expect {
|
2015-04-05 15:03:16 -04:00
|
|
|
|
t.Errorf("[%d] got %s but expected %s", i, result, this.expect)
|
2015-01-20 11:44:35 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestBytesToReader(t *testing.T) {
|
|
|
|
|
asBytes := ReaderToBytes(strings.NewReader("Hello World!"))
|
|
|
|
|
asReader := BytesToReader(asBytes)
|
|
|
|
|
assert.Equal(t, []byte("Hello World!"), asBytes)
|
|
|
|
|
assert.Equal(t, asBytes, ReaderToBytes(asReader))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestStringToReader(t *testing.T) {
|
|
|
|
|
asString := ReaderToString(strings.NewReader("Hello World!"))
|
|
|
|
|
assert.Equal(t, "Hello World!", asString)
|
|
|
|
|
asReader := StringToReader(asString)
|
|
|
|
|
assert.Equal(t, asString, ReaderToString(asReader))
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-29 15:12:13 -04:00
|
|
|
|
var containsTestText = (`На берегу пустынных волн
|
|
|
|
|
Стоял он, дум великих полн,
|
|
|
|
|
И вдаль глядел. Пред ним широко
|
|
|
|
|
Река неслася; бедный чёлн
|
|
|
|
|
По ней стремился одиноко.
|
|
|
|
|
По мшистым, топким берегам
|
|
|
|
|
Чернели избы здесь и там,
|
|
|
|
|
Приют убогого чухонца;
|
|
|
|
|
И лес, неведомый лучам
|
|
|
|
|
В тумане спрятанного солнца,
|
|
|
|
|
Кругом шумел.
|
|
|
|
|
|
|
|
|
|
Τη γλώσσα μου έδωσαν ελληνική
|
|
|
|
|
το σπίτι φτωχικό στις αμμουδιές του Ομήρου.
|
|
|
|
|
Μονάχη έγνοια η γλώσσα μου στις αμμουδιές του Ομήρου.
|
|
|
|
|
|
|
|
|
|
από το Άξιον Εστί
|
|
|
|
|
του Οδυσσέα Ελύτη
|
|
|
|
|
|
|
|
|
|
Sîne klâwen durh die wolken sint geslagen,
|
|
|
|
|
er stîget ûf mit grôzer kraft,
|
|
|
|
|
ich sih in grâwen tägelîch als er wil tagen,
|
|
|
|
|
den tac, der im geselleschaft
|
|
|
|
|
erwenden wil, dem werden man,
|
|
|
|
|
den ich mit sorgen în verliez.
|
|
|
|
|
ich bringe in hinnen, ob ich kan.
|
|
|
|
|
sîn vil manegiu tugent michz leisten hiez.
|
|
|
|
|
`)
|
|
|
|
|
|
|
|
|
|
var containsBenchTestData = []struct {
|
|
|
|
|
v1 string
|
|
|
|
|
v2 []byte
|
|
|
|
|
expect bool
|
|
|
|
|
}{
|
|
|
|
|
{"abc", []byte("a"), true},
|
|
|
|
|
{"abc", []byte("b"), true},
|
|
|
|
|
{"abcdefg", []byte("efg"), true},
|
|
|
|
|
{"abc", []byte("d"), false},
|
|
|
|
|
{containsTestText, []byte("стремился"), true},
|
|
|
|
|
{containsTestText, []byte(containsTestText[10:80]), true},
|
2015-03-29 19:22:08 -04:00
|
|
|
|
{containsTestText, []byte(containsTestText[100:111]), true},
|
2015-03-29 15:12:13 -04:00
|
|
|
|
{containsTestText, []byte(containsTestText[len(containsTestText)-100 : len(containsTestText)-10]), true},
|
|
|
|
|
{containsTestText, []byte(containsTestText[len(containsTestText)-20:]), true},
|
|
|
|
|
{containsTestText, []byte("notfound"), false},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// some corner cases
|
|
|
|
|
var containsAdditionalTestData = []struct {
|
|
|
|
|
v1 string
|
|
|
|
|
v2 []byte
|
|
|
|
|
expect bool
|
|
|
|
|
}{
|
2015-03-29 19:22:08 -04:00
|
|
|
|
{"", nil, false},
|
2015-03-29 15:12:13 -04:00
|
|
|
|
{"", []byte("a"), false},
|
|
|
|
|
{"a", []byte(""), false},
|
|
|
|
|
{"", []byte(""), false},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestReaderContains(t *testing.T) {
|
|
|
|
|
for i, this := range append(containsBenchTestData, containsAdditionalTestData...) {
|
|
|
|
|
result := ReaderContains(StringToReader(this.v1), this.v2)
|
|
|
|
|
if result != this.expect {
|
2015-04-05 15:03:16 -04:00
|
|
|
|
t.Errorf("[%d] got %t but expected %t", i, result, this.expect)
|
2015-03-29 15:12:13 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-03-29 19:22:08 -04:00
|
|
|
|
|
|
|
|
|
assert.False(t, ReaderContains(nil, []byte("a")))
|
|
|
|
|
assert.False(t, ReaderContains(nil, nil))
|
2015-03-29 15:12:13 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func BenchmarkReaderContains(b *testing.B) {
|
|
|
|
|
b.ResetTimer()
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
|
for i, this := range containsBenchTestData {
|
|
|
|
|
result := ReaderContains(StringToReader(this.v1), this.v2)
|
|
|
|
|
if result != this.expect {
|
2015-04-05 15:03:16 -04:00
|
|
|
|
b.Errorf("[%d] got %t but expected %t", i, result, this.expect)
|
2015-03-29 15:12:13 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// kept to compare the above
|
|
|
|
|
func _BenchmarkReaderContains(b *testing.B) {
|
|
|
|
|
b.ResetTimer()
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
|
for i, this := range containsBenchTestData {
|
|
|
|
|
bs, err := ioutil.ReadAll(StringToReader(this.v1))
|
|
|
|
|
if err != nil {
|
|
|
|
|
b.Fatalf("Failed %s", err)
|
|
|
|
|
}
|
|
|
|
|
result := bytes.Contains(bs, this.v2)
|
|
|
|
|
if result != this.expect {
|
2015-04-05 15:03:16 -04:00
|
|
|
|
b.Errorf("[%d] got %t but expected %t", i, result, this.expect)
|
2015-03-29 15:12:13 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-20 11:44:35 -05:00
|
|
|
|
func TestFindAvailablePort(t *testing.T) {
|
|
|
|
|
addr, err := FindAvailablePort()
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
assert.NotNil(t, addr)
|
|
|
|
|
assert.True(t, addr.Port > 0)
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-07 15:40:35 -05:00
|
|
|
|
func TestInStringArrayCaseSensitive(t *testing.T) {
|
2014-09-10 13:30:03 -04:00
|
|
|
|
type test struct {
|
2015-01-07 15:40:35 -05:00
|
|
|
|
input string
|
|
|
|
|
expected bool
|
|
|
|
|
}
|
|
|
|
|
array := []string{
|
|
|
|
|
"Albert",
|
|
|
|
|
"Joe",
|
|
|
|
|
"Francis",
|
2014-09-10 13:30:03 -04:00
|
|
|
|
}
|
|
|
|
|
data := []test{
|
2015-01-07 15:40:35 -05:00
|
|
|
|
{"Albert", true},
|
|
|
|
|
{"ALBERT", false},
|
|
|
|
|
}
|
2015-04-05 15:03:16 -04:00
|
|
|
|
for i, in := range data {
|
2015-01-07 15:40:35 -05:00
|
|
|
|
output := InStringArray(array, in.input)
|
|
|
|
|
if output != in.expected {
|
2015-04-05 15:03:16 -04:00
|
|
|
|
t.Errorf("[%d] got %t but expected %t", i, output, in.expected)
|
2015-01-07 15:40:35 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestSliceToLowerStable(t *testing.T) {
|
|
|
|
|
input := []string{
|
|
|
|
|
"New York",
|
|
|
|
|
"BARCELONA",
|
|
|
|
|
"COffEE",
|
|
|
|
|
"FLOWer",
|
|
|
|
|
"CanDY",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
output := SliceToLower(input)
|
|
|
|
|
|
|
|
|
|
for i, e := range output {
|
|
|
|
|
if e != strings.ToLower(input[i]) {
|
|
|
|
|
t.Errorf("Expected %s. Found %s.", strings.ToLower(input[i]), e)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestSliceToLowerNil(t *testing.T) {
|
|
|
|
|
var input []string
|
|
|
|
|
|
|
|
|
|
output := SliceToLower(input)
|
|
|
|
|
|
|
|
|
|
if output != nil {
|
|
|
|
|
t.Errorf("Expected nil to be returned. Had %s.", output)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestSliceToLowerNonDestructive(t *testing.T) {
|
|
|
|
|
input := []string{
|
|
|
|
|
"New York",
|
|
|
|
|
"BARCELONA",
|
|
|
|
|
"COffEE",
|
|
|
|
|
"FLOWer",
|
|
|
|
|
"CanDY",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This assignment actually copies the content
|
|
|
|
|
// of input into a new object.
|
|
|
|
|
// Otherwise, the test would not make sense...
|
2015-03-06 18:02:06 -05:00
|
|
|
|
inputCopy := input
|
2015-01-07 15:40:35 -05:00
|
|
|
|
|
|
|
|
|
SliceToLower(input)
|
|
|
|
|
|
|
|
|
|
for i, e := range input {
|
2015-03-06 18:02:06 -05:00
|
|
|
|
if e != inputCopy[i] {
|
|
|
|
|
t.Errorf("TestSliceToLowerNonDestructive failed. Expected element #%d of input slice to be %s. Found %s.", i, inputCopy[i], input[i])
|
2014-09-10 13:30:03 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-01-07 15:40:35 -05:00
|
|
|
|
|
|
|
|
|
// Just make sure there is no error for empty-like strings
|
|
|
|
|
func TestMd5StringEmpty(t *testing.T) {
|
|
|
|
|
inputs := []string{"", " ", " "}
|
|
|
|
|
|
|
|
|
|
for _, in := range inputs {
|
|
|
|
|
Md5String(in)
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-12-26 15:18:26 -05:00
|
|
|
|
|
2015-02-24 04:56:16 -05:00
|
|
|
|
func TestSeq(t *testing.T) {
|
|
|
|
|
for i, this := range []struct {
|
|
|
|
|
in []interface{}
|
|
|
|
|
expect interface{}
|
|
|
|
|
}{
|
|
|
|
|
{[]interface{}{-2, 5}, []int{-2, -1, 0, 1, 2, 3, 4, 5}},
|
|
|
|
|
{[]interface{}{1, 2, 4}, []int{1, 3}},
|
|
|
|
|
{[]interface{}{1}, []int{1}},
|
|
|
|
|
{[]interface{}{3}, []int{1, 2, 3}},
|
|
|
|
|
{[]interface{}{3.2}, []int{1, 2, 3}},
|
|
|
|
|
{[]interface{}{0}, []int{}},
|
|
|
|
|
{[]interface{}{-1}, []int{-1}},
|
|
|
|
|
{[]interface{}{-3}, []int{-1, -2, -3}},
|
|
|
|
|
{[]interface{}{3, -2}, []int{3, 2, 1, 0, -1, -2}},
|
|
|
|
|
{[]interface{}{6, -2, 2}, []int{6, 4, 2}},
|
|
|
|
|
{[]interface{}{1, 0, 2}, false},
|
|
|
|
|
{[]interface{}{1, -1, 2}, false},
|
|
|
|
|
{[]interface{}{2, 1, 1}, false},
|
|
|
|
|
{[]interface{}{2, 1, 1, 1}, false},
|
|
|
|
|
{[]interface{}{2001}, false},
|
|
|
|
|
{[]interface{}{}, false},
|
2015-03-18 07:42:00 -04:00
|
|
|
|
// TODO(bep) {[]interface{}{t}, false},
|
2015-02-24 04:56:16 -05:00
|
|
|
|
{nil, false},
|
|
|
|
|
} {
|
|
|
|
|
|
|
|
|
|
result, err := Seq(this.in...)
|
|
|
|
|
|
|
|
|
|
if b, ok := this.expect.(bool); ok && !b {
|
|
|
|
|
if err == nil {
|
2015-04-03 15:20:27 -04:00
|
|
|
|
t.Errorf("[%d] TestSeq didn't return an expected error", i)
|
2015-02-24 04:56:16 -05:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("[%d] failed: %s", i, err)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if !reflect.DeepEqual(result, this.expect) {
|
|
|
|
|
t.Errorf("[%d] TestSeq got %v but expected %v", i, result, this.expect)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-26 15:18:26 -05:00
|
|
|
|
func TestDoArithmetic(t *testing.T) {
|
|
|
|
|
for i, this := range []struct {
|
|
|
|
|
a interface{}
|
|
|
|
|
b interface{}
|
|
|
|
|
op rune
|
|
|
|
|
expect interface{}
|
|
|
|
|
}{
|
|
|
|
|
{3, 2, '+', int64(5)},
|
|
|
|
|
{3, 2, '-', int64(1)},
|
|
|
|
|
{3, 2, '*', int64(6)},
|
|
|
|
|
{3, 2, '/', int64(1)},
|
|
|
|
|
{3.0, 2, '+', float64(5)},
|
|
|
|
|
{3.0, 2, '-', float64(1)},
|
|
|
|
|
{3.0, 2, '*', float64(6)},
|
|
|
|
|
{3.0, 2, '/', float64(1.5)},
|
|
|
|
|
{3, 2.0, '+', float64(5)},
|
|
|
|
|
{3, 2.0, '-', float64(1)},
|
|
|
|
|
{3, 2.0, '*', float64(6)},
|
|
|
|
|
{3, 2.0, '/', float64(1.5)},
|
|
|
|
|
{3.0, 2.0, '+', float64(5)},
|
|
|
|
|
{3.0, 2.0, '-', float64(1)},
|
|
|
|
|
{3.0, 2.0, '*', float64(6)},
|
|
|
|
|
{3.0, 2.0, '/', float64(1.5)},
|
|
|
|
|
{uint(3), uint(2), '+', uint64(5)},
|
|
|
|
|
{uint(3), uint(2), '-', uint64(1)},
|
|
|
|
|
{uint(3), uint(2), '*', uint64(6)},
|
|
|
|
|
{uint(3), uint(2), '/', uint64(1)},
|
|
|
|
|
{uint(3), 2, '+', uint64(5)},
|
|
|
|
|
{uint(3), 2, '-', uint64(1)},
|
|
|
|
|
{uint(3), 2, '*', uint64(6)},
|
|
|
|
|
{uint(3), 2, '/', uint64(1)},
|
|
|
|
|
{3, uint(2), '+', uint64(5)},
|
|
|
|
|
{3, uint(2), '-', uint64(1)},
|
|
|
|
|
{3, uint(2), '*', uint64(6)},
|
|
|
|
|
{3, uint(2), '/', uint64(1)},
|
|
|
|
|
{uint(3), -2, '+', int64(1)},
|
|
|
|
|
{uint(3), -2, '-', int64(5)},
|
|
|
|
|
{uint(3), -2, '*', int64(-6)},
|
|
|
|
|
{uint(3), -2, '/', int64(-1)},
|
|
|
|
|
{-3, uint(2), '+', int64(-1)},
|
|
|
|
|
{-3, uint(2), '-', int64(-5)},
|
|
|
|
|
{-3, uint(2), '*', int64(-6)},
|
|
|
|
|
{-3, uint(2), '/', int64(-1)},
|
|
|
|
|
{uint(3), 2.0, '+', float64(5)},
|
|
|
|
|
{uint(3), 2.0, '-', float64(1)},
|
|
|
|
|
{uint(3), 2.0, '*', float64(6)},
|
|
|
|
|
{uint(3), 2.0, '/', float64(1.5)},
|
|
|
|
|
{3.0, uint(2), '+', float64(5)},
|
|
|
|
|
{3.0, uint(2), '-', float64(1)},
|
|
|
|
|
{3.0, uint(2), '*', float64(6)},
|
|
|
|
|
{3.0, uint(2), '/', float64(1.5)},
|
|
|
|
|
{0, 0, '+', 0},
|
|
|
|
|
{0, 0, '-', 0},
|
|
|
|
|
{0, 0, '*', 0},
|
|
|
|
|
{"foo", "bar", '+', "foobar"},
|
|
|
|
|
{3, 0, '/', false},
|
|
|
|
|
{3.0, 0, '/', false},
|
|
|
|
|
{3, 0.0, '/', false},
|
|
|
|
|
{uint(3), uint(0), '/', false},
|
|
|
|
|
{3, uint(0), '/', false},
|
|
|
|
|
{-3, uint(0), '/', false},
|
|
|
|
|
{uint(3), 0, '/', false},
|
|
|
|
|
{3.0, uint(0), '/', false},
|
|
|
|
|
{uint(3), 0.0, '/', false},
|
|
|
|
|
{3, "foo", '+', false},
|
|
|
|
|
{3.0, "foo", '+', false},
|
|
|
|
|
{uint(3), "foo", '+', false},
|
|
|
|
|
{"foo", 3, '+', false},
|
|
|
|
|
{"foo", "bar", '-', false},
|
|
|
|
|
{3, 2, '%', false},
|
|
|
|
|
} {
|
|
|
|
|
result, err := DoArithmetic(this.a, this.b, this.op)
|
|
|
|
|
if b, ok := this.expect.(bool); ok && !b {
|
|
|
|
|
if err == nil {
|
2015-03-06 08:56:44 -05:00
|
|
|
|
t.Errorf("[%d] doArithmetic didn't return an expected error", i)
|
2014-12-26 15:18:26 -05:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("[%d] failed: %s", i, err)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if !reflect.DeepEqual(result, this.expect) {
|
|
|
|
|
t.Errorf("[%d] doArithmetic got %v but expected %v", i, result, this.expect)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|