aminal/main_test.go

238 lines
5.0 KiB
Go

// +build linux
package main
import (
"flag"
"fmt"
"github.com/carlogit/phash"
"github.com/liamg/aminal/config"
"github.com/liamg/aminal/gui"
"github.com/liamg/aminal/terminal"
"os"
"runtime"
"strings"
"testing"
"time"
)
var termRef *terminal.Terminal
var guiRef *gui.GUI
func terminate(msg string) int {
defer fmt.Print(msg)
return 1
}
func sleep(seconds ...int) {
count := 1
if len(seconds) > 0 {
count = seconds[0]
}
time.Sleep(time.Duration(count) * time.Second)
}
func hash(path string) string {
image, err := os.Open(path)
if err != nil {
panic(err)
}
defer image.Close()
imageHash, err := phash.GetHash(image)
if err != nil {
panic(err)
}
return imageHash
}
func imagesAreEqual(expected string, actual string) int {
expectedHash := hash(expected)
actualHash := hash(actual)
return phash.GetDistance(expectedHash, actualHash)
}
func compareImages(expected string, actual string) {
distance := imagesAreEqual(expected, actual)
if distance != 0 {
os.Exit(terminate(fmt.Sprintf("Screenshot \"%s\" doesn't match expected image \"%s\". Distance of hashes difference: %d\n",
actual, expected, distance)))
}
}
func send(terminal *terminal.Terminal, cmd string) {
err := terminal.Write([]byte(cmd))
if err != nil {
panic(err)
}
}
func enter(terminal *terminal.Terminal) {
err := terminal.Write([]byte("\n"))
if err != nil {
panic(err)
}
}
func validateScreen(img string, waitForChange bool) {
fmt.Printf("taking screenshot: %s and comparing...", img)
guiRef.Screenshot(img)
compareImages(strings.Join([]string{"vttest/", img}, ""), img)
fmt.Printf("compare OK\n")
enter(termRef)
if waitForChange {
fmt.Print("Waiting for screen change...")
attempts := 10
for {
sleep()
actualScren := "temp.png"
guiRef.Screenshot(actualScren)
distance := imagesAreEqual(actualScren, img)
if distance != 0 {
break
}
fmt.Printf(" %d", attempts)
attempts--
if attempts <= 0 {
break
}
}
fmt.Print("done\n")
}
}
func TestMain(m *testing.M) {
flag.Parse()
go m.Run()
for f := range tests {
f()
}
}
var tests = make(chan func())
func runMain(f func()) {
complete := make(chan bool, 1)
tests <- func() {
f()
complete <- true
}
<-complete
}
func TestCursorMovement(t *testing.T) {
runMain(func() {
testFunc := func(term *terminal.Terminal, g *gui.GUI) {
termRef = term
guiRef = g
sleep()
send(term, "vttest\n")
sleep()
send(term, "1\n")
sleep()
term.Lock()
compareResult := term.ActiveBuffer().CompareViewLines("vttest/test-cursor-movement-1")
term.Unlock()
if compareResult == false {
os.Exit(terminate(fmt.Sprintf("ActiveBuffer doesn't match vttest template vttest/test-cursor-movement-1")))
}
validateScreen("test-cursor-movement-1.png", true)
validateScreen("test-cursor-movement-2.png", true)
validateScreen("test-cursor-movement-3.png", true)
validateScreen("test-cursor-movement-4.png", true)
validateScreen("test-cursor-movement-5.png", true)
validateScreen("test-cursor-movement-6.png", false)
g.Close()
}
initialize(testFunc, testConfig())
})
}
func TestScreenFeatures(t *testing.T) {
runMain(func() {
testFunc := func(term *terminal.Terminal, g *gui.GUI) {
termRef = term
guiRef = g
sleep()
send(term, "vttest\n")
sleep()
send(term, "2\n")
sleep()
validateScreen("test-screen-features-1.png", true)
validateScreen("test-screen-features-2.png", true)
validateScreen("test-screen-features-3.png", true)
validateScreen("test-screen-features-4.png", true)
validateScreen("test-screen-features-5.png", true)
validateScreen("test-screen-features-6.png", true)
validateScreen("test-screen-features-7.png", true)
validateScreen("test-screen-features-8.png", true)
validateScreen("test-screen-features-9.png", true)
validateScreen("test-screen-features-10.png", true)
validateScreen("test-screen-features-11.png", true)
validateScreen("test-screen-features-12.png", true)
validateScreen("test-screen-features-13.png", true)
validateScreen("test-screen-features-14.png", true)
validateScreen("test-screen-features-15.png", false)
g.Close()
}
initialize(testFunc, testConfig())
})
}
func TestSixel(t *testing.T) {
runMain(func() {
testFunc := func(term *terminal.Terminal, g *gui.GUI) {
termRef = term
guiRef = g
sleep()
send(term, "export PS1='> '\n")
sleep()
send(term, "clear\n")
sleep()
send(term, "cat example.sixel\n")
sleep(10) // Displaying SIXEL graphics *sometimes* takes long time. Excessive synchronization???
validateScreen("test-sixel.png", false)
g.Close()
}
initialize(testFunc, testConfig())
})
}
// Last Test should terminate main goroutine since it's infinity looped to execute others GUI tests in main goroutine
func TestExit(t *testing.T) {
os.Exit(0)
}
func testConfig() *config.Config {
c := config.DefaultConfig()
// Use a vanilla shell on POSIX to help ensure consistency.
if runtime.GOOS != "windows" {
c.Shell = "/bin/sh"
}
return c
}