20 "github.com/ActiveState/termtest"
21 "github.com/ActiveState/termtest/expect"
22 "github.com/dop251/goja"
25 type far2l_Status
struct {
35 type far2l_FoundString
struct {
41 type far2l_CellRaw
struct {
46 type far2l_Cell
struct {
67 var g_far2l_sock
string
68 var g_far2l_bin
string
69 var g_socket
*net
.UnixConn
70 var g_addr
*net
.UnixAddr
72 var g_app
*termtest
.ConsoleProcess
73 var g_vm
*goja
.Runtime
74 var g_status far2l_Status
75 var g_far2l_running
bool = false
81 var g_recv_timeout
uint32 = 30
82 var g_test_workdir
string
83 var g_calm
bool = false
84 var g_last_error
string
86 func stringFromBytes(buf
[]byte) string {
88 for ; last
< len(buf
) && buf
[last
] != 0; last
++ {
90 return string(buf
[0:last
])
101 func aux_Inspect() string {
107 func setErrorString(err
string) {
109 log
.Print("\x1b[1;31mERROR: " + err
+ "\x1b[39;22m")
115 func assertNoError(err error
) bool {
117 setErrorString(err
.Error())
123 func far2l_ReadSocket(expected_n
int, extra_timeout
uint32) {
124 err
:= g_socket
.SetReadDeadline(time
.Now().Add(time
.Duration(g_recv_timeout
+ extra_timeout
) * time
.Second
))
126 aux_Panic(err
.Error())
128 n
, addr
, err
:= g_socket
.ReadFromUnix(g_buf
[:])
129 if err
!= nil || n
!= expected_n
{
131 if net_err
, ok
:= err
.(net
.Error
); ok
&& net_err
.Timeout() {
132 aux_Panic("First communication timed out, make sure application built with testing support or increase timeout by -t argument")
135 aux_Panic(err
.Error())
137 if g_addr
== nil ||
*g_addr
!= *addr
{
139 log
.Printf("Peer: %v", g_addr
)
145 g_far2l_running
= false
150 func far2l_Start(args
[]string) far2l_Status
{
152 aux_Panic("far2l already running")
154 opts
:= termtest
.Options
{
155 CmdName
: g_far2l_bin
,
156 Args
: append([]string{g_far2l_bin
, "--test=" + g_far2l_sock
}, args
...),
157 Environment
: []string {
158 "FAR2L_STD=" + filepath
.Join(g_test_workdir
, "far2l.log"),
159 "FAR2L_TESTCTL=" + g_far2l_sock
},
160 ExtraOpts
: []expect
.ConsoleOpt
{expect
.WithTermRows(80), expect
.WithTermCols(120)},
163 g_app
, err
= termtest
.New(opts
)
165 aux_Panic(err
.Error())
167 g_far2l_running
= true
168 return far2l_RecvStatus()
171 func far2l_ReqRecvStatus() far2l_Status
{
172 binary
.LittleEndian
.PutUint32(g_buf
[0:], 1)
173 n
, err
:= g_socket
.WriteTo(g_buf
[0:4], g_addr
)
174 if err
!= nil || n
!= 4 {
175 aux_Panic(err
.Error())
177 return far2l_RecvStatus()
180 func far2l_RecvStatus() far2l_Status
{
181 far2l_ReadSocket(2068, 0)
182 g_status
.Title
= stringFromBytes(g_buf
[20:])
183 g_status
.CurH
= g_buf
[2]
184 g_status
.CurV
= g_buf
[3] != 0
185 g_status
.CurX
= binary
.LittleEndian
.Uint32(g_buf
[4:])
186 g_status
.CurY
= binary
.LittleEndian
.Uint32(g_buf
[8:])
187 g_status
.Width
= binary
.LittleEndian
.Uint32(g_buf
[12:])
188 g_status
.Height
= binary
.LittleEndian
.Uint32(g_buf
[16:])
192 func far2l_ReqRecvExpectString(str
string, x
uint32, y
uint32, w
uint32, h
uint32, tmout
uint32) far2l_FoundString
{
193 return far2l_ReqRecvExpectXStrings([]string{str
}, x
, y
, w
, h
, tmout
, true)
196 func far2l_ReqRecvExpectStrings(str_vec
[]string, x
uint32, y
uint32, w
uint32, h
uint32, tmout
uint32) far2l_FoundString
{
197 return far2l_ReqRecvExpectXStrings(str_vec
, x
, y
, w
, h
, tmout
, true)
200 func far2l_ReqRecvExpectNoString(str
string, x
uint32, y
uint32, w
uint32, h
uint32, tmout
uint32) far2l_FoundString
{
201 return far2l_ReqRecvExpectXStrings([]string{str
}, x
, y
, w
, h
, tmout
, false)
204 func far2l_ReqRecvExpectNoStrings(str_vec
[]string, x
uint32, y
uint32, w
uint32, h
uint32, tmout
uint32) far2l_FoundString
{
205 return far2l_ReqRecvExpectXStrings(str_vec
, x
, y
, w
, h
, tmout
, false)
208 func far2l_ReqRecvExpectXStrings(str_vec
[]string, x
uint32, y
uint32, w
uint32, h
uint32, tmout
uint32, need_presence
bool) far2l_FoundString
{
209 if w
== 0xffffffff { w
= g_status
.Width
; }
210 if h
== 0xffffffff { h
= g_status
.Height
; }
212 binary
.LittleEndian
.PutUint32(g_buf
[0:], 3) //TEST_CMD_WAIT_STRING
214 binary
.LittleEndian
.PutUint32(g_buf
[0:], 4) //TEST_CMD_WAIT_NO_STRING
216 binary
.LittleEndian
.PutUint32(g_buf
[4:], tmout
)
217 binary
.LittleEndian
.PutUint32(g_buf
[8:], x
) //left
218 binary
.LittleEndian
.PutUint32(g_buf
[12:], y
) //top
219 binary
.LittleEndian
.PutUint32(g_buf
[16:], w
) //width
220 binary
.LittleEndian
.PutUint32(g_buf
[20:], h
) //height
222 for i
:= 0; i
< len(str_vec
); i
++ {
223 str_bytes
:= []byte(str_vec
[i
])
224 for j
:= 0; j
< len(str_bytes
); j
++ {
225 g_buf
[24 + p
] = str_bytes
[j
]
232 aux_Panic("Too long strings")
234 for ; p
< 2048; p
++ {
238 n
, err
:= g_socket
.WriteTo(g_buf
[0:24 + 2048], g_addr
)
239 if err
!= nil || n
!= 24 + 2048 {
240 aux_Panic(err
.Error())
242 far2l_ReadSocket(12, tmout
/ 1000)
243 out
:= far2l_FoundString
{
244 I
: binary
.LittleEndian
.Uint32(g_buf
[0:]),
245 X
: binary
.LittleEndian
.Uint32(g_buf
[4:]),
246 Y
: binary
.LittleEndian
.Uint32(g_buf
[8:]),
249 if out
.I
< uint32(len(str_vec
)) {
250 status
= fmt
.Sprintf("String at [%d : %d] - %v", out
.X
, out
.Y
, str_vec
[out
.I
])
252 status
= fmt
.Sprintf("Nothing at [%d +%d : %d +%d] of %v", x
, w
, y
, h
, str_vec
)
255 if out
.I
< uint32(len(str_vec
)) {
258 setErrorString(status
)
260 } else if out
.I
< uint32(len(str_vec
)) {
261 setErrorString(status
)
268 func far2l_ReqRecvReadCellRaw(x
uint32, y
uint32) far2l_CellRaw
{
269 binary
.LittleEndian
.PutUint32(g_buf
[0:], 2) // TEST_CMD_READ_CELL
270 binary
.LittleEndian
.PutUint32(g_buf
[4:], x
) // left
271 binary
.LittleEndian
.PutUint32(g_buf
[8:], y
) // top
272 n
, err
:= g_socket
.WriteTo(g_buf
[0:12], g_addr
)
273 if err
!= nil || n
!= 12 {
274 aux_Panic(err
.Error())
276 far2l_ReadSocket(2056, 0)
277 return far2l_CellRaw
{
278 Text
: stringFromBytes(g_buf
[8:]),
279 Attributes
: binary
.LittleEndian
.Uint64(g_buf
[0:]),
283 func far2l_ReqRecvReadCell(x
uint32, y
uint32) far2l_Cell
{
284 raw_cell
:= far2l_ReqRecvReadCellRaw(x
, y
)
287 BackTC
: uint32((raw_cell
.Attributes
>> 40) & 0xFFFFFF),
288 ForeTC
: uint32((raw_cell
.Attributes
>> 16) & 0xFFFFFF),
289 Back
: uint8(((raw_cell
.Attributes
>> 4) & 0xF)),
290 Fore
: uint8((raw_cell
.Attributes
& 0xF)),
291 IsBackTC
: (raw_cell
.Attributes
& 0x0200) != 0,
292 IsForeTC
: (raw_cell
.Attributes
& 0x0100) != 0,
293 ForeBlue
: (raw_cell
.Attributes
& 0x0001) != 0,
294 ForeGreen
: (raw_cell
.Attributes
& 0x0002) != 0,
295 ForeRed
: (raw_cell
.Attributes
& 0x0004) != 0,
296 ForeIntense
: (raw_cell
.Attributes
& 0x0008) != 0,
297 BackBlue
: (raw_cell
.Attributes
& 0x0010) != 0,
298 BackGreen
: (raw_cell
.Attributes
& 0x0020) != 0,
299 BackRed
: (raw_cell
.Attributes
& 0x0040) != 0,
300 BackIntense
: (raw_cell
.Attributes
& 0x0080) != 0,
301 ReverseVideo
: (raw_cell
.Attributes
& 0x4000) != 0,
302 Underscore
: (raw_cell
.Attributes
& 0x8000) != 0,
303 Strikeout
: (raw_cell
.Attributes
& 0x2000) != 0,
307 func far2l_CheckBoundedLine(expected
string, left
uint32, top
uint32, width
uint32, trim_chars
string) string {
308 line
:= far2l_BoundedLine(left
, top
, width
, trim_chars
)
309 if line
!= expected
{
310 setErrorString(fmt
.Sprintf("Line at [%d +%d : %d] not expected: '%v'", left
, width
, top
, line
))
315 func far2l_BoundedLine(left
uint32, top
uint32, width
uint32, trim_chars
string) string {
316 lines
:= far2l_BoundedLines(left
, top
, width
, 1, trim_chars
)
320 func far2l_BoundedLines(left
uint32, top
uint32, width
uint32, height
uint32, trim_chars
string) []string {
322 for y
:= top
; y
< top
+ height
; y
++ {
324 for x
:= left
; x
< left
+ width
; x
++ {
325 cell
:= far2l_ReqRecvReadCellRaw(x
, y
)
328 if trim_chars
!= "" {
329 lines
= append(lines
, strings
.Trim(line
, trim_chars
))
331 lines
= append(lines
, line
)
337 func far2l_SurroundedLines(x
uint32, y
uint32, boundary_chars
string, trim_chars
string) []string {
338 var left
, top
, width
, height
uint32
339 far2l_ReqRecvStatus()
341 for left
= x
; left
> 0 && !far2l_CellCharMatches(left
- 1, y
, boundary_chars
); left
-- {
344 for width
= 1; left
+ width
< g_status
.Width
&& !far2l_CellCharMatches(left
+ width
, y
, boundary_chars
); width
++ {
347 // top & bottom edges has some quirks due to they may contains caption, hints, time etc..
348 for top
= y
; top
> 0 &&
349 !far2l_CellCharMatches(left
, top
- 1, boundary_chars
) &&
350 !far2l_CellCharMatches(left
+ width
/ 2, top
- 1, boundary_chars
) &&
351 !far2l_CellCharMatches(left
+ width
- 1, top
- 1, boundary_chars
); top
-- {
354 for height
= 1; top
+ height
< g_status
.Height
&&
355 !far2l_CellCharMatches(left
, top
+ height
, boundary_chars
) &&
356 !far2l_CellCharMatches(left
+ width
/ 2, top
+ height
, boundary_chars
) &&
357 !far2l_CellCharMatches(left
+ width
- 1, top
+ height
, boundary_chars
); height
++ {
360 return far2l_BoundedLines(left
, top
, width
, height
, trim_chars
)
363 func far2l_CellCharMatches(x
uint32, y
uint32, chars
string) bool {
364 cell
:= far2l_ReqRecvReadCellRaw(x
, y
)
365 return cell
.Text
!= "" && strings
.Contains(chars
, cell
.Text
)
368 func far2l_CheckCellChar(x
uint32, y
uint32, chars
string) string {
369 cell
:= far2l_ReqRecvReadCellRaw(x
, y
)
370 if cell
.Text
== "" ||
!strings
.Contains(chars
, cell
.Text
) {
371 setErrorString(fmt
.Sprintf("Cell at %d:%d = '%s' doesnt represent any of: '%s'", x
, y
, cell
.Text
, chars
))
376 func far2l_ReqBye() {
377 binary
.LittleEndian
.PutUint32(g_buf
[0:], 0)
378 n
, err
:= g_socket
.WriteTo(g_buf
[0:4], g_addr
)
379 if err
!= nil || n
!= 4 {
380 aux_Panic(err
.Error())
384 func far2l_ExpectExit(code
int, timeout_ms
int) string {
386 _
, err
:= g_app
.ExpectExitCode(code
, time
.Duration(timeout_ms
) * 1000000)
388 setErrorString(fmt
.Sprintf("ExpectExit: %v", err
))
389 return "ERROR:" + err
.Error()
395 func aux_Log(message
string) {
399 func aux_Panic(message
string) {
400 panic("\x1b[1;31m" + message
+ "\x1b[39;22m")
403 func tty_Write(s
string) {
411 func far2l_ToggleShift(pressed
bool) {
413 far2l_SendKeyEvent(0, 0x10, pressed
)
416 func far2l_ToggleLCtrl(pressed
bool) {
418 far2l_SendKeyEvent(0, 0x11, pressed
)
421 func far2l_ToggleRCtrl(pressed
bool) {
423 far2l_SendKeyEvent(0, 0x11, pressed
)
426 func far2l_ToggleLAlt(pressed
bool) {
428 far2l_SendKeyEvent(0, 0x12, pressed
)
431 func far2l_ToggleRAlt(pressed
bool) {
433 far2l_SendKeyEvent(0, 0x12, pressed
)
436 func far2l_TypeFKey(n
uint32) { far2l_TypeVK(0x6F + n
) }
437 func far2l_TypeDigit(n
uint32) { far2l_TypeVK(0x60 + n
) }
439 func far2l_TypeAdd() { far2l_TypeVK(0x6B) }
440 func far2l_TypeSub() { far2l_TypeVK(0x6D) }
441 func far2l_TypeMul() { far2l_TypeVK(0x6A) }
442 func far2l_TypeDiv() { far2l_TypeVK(0x6F) }
443 func far2l_TypeSeparator(){ far2l_TypeVK(0x6C) }
444 func far2l_TypeDecimal() { far2l_TypeVK(0x6E) }
446 func far2l_TypeBack() { far2l_TypeVK(0x08) }
447 func far2l_TypeEnter() { far2l_TypeVK(0x0D) }
448 func far2l_TypeEscape() { far2l_TypeVK(0x1B) }
449 func far2l_TypePageUp() { far2l_TypeVK(0x21) }
450 func far2l_TypePageDown() { far2l_TypeVK(0x22) }
451 func far2l_TypeEnd() { far2l_TypeVK(0x23) }
452 func far2l_TypeHome() { far2l_TypeVK(0x24) }
453 func far2l_TypeLeft() { far2l_TypeVK(0x25) }
454 func far2l_TypeUp() { far2l_TypeVK(0x26) }
455 func far2l_TypeRight() { far2l_TypeVK(0x27) }
456 func far2l_TypeDown() { far2l_TypeVK(0x28) }
457 func far2l_TypeIns() { far2l_TypeVK(0x2D) }
458 func far2l_TypeDel() { far2l_TypeVK(0x2E) }
461 func far2l_TypeVK(key_code
uint32) {
462 far2l_SendKeyEvent(0, key_code
, true)
463 far2l_SendKeyEvent(0, key_code
, false)
467 func far2l_TypeText(text
string) {
468 for _
, r
:= range text
{
469 far2l_SendKeyEvent(uint32(r
), 0, true)
470 far2l_SendKeyEvent(uint32(r
), 0, false)
474 func far2l_SendKeyEvent(utf32_code
uint32, key_code
uint32, pressed
bool) {
475 if key_code
== 0 && utf32_code
!= 0 {
476 if utf32_code
>= 'a' && utf32_code
<= 'z' {
477 key_code
= 'A' + (utf32_code
- 'a')
478 } else if (utf32_code
<= 0x7f) {
479 key_code
= utf32_code
482 var controls
uint32 = 0
483 if g_lctrl
{ controls |
= 0x0008 } // LEFT_CTRL_PRESSED
484 if g_rctrl
{ controls |
= 0x0004 } // RIGHT_CTRL_PRESSED
485 if g_lalt
{ controls |
= 0x0002 } // LEFT_ALT_PRESSED
486 if g_ralt
{ controls |
= 0x0001 } // RIGHT_ALT_PRESSED
487 if g_shift
{ controls |
= 0x0010 } // SHFIT_PRESSED
488 binary
.LittleEndian
.PutUint32(g_buf
[0:], 5) // TEST_CMD_SEND_KEY
489 binary
.LittleEndian
.PutUint32(g_buf
[4:], controls
)
490 binary
.LittleEndian
.PutUint32(g_buf
[8:], utf32_code
)
491 binary
.LittleEndian
.PutUint32(g_buf
[12:], key_code
)
492 binary
.LittleEndian
.PutUint32(g_buf
[16:], 0)
493 binary
.LittleEndian
.PutUint32(g_buf
[20:], 0)
494 if pressed
{ g_buf
[20] = 1 }
495 n
, err
:= g_socket
.WriteTo(g_buf
[0:24], g_addr
)
496 if err
!= nil || n
!= 24 {
497 aux_Panic(err
.Error())
501 func aux_RunCmd(args
[]string) string {
502 prog
, err
:= exec
.LookPath(args
[0])
506 cmd
:= exec
.Command(prog
, args
...)
509 setErrorString("RunCmd: " + err
.Error())
514 func aux_Sleep(msec
uint32) {
515 time
.Sleep(time
.Duration(msec
) * time
.Millisecond
)
518 func aux_WorkDir() string {
519 return g_test_workdir
522 func aux_Chmod(name
string, mode os
.FileMode
) bool {
523 return assertNoError(os
.Chmod(name
, mode
))
526 func aux_Chown(name
string, uid
, gid
int) bool {
527 return assertNoError(os
.Chown(name
, uid
, gid
))
530 func aux_Chtimes(name
string, atime time
.Time
, mtime time
.Time
) bool {
531 return assertNoError(os
.Chtimes(name
, atime
, mtime
))
534 func aux_Mkdir(name
string, perm os
.FileMode
) bool {
535 return assertNoError(os
.Mkdir(name
, perm
))
538 func aux_MkdirTemp(dir
, pattern
string) string {
539 out
, err
:= os
.MkdirTemp(dir
, pattern
)
540 if !assertNoError(err
) {
546 func aux_Remove(name
string) bool {
547 return assertNoError(os
.Remove(name
))
550 func aux_RemoveAll(name
string) bool {
551 return assertNoError(os
.RemoveAll(name
))
554 func aux_Rename(oldpath
, newpath
string) bool {
555 return assertNoError(os
.Rename(oldpath
, newpath
))
558 func aux_ReadFile(name
string) []byte {
559 out
, err
:= os
.ReadFile(name
)
560 if !assertNoError(err
) {
566 func aux_WriteFile(name
string, data
[]byte, perm os
.FileMode
) bool {
567 return assertNoError(os
.WriteFile(name
, data
, perm
))
570 func aux_Truncate(name
string, size
int64) bool {
571 return assertNoError(os
.Truncate(name
, size
))
574 func aux_ReadDir(name
string) []os
.DirEntry
{
575 out
, err
:= os
.ReadDir(name
)
576 if !assertNoError(err
) {
577 return []os
.DirEntry
{}
582 func aux_Symlink(oldname
, newname
string) bool {
583 return assertNoError(os
.Symlink(oldname
, newname
))
586 func aux_Readlink(name
string) string {
587 out
, err
:= os
.Readlink(name
)
588 if !assertNoError(err
) {
594 func aux_MkdirAll(path
string, perm os
.FileMode
) bool {
595 return assertNoError(os
.MkdirAll(path
, perm
))
598 func aux_MkdirsAll(pathes
[]string, perm os
.FileMode
) bool {
600 for _
, path
:= range pathes
{
601 if !aux_MkdirAll(path
, perm
) {
608 type LimitedRandomReader
struct {
612 func (r
*LimitedRandomReader
) Read(p
[]byte) (n
int, err error
) {
620 if uint64(piece
) > r
.remain
{
621 piece
= int(r
.remain
)
623 piece
, err
= rand
.Read(p
[0 : piece
])
625 if uint64(piece
) < r
.remain
{
626 r
.remain
-= uint64(piece
)
634 func aux_Mkfile(path
string, mode os
.FileMode
, min_size
uint64, max_size
uint64) bool {
635 f
, err
:= os
.OpenFile(path
, os
.O_WRONLY | os
.O_CREATE | os
.O_TRUNC
, mode
)
637 setErrorString(fmt
.Sprintf("Error %v creating %v", err
, path
))
642 lrr
:= LimitedRandomReader
{
645 if max_size
> min_size
{
646 lrr
.remain
+= rand
.Uint64() % (max_size
- min_size
)
649 _
, err
= io
.Copy(f
, &lrr
)
651 setErrorString(fmt
.Sprintf("Error %v writing %v", err
, path
))
658 func aux_Mkfiles(pathes
[]string, mode os
.FileMode
, min_size
uint64, max_size
uint64) bool {
660 for _
, path
:= range pathes
{
661 if !aux_Mkfile(path
, mode
, min_size
, max_size
) {
668 var g_hash_data
, g_hash_name
, g_hash_mode
, g_hash_link
, g_hash_times
bool
669 var g_hash_hide_path
string
672 func EnhashString(s
string) {
673 g_hash
.Write([]byte(s
))
676 func EnhashFileData(path
string) {
677 f
, err
:= os
.Open(path
)
679 EnhashString("ERR:" + err
.Error())
680 log
.Printf("EnhashFileData:" + err
.Error())
684 if _
, err
:= io
.Copy(g_hash
, f
); err
!= nil {
685 EnhashString("ERR:" + err
.Error())
686 log
.Printf("EnhashFileData:" + err
.Error())
690 func EnhashFSObject(path
string) bool {
694 fi
, err
= os
.Lstat(path
)
696 fi
, err
= os
.Stat(path
)
698 if g_hash_name
&& path
!= g_hash_hide_path
{
702 log
.Printf("Stat error %s while enhashing %s", err
.Error(), path
)
706 EnhashString(fi
.Mode().String())
709 // one second precision to avoid rounding errors
710 EnhashString( fi
.ModTime().Format(time
.Stamp
))
713 if (fi
.Mode() & fs
.ModeSymlink
) != 0 {
714 if dst
, err
:= os
.Readlink(path
); err
== nil {
717 EnhashString(err
.Error())
721 if fi
.Mode().IsRegular() {
729 func walkHash(path
string, de fs
.DirEntry
, err error
) error
{
733 func aux_HashPath(path
string, hash_data
bool, hash_name
bool, hash_link
bool, hash_mode
bool, hash_times
bool) string {
734 return aux_HashPathes([]string{path
}, hash_data
, hash_name
, hash_link
, hash_mode
, hash_times
)
737 func aux_HashPathes(pathes
[]string, hash_data
bool, hash_name
bool, hash_link
bool, hash_mode
bool, hash_times
bool) string {
738 g_hash_data
= hash_data
739 g_hash_name
= hash_name
740 g_hash_link
= hash_link
741 g_hash_mode
= hash_mode
742 g_hash_times
= hash_times
743 g_hash
= sha256
.New()
744 for _
, path
:= range pathes
{
745 g_hash_hide_path
= path
746 if EnhashFSObject(path
) {
747 filepath
.WalkDir(path
, walkHash
)
750 return fmt
.Sprintf("%x", g_hash
.Sum(nil))
753 func aux_Exists(path
string) bool {
754 _
, err
:= os
.Lstat(path
)
758 func aux_CountExisting(pathes
[]string) int {
760 for _
, path
:= range pathes
{
761 if aux_Exists(path
) {
771 fmt
.Println("Initializing JS VM...")
774 /* goja does not expose a standard "global" by default */
775 _
, err
:= g_vm
.RunString("var global = (function(){ return this; }).call(null);")
776 if err
!= nil { aux_Panic(err
.Error()) }
778 setVMFunction("BePanic", aux_BePanic
)
779 setVMFunction("BeCalm", aux_BeCalm
)
780 setVMFunction("Inspect", aux_Inspect
)
782 setVMFunction("StartApp", far2l_Start
)
783 setVMFunction("AppStatus", far2l_ReqRecvStatus
)
784 setVMFunction("ReadCellRaw", far2l_ReqRecvReadCellRaw
)
785 setVMFunction("ReadCell", far2l_ReqRecvReadCell
)
786 setVMFunction("CellCharMatches", far2l_CellCharMatches
)
787 setVMFunction("CheckCellChar", far2l_CheckCellChar
)
789 setVMFunction("BoundedLines", far2l_BoundedLines
)
790 setVMFunction("BoundedLine", far2l_BoundedLine
)
791 setVMFunction("CheckBoundedLine", far2l_CheckBoundedLine
)
792 setVMFunction("SurroundedLines", far2l_SurroundedLines
)
794 setVMFunction("ExpectStrings", far2l_ReqRecvExpectStrings
)
795 setVMFunction("ExpectString", far2l_ReqRecvExpectString
)
796 setVMFunction("ExpectNoStrings", far2l_ReqRecvExpectNoStrings
)
797 setVMFunction("ExpectNoString", far2l_ReqRecvExpectNoString
)
799 setVMFunction("ExpectAppExit", far2l_ExpectExit
)
801 setVMFunction("ToggleShift", far2l_ToggleShift
)
802 setVMFunction("ToggleLCtrl", far2l_ToggleLCtrl
)
803 setVMFunction("ToggleRCtrl", far2l_ToggleRCtrl
)
804 setVMFunction("ToggleLAlt", far2l_ToggleLAlt
)
805 setVMFunction("ToggleRAlt", far2l_ToggleRAlt
)
806 setVMFunction("TypeText", far2l_TypeText
)
807 setVMFunction("TypeVK", far2l_TypeVK
)
808 setVMFunction("TypeFKey", far2l_TypeFKey
)
809 setVMFunction("TypeDigit", far2l_TypeDigit
)
810 setVMFunction("TypeAdd", far2l_TypeAdd
)
811 setVMFunction("TypeSub", far2l_TypeSub
)
812 setVMFunction("TypeMul", far2l_TypeMul
)
813 setVMFunction("TypeDiv", far2l_TypeDiv
)
814 setVMFunction("TypeSeparator", far2l_TypeSeparator
)
815 setVMFunction("TypeDecimal", far2l_TypeDecimal
)
817 setVMFunction("TypeEnter", far2l_TypeEnter
)
818 setVMFunction("TypeEscape", far2l_TypeEscape
)
819 setVMFunction("TypePageUp", far2l_TypePageUp
)
820 setVMFunction("TypePageDown", far2l_TypePageDown
)
821 setVMFunction("TypeEnd", far2l_TypeEnd
)
822 setVMFunction("TypeHome", far2l_TypeHome
)
823 setVMFunction("TypeLeft", far2l_TypeLeft
)
824 setVMFunction("TypeUp", far2l_TypeUp
)
825 setVMFunction("TypeRight", far2l_TypeRight
)
826 setVMFunction("TypeDown", far2l_TypeDown
)
827 setVMFunction("TypeIns", far2l_TypeIns
)
828 setVMFunction("TypeDel", far2l_TypeDel
)
829 setVMFunction("TypeBack", far2l_TypeBack
)
831 setVMFunction("TTYWrite", tty_Write
)
832 setVMFunction("TTYCtrlC", tty_CtrlC
)
834 setVMFunction("Log", aux_Log
)
835 setVMFunction("Panic", aux_Panic
)
837 setVMFunction("RunCmd", aux_RunCmd
)
838 setVMFunction("Sleep", aux_Sleep
)
840 setVMFunction("WorkDir", aux_WorkDir
)
841 setVMFunction("Chmod", aux_Chmod
)
842 setVMFunction("Chown", aux_Chown
)
843 setVMFunction("Chtimes", aux_Chtimes
)
844 setVMFunction("Mkdir", aux_Mkdir
)
845 setVMFunction("MkdirTemp", aux_MkdirTemp
)
846 setVMFunction("Remove", aux_Remove
)
847 setVMFunction("RemoveAll", aux_RemoveAll
)
848 setVMFunction("Rename", aux_Rename
)
849 setVMFunction("ReadFile", aux_ReadFile
)
850 setVMFunction("WriteFile", aux_WriteFile
)
851 setVMFunction("Truncate", aux_Truncate
)
852 setVMFunction("ReadDir", aux_ReadDir
)
853 setVMFunction("Symlink", aux_Symlink
)
854 setVMFunction("Readlink", aux_Readlink
)
855 setVMFunction("MkdirAll", aux_MkdirAll
)
856 setVMFunction("MkdirsAll", aux_MkdirsAll
)
857 setVMFunction("Mkfile", aux_Mkfile
)
858 setVMFunction("Mkfiles", aux_Mkfiles
)
859 setVMFunction("HashPath", aux_HashPath
)
860 setVMFunction("HashPathes", aux_HashPathes
)
861 setVMFunction("Exists", aux_Exists
)
862 setVMFunction("CountExisting", aux_CountExisting
)
865 func setVMFunction(name
string, value
interface{}) {
866 err
:= g_vm
.Set(name
, value
)
868 aux_Panic(fmt
.Sprintf("VMSet(%s): %v", name
, err
))
875 for ;arg_ofs
< len(os
.Args
); arg_ofs
++ {
876 if os
.Args
[arg_ofs
] == "-t" && arg_ofs
+ 1 < len(os
.Args
) {
878 v
, err
:= strconv
.Atoi(os
.Args
[arg_ofs
])
879 if err
!= nil || v
< 0 { aux_Panic("timeout must be positive integer value") }
880 g_recv_timeout
= uint32(v
)
886 if len(os
.Args
) < arg_ofs
+ 3 {
887 log
.Fatal("Usage: far2l-smoke [-t TIMEOUT_SEC] /path/to/far2l /path/to/work/dir /path/to/test1.js [/path/to/test2.js [/path/to/test3.js ...]]\n")
890 workdir
, err
:= filepath
.Abs(os
.Args
[arg_ofs
+ 1])
891 if err
!= nil { log
.Fatal(err
) }
893 g_far2l_sock
= filepath
.Join(workdir
, "far2l.sock")
894 os
.Remove(g_far2l_sock
)
895 defer os
.Remove(g_far2l_sock
)
897 g_socket
, err
= net
.ListenUnixgram("unixgram", &net
.UnixAddr
{Name
:g_far2l_sock
, Net
:"unixgram"})
904 g_far2l_bin
, err
= filepath
.Abs(os
.Args
[arg_ofs
])
909 for i
:= arg_ofs
+ 2; i
< len(os
.Args
); i
++ {
910 fmt
.Println("\x1b[1;32m---> Running test: " + os
.Args
[i
] + "\x1b[39;22m")
911 name
:= filepath
.Base(os
.Args
[i
])
912 g_test_workdir
= filepath
.Join(workdir
, strings
.TrimSuffix(name
, filepath
.Ext(name
)))
917 func saveSnapshotOnExit() {
919 f
, err
:= os
.Create(g_test_workdir
+ "/snapshot.txt")
921 f
.WriteString(g_app
.Snapshot())
926 func runTest(file
string) {
928 defer saveSnapshotOnExit()
937 data
, err
:= ioutil
.ReadFile(file
)
938 if err
!= nil { aux_Panic(err
.Error()) }
940 rv
, err
:= g_vm
.RunString(src
)
941 if err
!= nil { aux_Panic(err
.Error()) }
942 if code
:= rv
.Export().(int64); code
!= 0 {
943 fmt
.Println("[FAILED] Error", code
, "from test", file
)