feat(debug): expose Log via environment

This commit is contained in:
Jan De Dobbeleer 2022-05-12 20:12:25 +02:00 committed by Jan De Dobbeleer
parent 9c5cc42622
commit 69ae95affc
11 changed files with 76 additions and 60 deletions

View file

@ -35,13 +35,13 @@ func (env *ShellEnvironment) parseBatteryOutput(output string) (*BatteryInfo, er
matches := regex.FindNamedRegexMatch(`(?P<PERCENTAGE>[0-9]{1,3})%; (?P<STATE>[a-zA-Z\s]+);`, output)
if len(matches) != 2 {
msg := "Unable to find battery state based on output"
env.log(Error, "BatteryInfo", msg)
env.Log(Error, "BatteryInfo", msg)
return nil, errors.New(msg)
}
var percentage int
var err error
if percentage, err = strconv.Atoi(matches["PERCENTAGE"]); err != nil {
env.log(Error, "BatteryInfo", err.Error())
env.Log(Error, "BatteryInfo", err.Error())
return nil, errors.New("Unable to parse battery percentage")
}
return &BatteryInfo{
@ -54,7 +54,7 @@ func (env *ShellEnvironment) BatteryState() (*BatteryInfo, error) {
defer env.Trace(time.Now(), "BatteryInfo")
output, err := env.RunCommand("pmset", "-g", "batt")
if err != nil {
env.log(Error, "BatteryInfo", err.Error())
env.Log(Error, "BatteryInfo", err.Error())
return nil, err
}
if !strings.Contains(output, "Battery") {

View file

@ -189,6 +189,7 @@ type Environment interface {
ConvertToWindowsPath(path string) string
WifiNetwork() (*WifiInfo, error)
TemplateCache() *TemplateCache
Log(logType LogType, funcName, message string)
Trace(start time.Time, function string, args ...string)
}
@ -209,11 +210,11 @@ func (c *commandCache) get(command string) (string, bool) {
return command, ok
}
type logType string
type LogType string
const (
Error logType = "error"
Debug logType = "debug"
Error LogType = "error"
Debug LogType = "debug"
)
type ShellEnvironment struct {
@ -305,11 +306,11 @@ func (env *ShellEnvironment) Trace(start time.Time, function string, args ...str
log.Println(trace)
}
func (env *ShellEnvironment) log(lt logType, function, message string) {
func (env *ShellEnvironment) Log(logType LogType, funcName, message string) {
if !env.CmdFlags.Debug {
return
}
trace := fmt.Sprintf("%s: %s\n%s", lt, function, message)
trace := fmt.Sprintf("%s: %s\n%s", logType, funcName, message)
log.Println(trace)
}
@ -324,7 +325,7 @@ func (env *ShellEnvironment) debugF(function string, fn func() string) {
func (env *ShellEnvironment) Getenv(key string) string {
defer env.Trace(time.Now(), "Getenv", key)
val := os.Getenv(key)
env.log(Debug, "Getenv", val)
env.Log(Debug, "Getenv", val)
return val
}
@ -333,7 +334,7 @@ func (env *ShellEnvironment) Pwd() string {
lock.Lock()
defer func() {
lock.Unlock()
env.log(Debug, "Pwd", env.cwd)
env.Log(Debug, "Pwd", env.cwd)
}()
if env.cwd != "" {
return env.cwd
@ -349,7 +350,7 @@ func (env *ShellEnvironment) Pwd() string {
}
dir, err := os.Getwd()
if err != nil {
env.log(Error, "Pwd", err.Error())
env.Log(Error, "Pwd", err.Error())
return ""
}
env.cwd = correctPath(dir)
@ -362,7 +363,7 @@ func (env *ShellEnvironment) HasFiles(pattern string) bool {
pattern = cwd + env.PathSeparator() + pattern
matches, err := filepath.Glob(pattern)
if err != nil {
env.log(Error, "HasFiles", err.Error())
env.Log(Error, "HasFiles", err.Error())
return false
}
for _, match := range matches {
@ -370,10 +371,10 @@ func (env *ShellEnvironment) HasFiles(pattern string) bool {
if f.IsDir() {
continue
}
env.log(Debug, "HasFiles", "true")
env.Log(Debug, "HasFiles", "true")
return true
}
env.log(Debug, "HasFiles", "false")
env.Log(Debug, "HasFiles", "false")
return false
}
@ -382,7 +383,7 @@ func (env *ShellEnvironment) HasFilesInDir(dir, pattern string) bool {
pattern = dir + env.PathSeparator() + pattern
matches, err := filepath.Glob(pattern)
if err != nil {
env.log(Error, "HasFilesInDir", err.Error())
env.Log(Error, "HasFilesInDir", err.Error())
return false
}
hasFilesInDir := len(matches) > 0
@ -396,18 +397,18 @@ func (env *ShellEnvironment) HasFileInParentDirs(pattern string, depth uint) boo
for c := 0; c < int(depth); c++ {
if env.HasFilesInDir(currentFolder, pattern) {
env.log(Debug, "HasFileInParentDirs", "true")
env.Log(Debug, "HasFileInParentDirs", "true")
return true
}
if dir := filepath.Dir(currentFolder); dir != currentFolder {
currentFolder = dir
} else {
env.log(Debug, "HasFileInParentDirs", "false")
env.Log(Debug, "HasFileInParentDirs", "false")
return false
}
}
env.log(Debug, "HasFileInParentDirs", "false")
env.Log(Debug, "HasFileInParentDirs", "false")
return false
}
@ -415,7 +416,7 @@ func (env *ShellEnvironment) HasFolder(folder string) bool {
defer env.Trace(time.Now(), "HasFolder", folder)
f, err := os.Stat(folder)
if err != nil {
env.log(Debug, "HasFolder", "false")
env.Log(Debug, "HasFolder", "false")
return false
}
env.debugF("HasFolder", func() string { return strconv.FormatBool(f.IsDir()) })
@ -433,11 +434,11 @@ func (env *ShellEnvironment) FileContent(file string) string {
}
content, err := ioutil.ReadFile(file)
if err != nil {
env.log(Error, "FileContent", err.Error())
env.Log(Error, "FileContent", err.Error())
return ""
}
fileContent := string(content)
env.log(Debug, "FileContent", fileContent)
env.Log(Debug, "FileContent", fileContent)
return fileContent
}
@ -445,7 +446,7 @@ func (env *ShellEnvironment) LsDir(path string) []fs.DirEntry {
defer env.Trace(time.Now(), "LsDir", path)
entries, err := os.ReadDir(path)
if err != nil {
env.log(Error, "LsDir", err.Error())
env.Log(Error, "LsDir", err.Error())
return nil
}
env.debugF("LsDir", func() string {
@ -469,7 +470,7 @@ func (env *ShellEnvironment) User() string {
if user == "" {
user = os.Getenv("USERNAME")
}
env.log(Debug, "User", user)
env.Log(Debug, "User", user)
return user
}
@ -477,11 +478,11 @@ func (env *ShellEnvironment) Host() (string, error) {
defer env.Trace(time.Now(), "Host")
hostName, err := os.Hostname()
if err != nil {
env.log(Error, "Host", err.Error())
env.Log(Error, "Host", err.Error())
return "", err
}
hostName = cleanHostName(hostName)
env.log(Debug, "Host", hostName)
env.Log(Debug, "Host", hostName)
return hostName, nil
}
@ -504,7 +505,7 @@ func (env *ShellEnvironment) RunCommand(command string, args ...string) (string,
if cmdErr != nil {
output := err.String()
errorStr := fmt.Sprintf("cmd.Start() failed with '%s'", output)
env.log(Error, "RunCommand", errorStr)
env.Log(Error, "RunCommand", errorStr)
return output, cmdErr
}
// some silly commands return 0 and the output is in stderr instead of stdout
@ -513,7 +514,7 @@ func (env *ShellEnvironment) RunCommand(command string, args ...string) (string,
result = err.String()
}
output := strings.TrimSpace(result)
env.log(Debug, "RunCommand", output)
env.Log(Debug, "RunCommand", output)
return output, nil
}
@ -540,7 +541,7 @@ func (env *ShellEnvironment) CommandPath(command string) string {
env.cmdCache.set(command, path)
return path
}
env.log(Error, "CommandPath", err.Error())
env.Log(Error, "CommandPath", err.Error())
return ""
}
@ -578,7 +579,7 @@ func (env *ShellEnvironment) Shell() string {
p, _ := process.NewProcess(int32(pid))
name, err := p.Name()
if err != nil {
env.log(Error, "Shell", err.Error())
env.Log(Error, "Shell", err.Error())
return Unknown
}
if name == "cmd.exe" {
@ -586,7 +587,7 @@ func (env *ShellEnvironment) Shell() string {
name, err = p.Name()
}
if err != nil {
env.log(Error, "Shell", err.Error())
env.Log(Error, "Shell", err.Error())
return Unknown
}
// Cache the shell value to speed things up.
@ -607,23 +608,23 @@ func (env *ShellEnvironment) HTTPRequest(targetURL string, timeout int, requestM
}
response, err := client.Do(request)
if err != nil {
env.log(Error, "HTTPRequest", err.Error())
env.Log(Error, "HTTPRequest", err.Error())
return nil, err
}
// anything inside the range [200, 299] is considered a success
if response.StatusCode < 200 || response.StatusCode >= 300 {
message := "HTTP status code " + strconv.Itoa(response.StatusCode)
err := errors.New(message)
env.log(Error, "HTTPRequest", message)
env.Log(Error, "HTTPRequest", message)
return nil, err
}
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
if err != nil {
env.log(Error, "HTTPRequest", err.Error())
env.Log(Error, "HTTPRequest", err.Error())
return nil, err
}
env.log(Debug, "HTTPRequest", string(body))
env.Log(Debug, "HTTPRequest", string(body))
return body, nil
}
@ -647,7 +648,7 @@ func (env *ShellEnvironment) HasParentFilePath(path string) (*FileInfo, error) {
currentFolder = dir
continue
}
env.log(Error, "HasParentFilePath", err.Error())
env.Log(Error, "HasParentFilePath", err.Error())
return nil, errors.New("no match at root level")
}
}
@ -722,7 +723,7 @@ func (env *ShellEnvironment) DirMatchesOneOf(dir string, regexes []string) (matc
defer func() {
if err := recover(); err != nil {
message := fmt.Sprintf("%s", err)
env.log(Error, "DirMatchesOneOf", message)
env.Log(Error, "DirMatchesOneOf", message)
match = false
}
}()

View file

@ -50,7 +50,7 @@ func (env *ShellEnvironment) TerminalWidth() (int, error) {
}
width, err := terminal.Width()
if err != nil {
env.log(Error, "TerminalWidth", err.Error())
env.Log(Error, "TerminalWidth", err.Error())
}
return int(width), err
}

View file

@ -33,7 +33,7 @@ func (env *ShellEnvironment) Root() bool {
0, 0, 0, 0, 0, 0,
&sid)
if err != nil {
env.log(Error, "Root", err.Error())
env.Log(Error, "Root", err.Error())
return false
}
defer func() {
@ -47,7 +47,7 @@ func (env *ShellEnvironment) Root() bool {
member, err := token.IsMember(sid)
if err != nil {
env.log(Error, "Root", err.Error())
env.Log(Error, "Root", err.Error())
return false
}
@ -57,7 +57,7 @@ func (env *ShellEnvironment) Root() bool {
func (env *ShellEnvironment) Home() string {
home := os.Getenv("HOME")
defer func() {
env.log(Debug, "Home", home)
env.Log(Debug, "Home", home)
}()
if len(home) > 0 {
return home
@ -74,7 +74,7 @@ func (env *ShellEnvironment) QueryWindowTitles(processName, windowTitleRegex str
defer env.Trace(time.Now(), "WindowTitle", windowTitleRegex)
title, err := queryWindowTitles(processName, windowTitleRegex)
if err != nil {
env.log(Error, "QueryWindowTitles", err.Error())
env.Log(Error, "QueryWindowTitles", err.Error())
}
return title, err
}
@ -96,12 +96,12 @@ func (env *ShellEnvironment) TerminalWidth() (int, error) {
}
handle, err := syscall.Open("CONOUT$", syscall.O_RDWR, 0)
if err != nil {
env.log(Error, "TerminalWidth", err.Error())
env.Log(Error, "TerminalWidth", err.Error())
return 0, err
}
info, err := winterm.GetConsoleScreenBufferInfo(uintptr(handle))
if err != nil {
env.log(Error, "TerminalWidth", err.Error())
env.Log(Error, "TerminalWidth", err.Error())
return 0, err
}
// return int(float64(info.Size.X) * 0.57), nil
@ -163,14 +163,14 @@ func (env *ShellEnvironment) WindowsRegistryKeyValue(path string) (*WindowsRegis
if len(regPathParts) < 2 {
errorLogMsg := fmt.Sprintf("Error, malformed registry path: '%s'", path)
env.log(Error, "WindowsRegistryKeyValue", errorLogMsg)
env.Log(Error, "WindowsRegistryKeyValue", errorLogMsg)
return nil, errors.New(errorLogMsg)
}
regRootHKeyHandle := getHKEYHandleFromAbbrString(regPathParts[0])
if regRootHKeyHandle == 0 {
errorLogMsg := fmt.Sprintf("Error, Supplied root HKEY value not valid: '%s'", regPathParts[0])
env.log(Error, "WindowsRegistryKeyValue", errorLogMsg)
env.Log(Error, "WindowsRegistryKeyValue", errorLogMsg)
return nil, errors.New(errorLogMsg)
}
@ -179,7 +179,7 @@ func (env *ShellEnvironment) WindowsRegistryKeyValue(path string) (*WindowsRegis
if lastSlash < 0 {
errorLogMsg := fmt.Sprintf("Error, malformed registry path: '%s'", path)
env.log(Error, "WindowsRegistryKeyValue", errorLogMsg)
env.Log(Error, "WindowsRegistryKeyValue", errorLogMsg)
return nil, errors.New(errorLogMsg)
}
@ -191,13 +191,13 @@ func (env *ShellEnvironment) WindowsRegistryKeyValue(path string) (*WindowsRegis
if len(regKeyLogged) == 0 {
regKeyLogged = "(Default)"
}
env.log(Debug, "WindowsRegistryKeyValue", fmt.Sprintf("WindowsRegistryKeyValue: root:\"%s\", path:\"%s\", key:\"%s\"", regPathParts[0], regPath, regKeyLogged))
env.Log(Debug, "WindowsRegistryKeyValue", fmt.Sprintf("WindowsRegistryKeyValue: root:\"%s\", path:\"%s\", key:\"%s\"", regPathParts[0], regPath, regKeyLogged))
// Second part of split is registry path after HK part - needs to be UTF16 to pass to the windows. API
regPathUTF16, err := windows.UTF16FromString(regPath)
if err != nil {
errorLogMsg := fmt.Sprintf("Error, Could not convert supplied path '%s' to UTF16, error: '%s'", regPath, err)
env.log(Error, "WindowsRegistryKeyValue", errorLogMsg)
env.Log(Error, "WindowsRegistryKeyValue", errorLogMsg)
return nil, errors.New(errorLogMsg)
}
@ -206,14 +206,14 @@ func (env *ShellEnvironment) WindowsRegistryKeyValue(path string) (*WindowsRegis
regOpenErr := windows.RegOpenKeyEx(regRootHKeyHandle, &regPathUTF16[0], 0, windows.KEY_READ, &hKeyHandle)
if regOpenErr != nil {
errorLogMsg := fmt.Sprintf("Error RegOpenKeyEx opening registry path to '%s', error: '%s'", regPath, regOpenErr)
env.log(Error, "WindowsRegistryKeyValue", errorLogMsg)
env.Log(Error, "WindowsRegistryKeyValue", errorLogMsg)
return nil, errors.New(errorLogMsg)
}
// Success - from here on out, when returning make sure to close that reg key with a deferred call to close:
defer func() {
err := windows.RegCloseKey(hKeyHandle)
if err != nil {
env.log(Error, "WindowsRegistryKeyValue", fmt.Sprintf("Error closing registry key: %s", err))
env.Log(Error, "WindowsRegistryKeyValue", fmt.Sprintf("Error closing registry key: %s", err))
}
}()
@ -221,7 +221,7 @@ func (env *ShellEnvironment) WindowsRegistryKeyValue(path string) (*WindowsRegis
regKeyUTF16, err := windows.UTF16FromString(regKey)
if err != nil {
errorLogMsg := fmt.Sprintf("Error, could not convert supplied key '%s' to UTF16, error: '%s'", regKey, err)
env.log(Error, "WindowsRegistryKeyValue", errorLogMsg)
env.Log(Error, "WindowsRegistryKeyValue", errorLogMsg)
return nil, errors.New(errorLogMsg)
}
@ -232,7 +232,7 @@ func (env *ShellEnvironment) WindowsRegistryKeyValue(path string) (*WindowsRegis
regQueryErr := windows.RegQueryValueEx(hKeyHandle, &regKeyUTF16[0], nil, &keyBufType, nil, &keyBufSize)
if regQueryErr != nil {
errorLogMsg := fmt.Sprintf("Error calling RegQueryValueEx to retrieve key data size with error '%s'", regQueryErr)
env.log(Error, "WindowsRegistryKeyValue", errorLogMsg)
env.Log(Error, "WindowsRegistryKeyValue", errorLogMsg)
return nil, errors.New(errorLogMsg)
}
@ -242,7 +242,7 @@ func (env *ShellEnvironment) WindowsRegistryKeyValue(path string) (*WindowsRegis
regQueryErr = windows.RegQueryValueEx(hKeyHandle, &regKeyUTF16[0], nil, &keyBufType, &keyBuf[0], &keyBufSize)
if regQueryErr != nil {
errorLogMsg := fmt.Sprintf("Error calling RegQueryValueEx to retrieve key data with error '%s'", regQueryErr)
env.log(Error, "WindowsRegistryKeyValue", errorLogMsg)
env.Log(Error, "WindowsRegistryKeyValue", errorLogMsg)
return nil, errors.New(errorLogMsg)
}
@ -253,20 +253,20 @@ func (env *ShellEnvironment) WindowsRegistryKeyValue(path string) (*WindowsRegis
uint16p = (*uint16)(unsafe.Pointer(&keyBuf[0])) // nasty casty
valueString := windows.UTF16PtrToString(uint16p)
env.log(Debug, "WindowsRegistryKeyValue", fmt.Sprintf("success, string: %s", valueString))
env.Log(Debug, "WindowsRegistryKeyValue", fmt.Sprintf("success, string: %s", valueString))
return &WindowsRegistryValue{ValueType: RegString, Str: valueString}, nil
case windows.REG_DWORD:
var uint32p *uint32
uint32p = (*uint32)(unsafe.Pointer(&keyBuf[0])) // more casting goodness
env.log(Debug, "WindowsRegistryKeyValue", fmt.Sprintf("success, DWORD, 0x%08X", *uint32p))
env.Log(Debug, "WindowsRegistryKeyValue", fmt.Sprintf("success, DWORD, 0x%08X", *uint32p))
return &WindowsRegistryValue{ValueType: RegDword, Dword: *uint32p}, nil
case windows.REG_QWORD:
var uint64p *uint64
uint64p = (*uint64)(unsafe.Pointer(&keyBuf[0])) // more casting goodness
env.log(Debug, "WindowsRegistryKeyValue", fmt.Sprintf("success, QWORD, 0x%016X", *uint64p))
env.Log(Debug, "WindowsRegistryKeyValue", fmt.Sprintf("success, QWORD, 0x%016X", *uint64p))
return &WindowsRegistryValue{ValueType: RegQword, Qword: *uint64p}, nil
default:
errorLogMsg := fmt.Sprintf("Error, no formatter for REG_? type:%d, data size:%d bytes", keyBufType, keyBufSize)
@ -375,7 +375,7 @@ func (env *ShellEnvironment) parseNetworkInterface(network *WLAN_INTERFACE_INFO,
uintptr(unsafe.Pointer(&wlanAttr)),
uintptr(unsafe.Pointer(nil)))
if e != 0 {
env.log(Error, "parseNetworkInterface", "wlan_intf_opcode_current_connection error")
env.Log(Error, "parseNetworkInterface", "wlan_intf_opcode_current_connection error")
return &info, err
}
@ -432,7 +432,7 @@ func (env *ShellEnvironment) parseNetworkInterface(network *WLAN_INTERFACE_INFO,
uintptr(unsafe.Pointer(&channel)),
uintptr(unsafe.Pointer(nil)))
if e != 0 {
env.log(Error, "parseNetworkInterface", "wlan_intf_opcode_channel_number error")
env.Log(Error, "parseNetworkInterface", "wlan_intf_opcode_channel_number error")
return &info, err
}
info.Channel = int(*channel)

View file

@ -50,7 +50,7 @@ func (env *ShellEnvironment) BatteryState() (*BatteryInfo, error) {
batteries, err := battery.GetAll()
// actual error, return it
if err != nil && len(batteries) == 0 {
env.log(Error, "BatteryInfo", err.Error())
env.Log(Error, "BatteryInfo", err.Error())
return nil, err
}
// there are no batteries found
@ -98,7 +98,7 @@ func (env *ShellEnvironment) BatteryState() (*BatteryInfo, error) {
}
// another error occurred (possibly unmapped use-case), return it
if fatalErr != nil {
env.log(Error, "BatteryInfo", fatalErr.Error())
env.Log(Error, "BatteryInfo", fatalErr.Error())
return nil, fatalErr
}
// everything is fine

View file

@ -234,3 +234,7 @@ func (env *MockedEnvironment) DirMatchesOneOf(dir string, regexes []string) bool
func (env *MockedEnvironment) Trace(start time.Time, function string, args ...string) {
_ = env.Called(start, function, args)
}
func (env *MockedEnvironment) Log(logType environment.LogType, funcName, message string) {
_ = env.Called(logType, funcName, message)
}

View file

@ -9,6 +9,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
mock2 "github.com/stretchr/testify/mock"
)
func renderTemplate(env *mock.MockedEnvironment, segmentTemplate string, context interface{}) string {
@ -24,6 +25,7 @@ func renderTemplate(env *mock.MockedEnvironment, segmentTemplate string, context
Env: make(map[string]string),
})
}
env.On("Log", mock2.Anything, mock2.Anything, mock2.Anything)
tmpl := &template.Text{
Template: segmentTemplate,
Context: context,

View file

@ -6,6 +6,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
mock2 "github.com/stretchr/testify/mock"
)
func TestUrl(t *testing.T) {
@ -23,6 +24,7 @@ func TestUrl(t *testing.T) {
env.On("TemplateCache").Return(&environment.TemplateCache{
Env: make(map[string]string),
})
env.On("Log", mock2.Anything, mock2.Anything, mock2.Anything)
for _, tc := range cases {
tmpl := &Text{
Template: tc.Template,

View file

@ -6,6 +6,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
mock2 "github.com/stretchr/testify/mock"
)
func TestRoundSeconds(t *testing.T) {
@ -30,6 +31,7 @@ func TestRoundSeconds(t *testing.T) {
env.On("TemplateCache").Return(&environment.TemplateCache{
Env: make(map[string]string),
})
env.On("Log", mock2.Anything, mock2.Anything, mock2.Anything)
for _, tc := range cases {
tmpl := &Text{
Template: tc.Template,

View file

@ -43,6 +43,7 @@ func (t *Text) Render() (string, error) {
t.cleanTemplate()
tmpl, err := template.New("title").Funcs(funcMap()).Parse(t.Template)
if err != nil {
t.Env.Log(environment.Error, "Render", err.Error())
return "", errors.New(InvalidTemplate)
}
context := &Context{}
@ -51,6 +52,7 @@ func (t *Text) Render() (string, error) {
defer buffer.Reset()
err = tmpl.Execute(buffer, context)
if err != nil {
t.Env.Log(environment.Error, "Render", err.Error())
return "", errors.New(IncorrectTemplate)
}
text := buffer.String()

View file

@ -6,6 +6,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
mock2 "github.com/stretchr/testify/mock"
)
func TestRenderTemplate(t *testing.T) {
@ -74,6 +75,7 @@ func TestRenderTemplate(t *testing.T) {
env.On("TemplateCache").Return(&environment.TemplateCache{
Env: make(map[string]string),
})
env.On("Log", mock2.Anything, mock2.Anything, mock2.Anything)
for _, tc := range cases {
tmpl := &Text{
Template: tc.Template,
@ -128,6 +130,7 @@ func TestRenderTemplateEnvVar(t *testing.T) {
env.On("TemplateCache").Return(&environment.TemplateCache{
Env: tc.Env,
})
env.On("Log", mock2.Anything, mock2.Anything, mock2.Anything)
tmpl := &Text{
Template: tc.Template,
Context: tc.Context,