Reputation: 1296
I'm writing a simple library to assist with common assertions.
type Test interface {
Fatalf(string, ...interface{})
}
func IsTrue(statement bool, message string, test Test) {
if !statement {
test.Fatalf(message)
}
}
I noticed that the log
package actually has a compatible implementation of Fatalf(string, ...interface{})
and it'd be great if the IsTrue
method could be invoked accordingly:
IsTrue(false, "false wasn't true", log)
But I get the error use of package log not in selector
. Is there any way to use or wrap a package to make this pattern work or is this not possible?
Upvotes: 4
Views: 4042
Reputation: 22196
The best you can hope for is to wrap it in a blank struct like so:
type internalLog struct{}
func (il internalLog) Fatalf(s string, i ...interface{}) {
log.Fatalf(s, i...)
}
In general, since packages are not types in Go, they cannot satisfy anything. You have to wrap them in another type in order to simulate them satisfying an interface.
Edit:
As Caleb mentions (and I forgot about), the package log
in specific has the function New
which returns a *log.Logger which will satisfy the Test
interface in your case (as well as most other package-level log
functions). However, in general if no such type is provided you must wrap the package like I showed above.
Upvotes: 5
Reputation: 9458
I would make a default provider using log
that can be overwritten:
package main
import (
"log"
"os"
)
type TestLogger interface{
Fatalf(string, ...interface{})
}
var DefaultLogger TestLogger
func init() {
DefaultLogger = log.New(os.Stderr, "", log.LstdFlags)
}
func IsTrue(statement bool, message string) {
if !statement {
DefaultLogger.Fatalf(message)
}
}
func main() {
IsTrue(false, "MESSAGE")
}
If someone was using your package they could do something like this:
type MyCustomImplementation struct {}
func (this MyCustomImplementation) Fatalf(msg string, args ... interface{}) {
// do whatever in here
}
some_package.DefaultLogger = MyCustomImplementation{}
Upvotes: 2