1// Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
2// Use of this source code is governed by a MIT style
3// license that can be found in the LICENSE file.
4
5package gin
6
7import (
8	"bytes"
9	"errors"
10	"html/template"
11	"io"
12	"log"
13	"os"
14	"runtime"
15	"sync"
16	"testing"
17
18	"github.com/stretchr/testify/assert"
19)
20
21// TODO
22// func debugRoute(httpMethod, absolutePath string, handlers HandlersChain) {
23// func debugPrint(format string, values ...interface{}) {
24
25func TestIsDebugging(t *testing.T) {
26	SetMode(DebugMode)
27	assert.True(t, IsDebugging())
28	SetMode(ReleaseMode)
29	assert.False(t, IsDebugging())
30	SetMode(TestMode)
31	assert.False(t, IsDebugging())
32}
33
34func TestDebugPrint(t *testing.T) {
35	re := captureOutput(t, func() {
36		SetMode(DebugMode)
37		SetMode(ReleaseMode)
38		debugPrint("DEBUG this!")
39		SetMode(TestMode)
40		debugPrint("DEBUG this!")
41		SetMode(DebugMode)
42		debugPrint("these are %d %s", 2, "error messages")
43		SetMode(TestMode)
44	})
45	assert.Equal(t, "[GIN-debug] these are 2 error messages\n", re)
46}
47
48func TestDebugPrintError(t *testing.T) {
49	re := captureOutput(t, func() {
50		SetMode(DebugMode)
51		debugPrintError(nil)
52		debugPrintError(errors.New("this is an error"))
53		SetMode(TestMode)
54	})
55	assert.Equal(t, "[GIN-debug] [ERROR] this is an error\n", re)
56}
57
58func TestDebugPrintRoutes(t *testing.T) {
59	re := captureOutput(t, func() {
60		SetMode(DebugMode)
61		debugPrintRoute("GET", "/path/to/route/:param", HandlersChain{func(c *Context) {}, handlerNameTest})
62		SetMode(TestMode)
63	})
64	assert.Regexp(t, `^\[GIN-debug\] GET    /path/to/route/:param     --> (.*/vendor/)?github.com/gin-gonic/gin.handlerNameTest \(2 handlers\)\n$`, re)
65}
66
67func TestDebugPrintLoadTemplate(t *testing.T) {
68	re := captureOutput(t, func() {
69		SetMode(DebugMode)
70		templ := template.Must(template.New("").Delims("{[{", "}]}").ParseGlob("./testdata/template/hello.tmpl"))
71		debugPrintLoadTemplate(templ)
72		SetMode(TestMode)
73	})
74	assert.Regexp(t, `^\[GIN-debug\] Loaded HTML Templates \(2\): \n(\t- \n|\t- hello\.tmpl\n){2}\n`, re)
75}
76
77func TestDebugPrintWARNINGSetHTMLTemplate(t *testing.T) {
78	re := captureOutput(t, func() {
79		SetMode(DebugMode)
80		debugPrintWARNINGSetHTMLTemplate()
81		SetMode(TestMode)
82	})
83	assert.Equal(t, "[GIN-debug] [WARNING] Since SetHTMLTemplate() is NOT thread-safe. It should only be called\nat initialization. ie. before any route is registered or the router is listening in a socket:\n\n\trouter := gin.Default()\n\trouter.SetHTMLTemplate(template) // << good place\n\n", re)
84}
85
86func TestDebugPrintWARNINGDefault(t *testing.T) {
87	re := captureOutput(t, func() {
88		SetMode(DebugMode)
89		debugPrintWARNINGDefault()
90		SetMode(TestMode)
91	})
92	m, e := getMinVer(runtime.Version())
93	if e == nil && m <= ginSupportMinGoVer {
94		assert.Equal(t, "[GIN-debug] [WARNING] Now Gin requires Go 1.11 or later and Go 1.12 will be required soon.\n\n[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re)
95	} else {
96		assert.Equal(t, "[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re)
97	}
98}
99
100func TestDebugPrintWARNINGNew(t *testing.T) {
101	re := captureOutput(t, func() {
102		SetMode(DebugMode)
103		debugPrintWARNINGNew()
104		SetMode(TestMode)
105	})
106	assert.Equal(t, "[GIN-debug] [WARNING] Running in \"debug\" mode. Switch to \"release\" mode in production.\n - using env:\texport GIN_MODE=release\n - using code:\tgin.SetMode(gin.ReleaseMode)\n\n", re)
107}
108
109func captureOutput(t *testing.T, f func()) string {
110	reader, writer, err := os.Pipe()
111	if err != nil {
112		panic(err)
113	}
114	defaultWriter := DefaultWriter
115	defaultErrorWriter := DefaultErrorWriter
116	defer func() {
117		DefaultWriter = defaultWriter
118		DefaultErrorWriter = defaultErrorWriter
119		log.SetOutput(os.Stderr)
120	}()
121	DefaultWriter = writer
122	DefaultErrorWriter = writer
123	log.SetOutput(writer)
124	out := make(chan string)
125	wg := new(sync.WaitGroup)
126	wg.Add(1)
127	go func() {
128		var buf bytes.Buffer
129		wg.Done()
130		_, err := io.Copy(&buf, reader)
131		assert.NoError(t, err)
132		out <- buf.String()
133	}()
134	wg.Wait()
135	f()
136	writer.Close()
137	return <-out
138}
139
140func TestGetMinVer(t *testing.T) {
141	var m uint64
142	var e error
143	_, e = getMinVer("go1")
144	assert.NotNil(t, e)
145	m, e = getMinVer("go1.1")
146	assert.Equal(t, uint64(1), m)
147	assert.Nil(t, e)
148	m, e = getMinVer("go1.1.1")
149	assert.Nil(t, e)
150	assert.Equal(t, uint64(1), m)
151	_, e = getMinVer("go1.1.1.1")
152	assert.NotNil(t, e)
153}
154