Remove gdscript version and replace with native

Former-commit-id: f9474fe533
This commit is contained in:
Leroy Hopson 2020-09-17 15:14:04 +07:00
parent f8412a03f5
commit a022104230
126 changed files with 116 additions and 14221 deletions

View file

@ -1,102 +0,0 @@
# Copyright (c) 2020 The GodotXterm authors. All rights reserved.
# License MIT
extends "res://addons/gut/test.gd"
const Parser = preload("res://addons/godot_xterm/parser/escape_sequence_parser.gd")
const Terminal = preload("res://addons/godot_xterm/terminal.gd")
const Decoder = preload("res://addons/godot_xterm/input/text_decoder.gd")
const Constants = preload("res://addons/godot_xterm/parser/constants.gd")
const C0 = Constants.C0
const C1 = Constants.C1
class TestBuffer:
var calls = []
var printed = ''
func handle_print(data, start, end):
var string = Decoder.utf32_to_string(data.slice(start, end - 1))
calls.append(['print', string])
printed += string
func handle_exec():
calls.append(['exec'])
func handle_csi(params):
calls.append(['csi', params.to_array()])
func clear():
printed = ''
calls.resize(0)
var parser
var buffer
var decoder
func parse(parser, string):
var container = []
container.resize(string.length())
var length = decoder.decode(string.to_utf8(), container)
parser.parse(container, length)
func before_all():
buffer = TestBuffer.new()
decoder = Decoder.Utf8ToUtf32.new()
func before_each():
parser = Parser.new()
parser.set_print_handler(buffer, 'handle_print')
buffer.clear()
func test_prints_printables():
var string = 'bash-4.4# '
var data = string.to_utf8()
var length = decoder.decode(data, data)
parser.parse(data, length)
assert_eq(buffer.calls, [['print', 'bash-4.4# ']])
assert_eq(buffer.printed, 'bash-4.4# ')
func skip_test_c0():
for code in C0.values():
parser.set_execute_handler(code, buffer, 'handle_exec')
parse(parser, char(code))
if code == 0x0 or code == 0x1b or code == 0x20 or code == 0x7f:
assert_eq(buffer.calls, [])
else:
assert_eq(buffer.calls, [['exec']], 'code: 0x%x' % code)
assert_eq(buffer.printed, '')
parser.reset()
buffer.clear()
func skip_test_c1():
for code in C1.values():
parser.set_execute_handler(code, buffer, 'handle_exec')
parse(parser, char(code))
assert_eq(buffer.calls, [['exec']], 'code: 0x%x' % code)
assert_eq(buffer.printed, '')
parser.reset()
buffer.clear()
func test_print_csi_print():
parser.set_csi_handler({'final': 'g'}, buffer, 'handle_csi')
parse(parser, 'a\u001b[gb')
assert_eq(buffer.calls, [['print', 'a'],['csi', [0]], ['print', 'b']])
assert_eq(buffer.printed, 'ab')
func test_csi_position_cursor():
parser.set_csi_handler({'final': 'H'}, buffer, 'handle_csi')
parse(parser, '\u001b[1;5H')
assert_eq(buffer.calls, [['csi', [1, 5]]])
assert_eq(buffer.printed, '')

View file

@ -1,17 +0,0 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://addons/gut/gut.gd" type="Script" id=1]
[node name="Gut" type="Control"]
self_modulate = Color( 1, 1, 1, 0 )
margin_right = 1031.0
margin_bottom = 597.0
rect_min_size = Vector2( 740, 250 )
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
_yield_between_tests = false
_include_subdirectories = true
_directory1 = "res://test"
_double_strategy = 1

View file

@ -1,66 +0,0 @@
# Copyright (c) 2019 The xterm.js authors. All rights reserved.
# Ported to GDScript by the GodotXterm authors.
# License MIT
extends "res://addons/gut/test.gd"
const Buffer = preload("res://addons/godot_xterm/buffer/buffer.gd")
const BufferSet = preload("res://addons/godot_xterm/buffer/buffer_set.gd")
const OptionsService = preload("res://addons/godot_xterm/services/options_service.gd")
class MockBufferService:
extends Reference
signal resized(cols, rows)
var service_brand
var buffer setget ,_get_buffer
var buffers
var is_user_scrolling: bool = false
var cols
var rows
func _get_buffer():
return buffers.active
func _init(cols: int, rows: int, options_service = MockOptionsService.new()):
self.cols = cols
self.rows = rows
buffers = BufferSet.new(options_service, self)
func resize(cols: int, rows: int) -> void:
self.cols = cols
self.rows = rows
func reset() -> void:
pass
class MockOptionsService:
extends Reference
signal option_changed
var service_brand
var options = OptionsService.TerminalOptions.new()
func _init(test_options = null):
if test_options:
for key in test_options.keys():
self.options.set(key, test_options[key])
func set_option(key: String, value) -> void:
pass
func get_option(key: String):
pass

Binary file not shown.

View file

@ -1,362 +0,0 @@
# Copyright (c) 2017 The xterm.js authors. All rights reserved.
# Ported to GDScript by the GodotXterm authors.
# License MIT
extends "res://addons/gut/test.gd"
const Buffer = preload("res://addons/godot_xterm/buffer/buffer.gd")
const CircularList = preload("res://addons/godot_xterm/circular_list.gd")
const CellData = preload("res://addons/godot_xterm/buffer/cell_data.gd")
const AttributeData = preload("res://addons/godot_xterm/buffer/attribute_data.gd")
const TestUtils = preload("res://test/test_utils.gd")
class BaseBufferTest:
extends "res://addons/gut/test.gd"
const INIT_COLS = 80
const INIT_ROWS = 24
const INIT_SCROLLBACK = 1000
var options_service
var buffer_service
var buffer
func before_each():
options_service = TestUtils.MockOptionsService.new({'scrollback': INIT_SCROLLBACK})
buffer_service = TestUtils.MockBufferService.new(INIT_COLS, INIT_ROWS)
buffer = Buffer.new(true, options_service, buffer_service)
class TestInit:
extends BaseBufferTest
func test_buffer_lines():
assert_eq(buffer.lines.get_script(), CircularList)
assert_eq(buffer.lines.max_length, buffer_service.rows + INIT_SCROLLBACK)
func test_buffer_scroll_bottom():
assert_eq(buffer.scroll_bottom, buffer_service.rows - 1)
func test_fill_viewport_rows():
# It should fill the buffer with blank lines based on the size of the viewport
var blank_line_char = buffer.get_blank_line(AttributeData.new()).load_cell(0, CellData.new()).get_as_char_data()
buffer.fill_viewport_rows()
assert_eq(buffer.lines.length, INIT_ROWS)
for y in range(INIT_ROWS):
assert_eq(buffer.lines.get_el(y).length, INIT_COLS)
for x in range(INIT_COLS):
assert_eq(buffer.lines.get_el(y).load_cell(x, CellData.new()).get_as_char_data(), blank_line_char)
class TestGetWrappedRangeForLine:
extends BaseBufferTest
func before_each():
.before_each()
buffer.fill_viewport_rows()
func test_non_wrapped_returns_a_single_row_for_the_first_row():
assert_eq(buffer.get_wrapped_range_for_line(0).first, 0)
assert_eq(buffer.get_wrapped_range_for_line(0).last, 0)
func test_non_wrapped_returns_a_single_row_for_a_middle_row():
assert_eq(buffer.get_wrapped_range_for_line(12).first, 12)
assert_eq(buffer.get_wrapped_range_for_line(12).last, 12)
func test_non_wrapped_returns_a_single_row_for_the_last_row():
assert_eq(buffer.get_wrapped_range_for_line(buffer.lines.length - 1).first, INIT_ROWS - 1)
assert_eq(buffer.get_wrapped_range_for_line(buffer.lines.length - 1).last, INIT_ROWS - 1)
func test_wrapped_returns_a_range_for_first_row():
buffer.lines.get_el(1).is_wrapped = true
assert_eq(buffer.get_wrapped_range_for_line(0).first, 0)
assert_eq(buffer.get_wrapped_range_for_line(0).last, 1)
func test_wrapped_range_for_middle_row_wrapping_upwards():
buffer.fill_viewport_rows()
buffer.lines.get_el(12).is_wrapped = true
assert_eq(buffer.get_wrapped_range_for_line(12).first, 11)
assert_eq(buffer.get_wrapped_range_for_line(12).last, 12)
func test_wrapped_range_for_middle_row_wrapping_downwards():
buffer.lines.get_el(13).is_wrapped = true
assert_eq(buffer.get_wrapped_range_for_line(12).first, 12)
assert_eq(buffer.get_wrapped_range_for_line(12).last, 13)
func test_wrapped_range_for_middle_row_wrapping_both_ways():
buffer.lines.get_el(11).is_wrapped = true
buffer.lines.get_el(12).is_wrapped = true
buffer.lines.get_el(13).is_wrapped = true
buffer.lines.get_el(14).is_wrapped = true
assert_eq(buffer.get_wrapped_range_for_line(12).first, 10)
assert_eq(buffer.get_wrapped_range_for_line(12).last, 14)
func test_wrapped_range_for_last_row():
buffer.lines.get_el(INIT_ROWS - 1).is_wrapped = true
assert_eq(buffer.get_wrapped_range_for_line(buffer.lines.length - 1).first, INIT_ROWS - 2)
assert_eq(buffer.get_wrapped_range_for_line(buffer.lines.length - 1).last, INIT_ROWS - 1)
func test_wrapped_range_for_row_that_wraps_upward_to_first_row():
buffer.lines.get_el(1).is_wrapped = true
assert_eq(buffer.get_wrapped_range_for_line(1).first, 0)
assert_eq(buffer.get_wrapped_range_for_line(1).last, 1)
func test_wrapped_range_for_row_that_wraps_downward_to_last_row():
buffer.lines.get_el(buffer.lines.length - 1).is_wrapped = true
assert_eq(buffer.get_wrapped_range_for_line(buffer.lines.length - 2).first, INIT_ROWS - 2)
assert_eq(buffer.get_wrapped_range_for_line(buffer.lines.length - 2).last, INIT_ROWS - 1)
class TestResize:
extends BaseBufferTest
func before_each():
.before_each()
buffer.fill_viewport_rows()
func test_column_size_reduction_trims_data_in_the_buffer():
buffer.resize(INIT_COLS / 2, INIT_ROWS)
assert_eq(buffer.lines.length, INIT_ROWS)
for i in range(INIT_ROWS):
assert_eq(buffer.lines.get_line(i).length, INIT_COLS / 2)
func test_column_size_increase_adds_pad_columns():
buffer.resize(INIT_COLS + 10, INIT_ROWS)
assert_eq(buffer.lines.length, INIT_ROWS)
for i in range(INIT_ROWS):
assert_eq(buffer.lines.get_line(i).length, INIT_COLS + 10)
func test_row_size_reduction_trims_blank_lines_from_the_end():
buffer.resize(INIT_COLS, INIT_ROWS - 10)
assert_eq(buffer.lines.length, INIT_ROWS - 10)
func test_row_size_reduction_moves_viewport_down_when_it_is_at_the_end():
# Set cursor y to have 5 blank lines below it
buffer.y = INIT_ROWS - 5 - 1
buffer.resize(INIT_COLS, INIT_ROWS - 10)
# Trim 5 rows
assert_eq(buffer.lines.length, INIT_ROWS - 5)
# Shift the viewport down 5 rows
assert_eq(buffer.ydisp, 5)
assert_eq(buffer.ybase, 5)
func test_no_scrollback_trims_from_the_top_of_the_buffer_when_the_cursor_reaches_the_bottom():
buffer = Buffer.new(true, TestUtils.MockOptionsService.new({"scrollback": 0}), buffer_service)
assert_eq(buffer.lines.max_length, INIT_ROWS)
buffer.y = INIT_ROWS - 1
buffer.fill_viewport_rows()
var ch_data = buffer.lines.get_line(5).load_cell(0, CellData.new()).get_as_char_data()
ch_data[1] = "a"
buffer.lines.get_line(5).set_cell(0, CellData.from_char_data(ch_data))
ch_data = buffer.lines.get_line(INIT_ROWS - 1).load_cell(0, CellData.new()).get_as_char_data()
ch_data[1] = "b"
buffer.lines.get_line(INIT_ROWS - 1).set_cell(0, CellData.from_char_data(ch_data))
buffer.resize(INIT_COLS, INIT_ROWS - 5)
assert_eq(buffer.lines.get_line(0).load_cell(0, CellData.new()).get_as_char_data()[1], "a")
assert_eq(buffer.lines.get_line(INIT_ROWS - 1 - 5).load_cell(0, CellData.new()).get_as_char_data()[1], "b")
func test_row_size_increase_adds_blank_lines_to_empty_buffer():
assert_eq(buffer.ydisp, 0)
buffer.resize(INIT_COLS, INIT_ROWS + 10)
assert_eq(buffer.ydisp, 0)
assert_eq(buffer.lines.length, INIT_ROWS + 10)
func test_row_size_increase_shows_more_of_the_buffer_above():
# Create 10 extra blank lines
for i in range(10):
buffer.lines.push(buffer.get_blank_line(AttributeData.new()))
# Set cursor to the bottom of the buffer
buffer.y = INIT_ROWS - 1
# Scroll down 10 lines
buffer.ybase = 10
buffer.ydisp = 10
assert_eq(buffer.lines.length, INIT_ROWS + 10)
buffer.resize(INIT_COLS, INIT_ROWS + 5)
# Should be 5 more lines
assert_eq(buffer.ydisp, 5)
assert_eq(buffer.ybase, 5)
# Should not trim the buffer
assert_eq(buffer.lines.length, INIT_ROWS + 10)
func test_row_size_increase_shows_more_of_the_buffer_below_when_the_viewort_is_at_the_top_of_the_buffer():
# Create 10 extra blank lines
for i in range(10):
buffer.lines.push(buffer.get_blank_line(AttributeData.new()))
# Set cursor to the bottom of the buffer
buffer.y = INIT_ROWS - 1
# Scroll down 10 lines
buffer.ybase = 10
buffer.ydisp = 0
assert_eq(buffer.lines.length, INIT_ROWS + 10)
buffer.resize(INIT_COLS, INIT_ROWS + 5)
# The viewport should remain at the top
assert_eq(buffer.ydisp, 0)
# The buffer ybase should move up 5 lines
assert_eq(buffer.ybase, 5)
# Should not trim the buffer
assert_eq(buffer.lines.length, INIT_ROWS + 10)
func test_row_and_column_increase_resizes_properly():
buffer.resize(INIT_COLS + 5, INIT_ROWS + 5)
assert_eq(buffer.lines.length, INIT_ROWS + 5)
buffer.resize(INIT_COLS - 5, INIT_ROWS)
assert_eq(buffer.lines.length, INIT_ROWS)
func test_reflow_does_not_wrap_empty_lines():
assert_eq(buffer.lines.length, INIT_ROWS)
buffer.resize(INIT_COLS - 5, INIT_ROWS)
assert_eq(buffer.lines.length, INIT_ROWS)
func test_reflow_shrinks_row_length():
buffer.resize(5, 10)
assert_eq(buffer.lines.length, 10)
for i in range(10):
assert_eq(buffer.lines.get_line(i).length, 5)
func test_reflow_wraps_and_unwraps_lines():
buffer.resize(5, 10)
var first_line = buffer.lines.get_line(0)
for i in range(5):
var code = "a".ord_at(0) + i
var ch = char(code)
first_line.set_cell(i, CellData.from_char_data([0, ch, 1, code]))
buffer.y = 1
assert_eq(buffer.lines.get_line(0).length, 5)
assert_eq(buffer.lines.get_line(0).translate_to_string(), "abcde")
buffer.resize(1, 10)
assert_eq(buffer.lines.length, 10)
assert_eq(buffer.lines.get_line(0).translate_to_string(), "a")
assert_eq(buffer.lines.get_line(1).translate_to_string(), "b")
assert_eq(buffer.lines.get_line(2).translate_to_string(), "c")
assert_eq(buffer.lines.get_line(3).translate_to_string(), "d")
assert_eq(buffer.lines.get_line(4).translate_to_string(), "e")
assert_eq(buffer.lines.get_line(5).translate_to_string(), " ")
assert_eq(buffer.lines.get_line(6).translate_to_string(), " ")
assert_eq(buffer.lines.get_line(7).translate_to_string(), " ")
assert_eq(buffer.lines.get_line(8).translate_to_string(), " ")
assert_eq(buffer.lines.get_line(9).translate_to_string(), " ")
buffer.resize(5, 10)
assert_eq(buffer.lines.length, 10)
assert_eq(buffer.lines.get_line(0).translate_to_string(), "abcde")
assert_eq(buffer.lines.get_line(1).translate_to_string(), " ")
assert_eq(buffer.lines.get_line(2).translate_to_string(), " ")
assert_eq(buffer.lines.get_line(3).translate_to_string(), " ")
assert_eq(buffer.lines.get_line(4).translate_to_string(), " ")
assert_eq(buffer.lines.get_line(5).translate_to_string(), " ")
assert_eq(buffer.lines.get_line(6).translate_to_string(), " ")
assert_eq(buffer.lines.get_line(7).translate_to_string(), " ")
assert_eq(buffer.lines.get_line(8).translate_to_string(), " ")
assert_eq(buffer.lines.get_line(9).translate_to_string(), " ")
func test_discards_parts_of_wrapped_lines_that_go_out_of_the_scrollback():
options_service.options.scrollback = 1
buffer.resize(10, 5)
var last_line = buffer.lines.get_line(3)
for i in range(10):
var code = "a".ord_at(0) + i
var ch = char(code)
last_line.set_cell(i, CellData.from_char_data([0, ch, 1, code]))
assert_eq(buffer.lines.length, 5)
buffer.y = 4
buffer.resize(2, 5)
assert_eq(buffer.y, 4)
assert_eq(buffer.ybase, 1)
assert_eq(buffer.lines.get_line(0).translate_to_string(), "ab")
assert_eq(buffer.lines.get_line(1).translate_to_string(), "cd")
assert_eq(buffer.lines.get_line(2).translate_to_string(), "ef")
assert_eq(buffer.lines.get_line(3).translate_to_string(), "gh")
assert_eq(buffer.lines.get_line(4).translate_to_string(), "ij")
assert_eq(buffer.lines.get_line(5).translate_to_string(), " ")
buffer.resize(1, 5)
assert_eq(buffer.y, 4)
assert_eq(buffer.ybase, 1)
assert_eq(buffer.lines.length, 6)
assert_eq(buffer.lines.get_line(0).translate_to_string(), "f")
assert_eq(buffer.lines.get_line(1).translate_to_string(), "g")
assert_eq(buffer.lines.get_line(2).translate_to_string(), "h")
assert_eq(buffer.lines.get_line(3).translate_to_string(), "i")
assert_eq(buffer.lines.get_line(4).translate_to_string(), "j")
assert_eq(buffer.lines.get_line(5).translate_to_string(), " ")
buffer.resize(10, 5)
assert_eq(buffer.y, 1)
assert_eq(buffer.ybase, 0)
assert_eq(buffer.lines.length, 5)
assert_eq(buffer.lines.get_line(0).translate_to_string(), "fghij ")
assert_eq(buffer.lines.get_line(1).translate_to_string(), " ")
assert_eq(buffer.lines.get_line(2).translate_to_string(), " ")
assert_eq(buffer.lines.get_line(3).translate_to_string(), " ")
assert_eq(buffer.lines.get_line(4).translate_to_string(), " ")
func test_removes_the_correct_amount_of_rows_when_reflowing_larger():
# This is a regression test to ensure that successive wrapped lines that are getting
# 3+ lines removed on a reflow actually remove the right lines
buffer.resize(10, 10)
buffer.y = 2
var first_line = buffer.lines.get_line(0)
var second_line = buffer.lines.get_line(1)
for i in range(10):
var code = "a".ord_at(0) + i
var ch = char(code)
first_line.set_cell(i, CellData.from_char_data([0, ch, 1, code]))
for i in range(10):
var code = "0".ord_at(0) + i
var ch = char(code)
second_line.set_cell(i, CellData.from_char_data([0, ch, 1, code]))
assert_eq(buffer.lines.length, 10)
assert_eq(buffer.lines.get_line(0).translate_to_string(), "abcdefghij")
assert_eq(buffer.lines.get_line(1).translate_to_string(), "0123456789")
for i in range(2, 10):
assert_eq(buffer.lines.get_line(i).translate_to_string(), " ")
buffer.resize(2, 10)
assert_eq(buffer.ybase, 1)
assert_eq(buffer.lines.length, 11)
assert_eq(buffer.lines.get_line(0).translate_to_string(), "ab")
assert_eq(buffer.lines.get_line(1).translate_to_string(), "cd")
assert_eq(buffer.lines.get_line(2).translate_to_string(), "ef")
assert_eq(buffer.lines.get_line(3).translate_to_string(), "gh")
assert_eq(buffer.lines.get_line(4).translate_to_string(), "ij")
assert_eq(buffer.lines.get_line(5).translate_to_string(), "01")
assert_eq(buffer.lines.get_line(6).translate_to_string(), "23")
assert_eq(buffer.lines.get_line(7).translate_to_string(), "45")
assert_eq(buffer.lines.get_line(8).translate_to_string(), "67")
assert_eq(buffer.lines.get_line(9).translate_to_string(), "89")
assert_eq(buffer.lines.get_line(10).translate_to_string(), " ")
buffer.resize(10, 10)
assert_eq(buffer.ybase, 0)
assert_eq(buffer.lines.length, 10)
assert_eq(buffer.lines.get_line(0).translate_to_string(), "abcdefghij")
assert_eq(buffer.lines.get_line(1).translate_to_string(), "0123456789")
for i in range(2, 10):
assert_eq(buffer.lines.get_line(i).translate_to_string(), " ",
"line %d is incorrect" % i)

View file

@ -1,436 +0,0 @@
# Copyright (c) 2018 The xterm.js authors. All rights reserved.
# Ported to GDScript by the GodotXterm authors.
# License MIT
extends "res://addons/gut/test.gd"
const BufferLine = preload("res://addons/godot_xterm/buffer/buffer_line.gd")
const AttributeData = preload("res://addons/godot_xterm/buffer/attribute_data.gd")
const CellData = preload("res://addons/godot_xterm/buffer/cell_data.gd")
const Decoder = preload("res://addons/godot_xterm/input/text_decoder.gd")
const Constants = preload("res://addons/godot_xterm/buffer/constants.gd")
const BgFlags = Constants.BgFlags
const Attributes = Constants.Attributes
const UnderlineStyle = Constants.UnderlineStyle
const FgFlags = Constants.FgFlags
const Content = Constants.Content
class BufferLineTest:
extends BufferLine
func _init(cols: int, fill_cell_data = null, is_wrapped: bool = false).(cols, fill_cell_data, is_wrapped):
pass
func to_array():
var result = []
for i in range(length):
result.append(load_cell(i, CellData.new()).get_as_char_data())
return result
class TestAttributeData:
extends "res://addons/gut/test.gd"
var attrs
func before_each():
attrs = AttributeData.new()
func test_has_extended_attrs():
assert_eq(attrs.has_extended_attrs() as bool, false)
attrs.bg |= BgFlags.HAS_EXTENDED
assert_eq(attrs.has_extended_attrs() as bool, true)
func test_get_underline_color_P256():
# set a P256 color
attrs.extended.underline_color = Attributes.CM_P256 | 45
# should use FG color if BgFlags.HAS_EXTENDED is not set
assert_eq(attrs.get_underline_color(), -1)
# should use underline_color is BgFlags.HAS_EXTENDED is set and underline_color holds a value
attrs.bg |= BgFlags.HAS_EXTENDED
assert_eq(attrs.get_underline_color(), 45)
# should use FG color if underline_color holds no value
attrs.extended.underline_color = -1
attrs.fg |= Attributes.CM_P256 | 123
assert_eq(attrs.get_underline_color(), 123)
func test_get_underline_color_RGB():
# set a P256 color
attrs.extended.underline_color = Attributes.CM_RGB | (1 << 16) | (2 << 8) | 3
# should use FG color if BgFlags.HAS_EXTENDED is not set
assert_eq(attrs.get_underline_color(), -1)
# should use underline_color if BgFlags.HAS_EXTENDED is set and underline_color holds a value
attrs.bg |= BgFlags.HAS_EXTENDED
assert_eq(attrs.get_underline_color(), (1 << 16) | (2 << 8) | 3)
# should use FG color if underline_color holds no value
attrs.extended.underline_color = -1
attrs.fg |= Attributes.CM_P256 | 123
assert_eq(attrs.get_underline_color(), 123)
func test_underline_attrs():
# should always return color mode of fg
for mode in [Attributes.CM_DEFAULT, Attributes.CM_P16, Attributes.CM_P256, Attributes.CM_RGB]:
attrs.extended.underline_color = mode
assert_eq(attrs.get_underline_color_mode(), attrs.get_fg_color_mode())
assert_eq(attrs.is_underline_color_default(), true)
attrs.fg = Attributes.CM_RGB
for mode in [Attributes.CM_DEFAULT, Attributes.CM_P16, Attributes.CM_P256, Attributes.CM_RGB]:
attrs.extended.underline_color = mode
assert_eq(attrs.get_underline_color_mode(), attrs.get_fg_color_mode())
assert_eq(attrs.is_underline_color_default(), false)
assert_eq(attrs.is_underline_color_rgb(), true)
# should return own mode
attrs.bg |= BgFlags.HAS_EXTENDED
attrs.extended.underline_color = Attributes.CM_DEFAULT
assert_eq(attrs.get_underline_color_mode(), Attributes.CM_DEFAULT)
attrs.extended.underline_color = Attributes.CM_P16
assert_eq(attrs.get_underline_color_mode(), Attributes.CM_P16)
assert_eq(attrs.is_underline_color_palette(), true)
attrs.extended.underline_color = Attributes.CM_P256
assert_eq(attrs.get_underline_color_mode(), Attributes.CM_P256)
assert_eq(attrs.is_underline_color_palette(), true)
attrs.extended.underline_color = Attributes.CM_RGB
assert_eq(attrs.get_underline_color_mode(), Attributes.CM_RGB)
assert_eq(attrs.is_underline_color_rgb(), true)
func test_get_underline_style():
# defaults to no underline style
assert_eq(attrs.get_underline_style(), UnderlineStyle.NONE)
# should return NONE if UNDERLINE is not set
attrs.extended.underline_style = UnderlineStyle.CURLY
assert_eq(attrs.get_underline_style(), UnderlineStyle.NONE)
# should return SINGLE style if UNDERLINE is set and HAS_EXTENDED is false
attrs.fg |= FgFlags.UNDERLINE
assert_eq(attrs.get_underline_style(), UnderlineStyle.SINGLE)
# shoud return correct style if both is set
attrs.bg |= BgFlags.HAS_EXTENDED
assert_eq(attrs.get_underline_style(), UnderlineStyle.CURLY)
# should return NONE if UNDERLINE is not set, but HAS_EXTENDED is true
attrs.fg &= ~FgFlags.UNDERLINE
assert_eq(attrs.get_underline_style(), UnderlineStyle.NONE)
class TestCellData:
extends "res://addons/gut/test.gd"
var cell
var decoder = Decoder.Utf8ToUtf32.new()
func before_each():
cell = CellData.new()
func test_char_data_cell_data_equality():
# ASCII
cell.set_from_char_data([123, 'a', 1, 'a'.ord_at(0)])
assert_eq(cell.get_as_char_data(), [123, 'a', 1, 'a'.ord_at(0)])
assert_eq(cell.is_combined(), 0)
# combining
cell.set_from_char_data([123, 'e\u0301', 1, '\u0301'.ord_at(0)])
assert_eq(cell.get_as_char_data(), [123, 'e\u0301', 1, '\u0301'.ord_at(0)])
assert_eq(cell.is_combined(), Content.IS_COMBINED_MASK)
# surrogate
cell.set_from_char_data([123, '𝄞', 1, 0x1D11E])
assert_eq(cell.get_as_char_data(), [123, '𝄞', 1, 0x1D11E])
assert_eq(cell.is_combined(), 0)
# surrogate + combining
cell.set_from_char_data([123, '𓂀\u0301', 1, '𓂀\u0301'.ord_at(1)])
assert_eq(cell.get_as_char_data(), [123, '𓂀\u0301', 1, '𓂀\u0301'.ord_at(1)])
assert_eq(cell.is_combined(), Content.IS_COMBINED_MASK)
# wide char
cell.set_from_char_data([123, '', 2, ''.ord_at(0)])
assert_eq(cell.get_as_char_data(), [123, '', 2, ''.ord_at(0)])
assert_eq(cell.is_combined(), 0)
class TestBufferLine:
extends "res://addons/gut/test.gd"
func test_ctor():
var line = BufferLineTest.new(0)
assert_eq(line.length, 0)
assert_eq(line.is_wrapped, false)
line = BufferLineTest.new(10)
assert_eq(line.length, 10)
assert_eq(line.load_cell(0, CellData.new()).get_as_char_data(),
[0, Constants.NULL_CELL_CHAR, Constants.NULL_CELL_WIDTH,
Constants.NULL_CELL_CODE])
assert_eq(line.is_wrapped, false)
line = BufferLineTest.new(10, null, true)
assert_eq(line.length, 10)
assert_eq(line.load_cell(0, CellData.new()).get_as_char_data(),
[0, Constants.NULL_CELL_CHAR, Constants.NULL_CELL_WIDTH,
Constants.NULL_CELL_CODE])
assert_eq(line.is_wrapped, true)
var char_data = [123, 'a', 456, 'a'.ord_at(0)]
line = BufferLineTest.new(10, CellData.from_char_data(char_data), true)
assert_eq(line.length, 10)
assert_eq(line.load_cell(0, CellData.new()).get_as_char_data(), char_data)
assert_eq(line.is_wrapped, true)
func test_insert_cells() -> void:
var line = BufferLineTest.new(3)
line.set_cell(0, CellData.from_char_data([1, 'a', 0, 'a'.ord_at(0)]))
line.set_cell(1, CellData.from_char_data([2, 'b', 0, 'b'.ord_at(0)]))
line.set_cell(2, CellData.from_char_data([3, 'c', 0, 'c'.ord_at(0)]))
line.insert_cells(1, 3, CellData.from_char_data([4, 'd', 0, 'd'.ord_at(0)]))
assert_eq(line.to_array(), [
[1, 'a', 0, 'a'.ord_at(0)],
[4, 'd', 0, 'd'.ord_at(0)],
[4, 'd', 0, 'd'.ord_at(0)]
])
func test_delete_cells() -> void:
var line = BufferLineTest.new(5)
line.set_cell(0, CellData.from_char_data([1, 'a', 0, 'a'.ord_at(0)]))
line.set_cell(1, CellData.from_char_data([2, 'b', 0, 'b'.ord_at(0)]))
line.set_cell(2, CellData.from_char_data([3, 'c', 0, 'c'.ord_at(0)]))
line.set_cell(3, CellData.from_char_data([4, 'd', 0, 'd'.ord_at(0)]))
line.set_cell(4, CellData.from_char_data([5, 'e', 0, 'e'.ord_at(0)]))
line.delete_cells(1, 2, CellData.from_char_data([6, 'f', 0, 'f'.ord_at(0)]))
assert_eq(line.to_array(), [
[1, 'a', 0, 'a'.ord_at(0)],
[4, 'd', 0, 'd'.ord_at(0)],
[5, 'e', 0, 'e'.ord_at(0)],
[6, 'f', 0, 'f'.ord_at(0)],
[6, 'f', 0, 'f'.ord_at(0)]
])
func test_replace_cells():
var line = BufferLineTest.new(5)
line.set_cell(0, CellData.from_char_data([1, 'a', 0, 'a'.ord_at(0)]))
line.set_cell(1, CellData.from_char_data([2, 'b', 0, 'b'.ord_at(0)]))
line.set_cell(2, CellData.from_char_data([3, 'c', 0, 'c'.ord_at(0)]))
line.set_cell(3, CellData.from_char_data([4, 'd', 0, 'd'.ord_at(0)]))
line.set_cell(4, CellData.from_char_data([5, 'e', 0, 'e'.ord_at(0)]))
line.replace_cells(2, 4, CellData.from_char_data([6, 'f', 0, 'f'.ord_at(0)]))
assert_eq(line.to_array(), [
[1, 'a', 0, 'a'.ord_at(0)],
[2, 'b', 0, 'b'.ord_at(0)],
[6, 'f', 0, 'f'.ord_at(0)],
[6, 'f', 0, 'f'.ord_at(0)],
[5, 'e', 0, 'e'.ord_at(0)],
])
func test_copy_from():
var line = BufferLineTest.new(5)
line.set_cell(0, CellData.from_char_data([1, 'a', 0, 'a'.ord_at(0)]))
line.set_cell(0, CellData.from_char_data([2, 'b', 0, 'b'.ord_at(0)]))
line.set_cell(0, CellData.from_char_data([3, 'c', 0, 'c'.ord_at(0)]))
line.set_cell(0, CellData.from_char_data([4, 'd', 0, 'd'.ord_at(0)]))
line.set_cell(0, CellData.from_char_data([5, 'e', 0, 'e'.ord_at(0)]))
var line2 = BufferLineTest.new(5, CellData.from_char_data([1, 'a', 0, 'a'.ord_at(0)]), true)
line2.copy_from(line)
assert_eq(line2.to_array(), line.to_array())
assert_eq(line2.length, line.length)
assert_eq(line2.is_wrapped, line.is_wrapped)
class TestResize:
extends "res://addons/gut/test.gd"
var CHAR_DATA = [1, 'a', 0, 'a'.ord_at(0)]
var line
func repeat(el, times: int) -> Array:
var result = []
result.resize(times)
for i in range(times):
result[i] = el
return result
func test_enlarge():
line = BufferLineTest.new(5, CellData.from_char_data(CHAR_DATA), false)
line.resize(10, CellData.from_char_data(CHAR_DATA))
assert_eq(line.to_array(), repeat(CHAR_DATA, 10))
func test_shrink():
line = BufferLineTest.new(10, CellData.from_char_data(CHAR_DATA), false)
line.resize(5, CellData.from_char_data(CHAR_DATA))
assert_eq(line.to_array(), repeat(CHAR_DATA, 5))
func test_shrink_to_0_length():
line = BufferLineTest.new(10, CellData.from_char_data(CHAR_DATA), false)
line.resize(0, CellData.from_char_data(CHAR_DATA))
assert_eq(line.to_array(), repeat(CHAR_DATA, 0))
func shrink_then_enlarge():
line = BufferLineTest.new(10, CellData.from_char_data(CHAR_DATA), false);
line.set_cell(2, CellData.from_char_data([0, '😁', 1, '😁'.ord_at(0)]))
line.set_cell(9, CellData.from_char_data([0, '😁', 1, '😁'.ord_at(0)]))
assert_eq(line.translate_to_string(), 'aa😁aaaaaa😁')
line.resize(5, CellData.from_char_data(CHAR_DATA))
assert_eq(line.translate_to_string(), 'aa😁aa')
line.resize(10, CellData.from_char_data(CHAR_DATA))
assert_eq(line.translate_to_string(), 'aa😁aaaaaaa')
class TestTrimLength:
extends "res://addons/gut/test.gd"
var line
func before_each():
line = BufferLineTest.new(3, CellData.from_char_data([Constants.DEFAULT_ATTR,
Constants.NULL_CELL_CHAR, Constants.NULL_CELL_WIDTH, Constants.NULL_CELL_CODE]))
func test_empty_line():
assert_eq(line.get_trimmed_length(), 0)
func test_ascii():
line.set_cell(0, CellData.from_char_data([1, "a", 1, "a".ord_at(0)]))
line.set_cell(2, CellData.from_char_data([1, "a", 1, "a".ord_at(0)]))
assert_eq(line.get_trimmed_length(), 3)
func test_unicode():
line.set_cell(0, CellData.from_char_data([1, "\u1f914", 1, "\u1f914".ord_at(0)]))
line.set_cell(2, CellData.from_char_data([1, "\u1f914", 1, "\u1f914".ord_at(0)]))
assert_eq(line.get_trimmed_length(), 3)
func test_one_cell():
line.set_cell(0, CellData.from_char_data([1, "a", 1, "a".ord_at(0)]))
assert_eq(line.get_trimmed_length(), 1)
class TestAddCharToCell:
extends "res://addons/gut/test.gd"
var line
var cell
func before_each():
line = BufferLineTest.new(3, CellData.from_char_data([Constants.DEFAULT_ATTR,
Constants.NULL_CELL_CHAR, Constants.NULL_CELL_WIDTH, Constants.NULL_CELL_CODE]))
cell = line.load_cell(0, CellData.new())
func test_sets_width_to_1_for_empty_cell():
line.add_codepoint_to_cell(0, "\u0301".ord_at(0))
cell = line.load_cell(0, CellData.new())
# chars contains single combining char
# width is set to 1
assert_eq(cell.get_as_char_data(), [Constants.DEFAULT_ATTR, '\u0301', 1, 0x0301])
# do not account a single combining char as combined
assert_eq(cell.is_combined(), 0)
func test_add_char_to_combining_string_in_cell():
cell.set_from_char_data([123, "e\u0301", 1, "e\u0301".ord_at(1)])
line.set_cell(0, cell)
line.add_codepoint_to_cell(0, "\u0301".ord_at(0))
line.load_cell(0, cell)
# char contains 3 chars
# width is set to 1
assert_eq(cell.get_as_char_data(), [123, "e\u0301\u0301", 1, 0x0301])
# do not account a single combining char as combined
assert_eq(cell.is_combined(), Content.IS_COMBINED_MASK)
func test_create_combining_string_on_taken_cell():
cell.set_from_char_data([123, "e", 1, "e".ord_at(1)])
line.set_cell(0, cell)
line.add_codepoint_to_cell(0, "\u0301".ord_at(0))
line.load_cell(0, cell)
# chars contains 2 chars
# width is set to 1
assert_eq(cell.get_as_char_data(), [123, "e\u0301", 1, 0x0301])
# do not account a single combining char as combined
assert_eq(cell.is_combined(), Content.IS_COMBINED_MASK)
class TestTranslateToString:
extends "res://addons/gut/test.gd"
var line
func before_each():
line = BufferLineTest.new(10, CellData.from_char_data([Constants.DEFAULT_ATTR,
Constants.NULL_CELL_CHAR, Constants.NULL_CELL_WIDTH, Constants.NULL_CELL_CODE]), false)
func test_empty_line():
assert_eq(line.translate_to_string(false), ' ')
assert_eq(line.translate_to_string(true), '')
func test_ASCII():
line.set_cell(0, CellData.from_char_data([1, 'a', 1, 'a'.ord_at(0)]))
line.set_cell(2, CellData.from_char_data([1, 'a', 1, 'a'.ord_at(0)]))
line.set_cell(4, CellData.from_char_data([1, 'a', 1, 'a'.ord_at(0)]))
line.set_cell(5, CellData.from_char_data([1, 'a', 1, 'a'.ord_at(0)]))
assert_eq(line.translate_to_string(false), 'a a aa ')
assert_eq(line.translate_to_string(true), 'a a aa')
assert_eq(line.translate_to_string(false, 0, 5), 'a a a')
assert_eq(line.translate_to_string(false, 0, 4), 'a a ')
assert_eq(line.translate_to_string(false, 0, 3), 'a a')
assert_eq(line.translate_to_string(true, 0, 5), 'a a a')
assert_eq(line.translate_to_string(true, 0, 4), 'a a ')
assert_eq(line.translate_to_string(true, 0, 3), 'a a')
func test_space_at_end():
line.set_cell(0, CellData.from_char_data([1, 'a', 1, 'a'.ord_at(0)]))
line.set_cell(2, CellData.from_char_data([1, 'a', 1, 'a'.ord_at(0)]))
line.set_cell(4, CellData.from_char_data([1, 'a', 1, 'a'.ord_at(0)]))
line.set_cell(5, CellData.from_char_data([1, 'a', 1, 'a'.ord_at(0)]))
line.set_cell(6, CellData.from_char_data([1, ' ', 1, ' '.ord_at(0)]))
assert_eq(line.translate_to_string(false), 'a a aa ')
assert_eq(line.translate_to_string(true), 'a a aa ')
func test_always_returns_some_sane_value():
# sanity check - broken line with invalid out of bound null width cells
# this can atm happen with deleting/inserting chars in inputhandler by "breaking"
# fullwidth pairs --> needs to be fixed after settling BufferLine impl
assert_eq(line.translate_to_string(false), ' ')
assert_eq(line.translate_to_string(true), '')
func test_works_with_end_col_0():
line.set_cell(0, CellData.from_char_data([1, 'a', 1, 'a'.ord_at(0)]))
assert_eq(line.translate_to_string(true, 0, 0), '')

View file

@ -1,113 +0,0 @@
# Copyright (c) 2019 The xterm.js authors. All rights reserved.
# Ported to GDScript by the GodotXterm authors.
# License MIT
extends 'res://addons/gut/test.gd'
const Decoder = preload("res://addons/godot_xterm/input/text_decoder.gd")
# Note: There might be some invisible characters (such as emoji) depending
# on your editor and font settings.
const TEST_STRINGS = [
"Лорем ипсум долор сит амет, ех сеа аццусам диссентиет. Ан еос стет еирмод витуперата. Иус дицерет урбанитас ет. Ан при алтера долорес сплендиде, цу яуо интегре денияуе, игнота волуптариа инструцтиор цу вим.",
"ლორემ იფსუმ დოლორ სით ამეთ, ფაცერ მუციუს ცონსეთეთურ ყუო იდ, ფერ ვივენდუმ ყუაერენდუმ ეა, ესთ ამეთ მოვეთ სუავითათე ცუ. ვითაე სენსიბუს ან ვიხ. ეხერცი დეთერრუისსეთ უთ ყუი. ვოცენთ დებითის ადიფისცი ეთ ფერ. ნეც ან ფეუგაით ფორენსიბუს ინთერესსეთ. იდ დიცო რიდენს იუს. დისსენთიეთ ცონსეყუუნთურ სედ ნე, ნოვუმ მუნერე ეუმ ათ, ნე ეუმ ნიჰილ ირაცუნდია ურბანითას.",
"अधिकांश अमितकुमार प्रोत्साहित मुख्य जाने प्रसारन विश्लेषण विश्व दारी अनुवादक अधिकांश नवंबर विषय गटकउसि गोपनीयता विकास जनित परस्पर गटकउसि अन्तरराष्ट्रीयकरन होसके मानव पुर्णता कम्प्युटर यन्त्रालय प्रति साधन",
"覧六子当聞社計文護行情投身斗来。増落世的況上席備界先関権能万。本物挙歯乳全事携供板栃果以。頭月患端撤競見界記引去法条公泊候。決海備駆取品目芸方用朝示上用報。講申務紙約週堂出応理田流団幸稿。起保帯吉対阜庭支肯豪彰属本躍。量抑熊事府募動極都掲仮読岸。自続工就断庫指北速配鳴約事新住米信中験。婚浜袋著金市生交保他取情距。",
"八メル務問へふらく博辞説いわょ読全タヨムケ東校どっ知壁テケ禁去フミ人過を装5階がねぜ法逆はじ端40落ミ予竹マヘナセ任1悪た。省ぜりせ製暇ょへそけ風井イ劣手はぼまず郵富法く作断タオイ取座ゅょが出作ホシ月給26島ツチ皇面ユトクイ暮犯リワナヤ断連こうでつ蔭柔薄とレにの。演めけふぱ損田転10得観びトげぎ王物鉄夜がまけ理惜くち牡提づ車惑参ヘカユモ長臓超漫ぼドかわ。",
"모든 국민은 행위시의 법률에 의하여 범죄를 구성하지 아니하는 행위로 소추되지 아니하며. 전직대통령의 신분과 예우에 관하여는 법률로 정한다, 국회는 헌법 또는 법률에 특별한 규정이 없는 한 재적의원 과반수의 출석과 출석의원 과반수의 찬성으로 의결한다. 군인·군무원·경찰공무원 기타 법률이 정하는 자가 전투·훈련등 직무집행과 관련하여 받은 손해에 대하여는 법률이 정하는 보상외에 국가 또는 공공단체에 공무원의 직무상 불법행위로 인한 배상은 청구할 수 없다.",
"كان فشكّل الشرقي مع, واحدة للمجهود تزامناً بعض بل. وتم جنوب للصين غينيا لم, ان وبدون وكسبت الأمور ذلك, أسر الخاسر الانجليزية هو. نفس لغزو مواقعها هو. الجو علاقة الصعداء انه أي, كما مع بمباركة للإتحاد الوزراء. ترتيب الأولى أن حدى, الشتوية باستحداث مدن بل, كان قد أوسع عملية. الأوضاع بالمطالبة كل قام, دون إذ شمال الربيع،. هُزم الخاصّة ٣٠ أما, مايو الصينية مع قبل.",
"או סדר החול מיזמי קרימינולוגיה. קהילה בגרסה לויקיפדים אל היא, של צעד ציור ואלקטרוניקה. מדע מה ברית המזנון ארכיאולוגיה, אל טבלאות מבוקשים כלל. מאמרשיחהצפה העריכהגירסאות שכל אל, כתב עיצוב מושגי של. קבלו קלאסיים ב מתן. נבחרים אווירונאוטיקה אם מלא, לוח למנוע ארכיאולוגיה מה. ארץ לערוך בקרבת מונחונים או, עזרה רקטות לויקיפדים אחר גם.",
"Лорем ლორემ अधिकांश 覧六子 八メル 모든 בקרבת äggg 123€ .",
]
func test_utf32_to_utf8():
# 1 byte utf8 character
assert_eq(
Decoder.utf32_to_utf8(0x00000061),
PoolByteArray([0x61])
)
# 2 byte utf8 character
assert_eq(
Decoder.utf32_to_utf8(0x00000761),
PoolByteArray([0xdd, 0xa1])
)
# 3 byte utf8 character
assert_eq(
Decoder.utf32_to_utf8(0x00002621),
PoolByteArray([0xe2, 0x98, 0xa1])
)
# 4 byte utf8 character
assert_eq(
Decoder.utf32_to_utf8(0x00010144),
PoolByteArray([0xf0, 0x90, 0x85, 0x84])
)
assert_eq(
Decoder.utf32_to_utf8(0x0001f427) as Array,
PoolByteArray([0xf0, 0x9f, 0x90, 0xa7]) as Array
)
func test_utf32_to_string():
assert_eq(
Decoder.utf32_to_string([49, 50, 51, 0x1d11e, 49, 50, 51]),
'123𝄞123'
)
class TestUtf8ToUtf32Decoder:
extends 'res://addons/gut/test.gd'
var decoder = Decoder.Utf8ToUtf32.new()
var target = []
# Full codepoint tests take a long time to run, so skip them unless this
# environment variable is set.
var skip_full_codepoint_tests = not OS.get_environment("RUN_FULL_CODEPOINT_TESTS")
func before_each():
decoder.clear()
target.clear()
target.resize(5)
func test_lol():
var target = [0, 0, 0, 0]
decoder.decode('<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>'.substr(0, 1).to_utf8(), target)
assert_eq(target, [])
func test_full_code_point_0_to_65535(): # 1/2/3 byte sequences
if skip_full_codepoint_tests:
print("Skipping full codepoint test")
return
for i in range(65536):
# skip surrogate pairs
if i >= 0xD800 and i <= 0xDFFF:
continue
# FIXME: Skip 0xfeff (zero width no-break space)
# which fails for some reason
if i == 0xfeff:
continue
var utf8_data = Decoder.utf32_to_utf8(i)
var length = decoder.decode(utf8_data, target)
assert_eq(length, 1)
assert_eq(char(target[0]), utf8_data.get_string_from_utf8(),
"Wrong string for codepoint 0x%x" % target[0])
decoder.clear()
func test_full_codepoint_65536_to_0x10FFFF(): # 4 byte sequences
if skip_full_codepoint_tests:
print("Skipping full codepoint test")
return
for i in range(65536, 0x10FFFF):
var utf8_data = Decoder.utf32_to_utf8(i)
var length = decoder.decode(utf8_data, target)
assert_eq(length, 1)
assert_eq(target[0], i)
func test_test_strings():
target.resize(500)
for string in TEST_STRINGS:
var utf8_data = string.to_utf8()
var length = decoder.decode(utf8_data, target)
assert_eq(Decoder.utf32_to_string(target, 0, length), string)
decoder.clear()

View file

@ -1,100 +0,0 @@
# Copyright (c) 2020 The GodotXterm authors.
# Copyright (c) 2019 The xterm.js authors. All rights reserved.
# License MIT
extends "res://addons/gut/test.gd"
const DcsParser = preload("res://addons/godot_xterm/parser/dcs_parser.gd")
const Parser = preload("res://addons/godot_xterm/parser/escape_sequence_parser.gd")
const Params = preload("res://addons/godot_xterm/parser/params.gd")
const Decoder = preload("res://addons/godot_xterm/input/text_decoder.gd")
class Handler:
extends Reference
var _output
var _msg
var _return_false
func _init(output: Array, msg: String, return_false: bool = false):
_output = output
_msg = msg
_return_false = return_false
func hook(params):
_output.append([_msg, 'HOOK', params.to_array()])
func put(data: Array, start: int, end: int):
_output.append([_msg, 'PUT', Decoder.utf32_to_string(data, start, end)])
func unhook(success: bool):
_output.append([_msg, 'UNHOOK', success])
if _return_false:
return false
var parser: DcsParser
var reports: Array
func to_utf32(s: String):
var utf32 = []
utf32.resize(s.length())
var decoder = Decoder.Utf8ToUtf32.new()
var length = decoder.decode(s.to_utf8(), utf32)
assert_eq(length, s.length())
return utf32.slice(0, length - 1)
func handler_fallback(id, action, data):
if action == 'HOOK':
data = data.to_array()
reports.append([id, action, data])
func before_each():
parser = DcsParser.new()
parser.set_handler_fallback(self, 'handler_fallback')
reports = []
func test_set_dcs_handler():
parser.set_handler(Parser.identifier({'intermediates': '+', 'final': 'p'}),
Handler.new(reports, 'th'))
parser.hook(Parser.identifier({'intermediates': '+', 'final': 'p'}),
Params.from_array([1, 2, 3]))
var data = to_utf32('Here comes')
parser.put(data, 0, data.size())
data = to_utf32('the mouse!')
parser.put(data, 0, data.size())
parser.unhook(true)
assert_eq(reports, [
# messages from Handler
['th', 'HOOK', [1, 2, 3]],
['th', 'PUT', 'Here comes'],
['th', 'PUT', 'the mouse!'],
['th', 'UNHOOK', true],
])
func test_clear_dcs_handler():
var ident = Parser.identifier({'intermediates': '+', 'final': 'p'})
parser.set_handler(ident, Handler.new(reports, 'th'))
parser.clear_handler(ident)
parser.hook(ident, Params.from_array([1, 2, 3]))
var data = to_utf32('Here comes')
parser.put(data, 0, data.size())
data = to_utf32('the mouse!')
parser.put(data, 0, data.size())
parser.unhook(true)
assert_eq(reports, [
# messages from fallback handler
[ident, 'HOOK', [1, 2, 3]],
[ident, 'PUT', 'Here comes'],
[ident, 'PUT', 'the mouse!'],
[ident, 'UNHOOK', true],
])

View file

@ -1,411 +0,0 @@
# Copyright (c) 2020 The GodotXterm authors.
# Copyright (c) 2018 The xterm.js authors. All rights reserved.
# License MIT
extends 'res://addons/gut/test.gd'
const Parser = preload("res://addons/godot_xterm/parser/escape_sequence_parser.gd")
const Params = preload("res://addons/godot_xterm/parser/params.gd")
const Decoder = preload("res://addons/godot_xterm/input/text_decoder.gd")
const Constants = preload("res://addons/godot_xterm/parser/constants.gd")
const ParserState = Constants.ParserState
class TestTerminal:
var calls = []
func clear():
calls = []
func handle_print(data, start, end):
var string = Decoder.utf32_to_string(data, start, end)
calls.append(['print', string])
func handle_csi(ident, params):
var id = Parser.ident_to_string(ident)
var collect = id.substr(0, id.length() - 1)
var flag = id.substr(id.length() - 1, 1)
calls.append(['csi', collect, params, flag])
func handle_esc(ident: int):
var id = Parser.ident_to_string(ident)
var collect = id.substr(0, id.length() - 1)
var flag = id.substr(id.length() - 1, 1)
calls.append(['esc', collect, flag])
func handle_execute(code: int):
var flag = char(code)
calls.append(['exe', flag])
func handle_dcs(collect_and_flag, action, payload):
match action:
'HOOK':
calls.append(['dcs hook', payload.to_array()])
'PUT':
calls.append(['dcs put', payload])
'UNHOOK':
calls.append(['dcs unhook', payload])
# derived parser with access to internal states
class TestParser:
extends Parser
var params setget _set_params,_get_params
var collect setget _set_collect,_get_collect
func _init():
pass
func _set_params(value):
_params = Params.from_array(value)
func _get_params():
return _params.to_array()
func _set_collect(value: String):
_collect = 0
for c in value.to_ascii():
_collect <<= 8
_collect |= c
func _get_collect() -> String:
return ident_to_string(_collect)
func real_params():
return _params
# translate string based parse calls into typed array based
func parse(parser: TestParser, data):
if data == '': # handle the 0x00 codepoint
data = PoolByteArray([0])
else:
data = data.to_utf8()
var container = []
var decoder = Decoder.Utf8ToUtf32.new()
decoder.clear()
var length = decoder.decode(data, container)
parser.parse(container, length)
var parser
var test_terminal
func before_all():
parser = TestParser.new()
test_terminal = TestTerminal.new()
parser.set_print_handler(test_terminal, 'handle_print')
parser.set_csi_handler_fallback(test_terminal, 'handle_csi')
parser.set_esc_handler_fallback(test_terminal, 'handle_esc')
parser.set_execute_handler_fallback(test_terminal, "handle_execute")
parser.set_dcs_handler_fallback(test_terminal, "handle_dcs")
func before_each():
parser.reset()
test_terminal.clear()
func test_initial_states():
assert_eq(parser.initial_state, ParserState.GROUND)
assert_eq(parser.current_state, ParserState.GROUND)
assert_eq(parser._params.to_array(), [0])
func test_reset_states():
var params = Params.new()
params.add_param(123)
parser.current_state = 124
parser._params = params
parser.reset()
assert_eq(parser.current_state, ParserState.GROUND)
assert_eq(parser._params.to_array(), [0])
# state transitions and actions
func test_state_GROUND_execute_action():
var exes = range(0x00, 0x18) + [0x19] + range(0x1c, 0x20)
for exe in exes:
parser.current_state = ParserState.GROUND
parse(parser, char(exe))
assert_eq(parser.current_state, ParserState.GROUND)
parser.reset()
func test_state_GROUND_print_action():
var printables = range(0x20, 0x7f) # NOTE: DEL excluded
for printable in printables:
var string = char(printable)
parser.current_state = ParserState.GROUND
parse(parser, string)
assert_eq(parser.current_state, ParserState.GROUND)
assert_eq(test_terminal.calls, [['print', string]])
parser.reset()
test_terminal.clear()
func test_trans_ANYWHERE_to_GROUND_with_actions():
var exes = [
'\u0018', '\u001a',
'\u0080', '\u0081', '\u0082', '\u0083', '\u0084', '\u0085', '\u0086', '\u0087', '\u0088',
'\u0089', '\u008a', '\u008b', '\u008c', '\u008d', '\u008e', '\u008f',
'\u0091', '\u0092', '\u0093', '\u0094', '\u0095', '\u0096', '\u0097', '\u0099', '\u009a'
]
var exceptions = {
8: { '\u0018': [], '\u001a': [] }, # abort OSC_STRING
13: { '\u0018': [['dcs unhook', false]], '\u001a': [['dcs unhook', false]] } # abort DCS_PASSTHROUGH
}
for state in ParserState.values():
for exe in exes:
if exe != '\u0018' and exe != '\u001a':
continue
parser.current_state = state
parse(parser, exe)
assert_eq(parser.current_state, ParserState.GROUND)
assert_eq(
test_terminal.calls,
exceptions[state][exe] if exceptions.has(state) and exceptions[state].has(exe) else [['exe', exe]],
'state: %s exe: %x' % [ParserState.keys()[state], exe.to_utf8()[0]]
)
parser.reset()
test_terminal.clear()
parse(parser, '\u009c')
assert_eq(parser.current_state, ParserState.GROUND)
assert_eq(test_terminal.calls, [])
parser.reset()
test_terminal.clear()
func skip_test_trans_ANYWHERE_to_ESCAPE_with_clear():
for state in ParserState.values():
var state_name = ParserState.keys()[state]
parser.current_state = state
parser.params = [23]
parser.collect = '#'
parse(parser, '\u001b')
assert_eq(parser.current_state, ParserState.ESCAPE,
'wrong current_state. start state: %s' % state_name)
assert_eq(parser.params, [0],
'wrong params. start state: %s' % state_name)
assert_eq(parser.collect, '',
'wrong collect. start state: %s' % state_name)
parser.reset()
func test_state_ESCAPE_execute_rules():
var exes = range(0x00, 0x18) + [0x19] + range(0x1c, 0x20)
for exe in exes:
parser.current_state = ParserState.ESCAPE
var data = char(exe)
parse(parser, data)
assert_eq(parser.current_state, ParserState.ESCAPE, 'exe: %x' % exe)
assert_eq(test_terminal.calls, [['exe', data]], 'exe: %x' % exe)
parser.reset()
test_terminal.clear()
func test_state_ESCAPE_ignore():
parser.current_state = ParserState.ESCAPE
parse(parser, '\u007f')
assert_eq(parser.current_state, ParserState.ESCAPE)
assert_eq(test_terminal.calls, [])
func test_trans_ESCAPE_to_GROUND_with_esc_dispatch_action():
var dispatches = range(0x30, 0x50) + range(0x51, 0x58) + [0x59, 0x5a] + range(0x60, 0x7f)
for dispatch in dispatches:
parser.current_state = ParserState.ESCAPE
var data = char(dispatch)
parse(parser, data)
assert_eq(parser.current_state, ParserState.GROUND,
'wrong state: %s, dispatch: %x' % [ParserState.keys()[parser.current_state], dispatch])
assert_eq(test_terminal.calls, [['esc', '', data]],
'wrong call. dispatch: %x' % dispatch)
parser.reset()
test_terminal.clear()
func test_trans_ESCAPE_to_ESCAPE_INTERMEDIATE_with_collect_action():
var collect = range(0x20, 0x30)
for c in collect:
parser.current_state = ParserState.ESCAPE
var data = char(c)
parse(parser, data)
assert_eq(parser.current_state, ParserState.ESCAPE_INTERMEDIATE)
assert_eq(parser.collect, data)
parser.reset()
func test_state_ESCAPE_INTERMEDIATE_execute_rules():
var exes = range(0x00, 0x18) + [0x19] + range(0x1c, 0x20)
for exe in exes:
var data = char(exe)
parser.current_state = ParserState.ESCAPE_INTERMEDIATE
parse(parser, data)
assert_eq(parser.current_state, ParserState.ESCAPE_INTERMEDIATE)
assert_eq(test_terminal.calls, [['exe', data]])
parser.reset()
test_terminal.clear()
func test_state_ESCAPE_INTERMEDIATE_ignore():
parser.current_state = ParserState.ESCAPE_INTERMEDIATE
parse(parser, '\u007f')
assert_eq(parser.current_state, ParserState.ESCAPE_INTERMEDIATE)
assert_eq(test_terminal.calls, [])
func test_state_ESCAPE_INTERMEDIATE_collect_action():
var collect = range(0x20, 0x30)
for c in collect:
var data = char(c)
parser.current_state = ParserState.ESCAPE_INTERMEDIATE
parse(parser, data)
assert_eq(parser.current_state, ParserState.ESCAPE_INTERMEDIATE)
assert_eq(parser.collect, data)
parser.reset()
func test_trans_ESCAPE_INTERMEDIATE_to_GROUND_with_esc_dispatch_action():
var collect = range(0x30, 0x7f)
for c in collect:
var data = char(c)
parser.current_state = ParserState.ESCAPE_INTERMEDIATE
parse(parser, data)
assert_eq(parser.current_state, ParserState.GROUND)
# '\u005c' --> ESC + \ (7bit ST) parser does not expose this as it already got handled
assert_eq(test_terminal.calls, [] if c == 0x5c else [['esc', '', data]], 'c: 0x%x' % c)
parser.reset()
test_terminal.clear()
func test_ANYWHERE_or_ESCAPE_to_CSI_ENTRY_with_clear():
# C0
parser.current_state = ParserState.ESCAPE
parser.params = [123]
parser.collect = '#'
parse(parser, '[')
assert_eq(parser.current_state, ParserState.CSI_ENTRY)
assert_eq(parser.params, [0])
assert_eq(parser.collect, '')
parser.reset()
# C1
for state in ParserState.values():
parser.current_state = state
parser.params = [123]
parser.collect = '#'
parse(parser, '\u009b')
assert_eq(parser.current_state, ParserState.CSI_ENTRY)
assert_eq(parser.collect, '')
parser.reset()
func test_CSI_ENTRY_execute_rules():
var exes = range(0x00, 0x18) + [0x19] + range(0x1c, 0x20)
for exe in exes:
var data = char(exe)
parser.current_state = ParserState.CSI_ENTRY
parse(parser, data)
assert_eq(parser.current_state, ParserState.CSI_ENTRY)
assert_eq(test_terminal.calls, [['exe', data]])
parser.reset()
test_terminal.clear()
func test_state_CSI_ENTRY_ignore():
parser.current_state = ParserState.CSI_ENTRY
parse(parser, '\u007f')
assert_eq(parser.current_state, ParserState.CSI_ENTRY)
assert_eq(test_terminal.calls, [])
func test_trans_CSI_ENTRY_to_GROUND_with_csi_dispatch_action():
var dispatches = range(0x40, 0x7f)
for dispatch in dispatches:
var data = char(dispatch)
parser.current_state = ParserState.CSI_ENTRY
parse(parser, data)
assert_eq(parser.current_state, ParserState.GROUND)
assert_eq(test_terminal.calls, [['csi', '', [0], data]])
parser.reset()
test_terminal.clear()
func test_trans_CSI_ENTRY_to_CSI_PARAMS_with_param_or_collect_action():
var params = range(0x30, 0x3a)
var collect = ['\u003c', '\u003d', '\u003e', '\u003f']
for param in params:
parser.current_state = ParserState.CSI_ENTRY
parse(parser, char(param))
assert_eq(parser.current_state, ParserState.CSI_PARAM)
assert_eq(parser.params, [param - 48], 'param: 0x%x' % param)
parser.reset()
parser.current_state = ParserState.CSI_ENTRY
parse(parser, '\u003b')
assert_eq(parser.current_state, ParserState.CSI_PARAM)
assert_eq(parser.params, [0, 0])
parser.reset()
for c in collect:
parser.current_state = ParserState.CSI_ENTRY
parse(parser, c)
assert_eq(parser.current_state, ParserState.CSI_PARAM)
assert_eq(parser.collect, c)
parser.reset()
func test_state_CSI_PARAM_execute_rules():
var exes = range(0x00, 0x018) + [0x19] + range(0x1c, 0x20)
for exe in exes:
var data = char(exe)
parser.current_state = ParserState.CSI_PARAM
parse(parser, data)
assert_eq(parser.current_state, ParserState.CSI_PARAM)
assert_eq(test_terminal.calls, [['exe', data]])
parser.reset()
test_terminal.clear()
func test_state_CSI_PARAM_param_action():
var params = range(0x30, 0x3a)
for param in params:
parser.current_state = ParserState.CSI_PARAM
parse(parser, char(param))
assert_eq(parser.current_state, ParserState.CSI_PARAM)
assert_eq(parser.params, [param - 48], 'param: 0x%x' % param)
parser.reset()
func test_state_CSI_PARAM_ignore():
parser.current_state = ParserState.CSI_PARAM
parse(parser, '\u007f')
assert_eq(parser.current_state, ParserState.CSI_PARAM)
assert_eq(test_terminal.calls, [])
func test_trans_CSI_PARAM_to_GROUND_with_csi_dispatch_action():
var dispatches = range(0x40, 0x7f)
for dispatch in dispatches:
var data = char(dispatch)
parser.current_state = ParserState.CSI_PARAM
parser.params = [0, 1]
parse(parser, data)
assert_eq(parser.current_state, ParserState.GROUND)
assert_eq(test_terminal.calls, [['csi', '', [0, 1], data]])
parser.reset()
test_terminal.clear()
func test_trans_CSI_ENTRY_to_CSI_INTERMEDIATE_with_collect_action():
for collect in range(0x20, 0x30):
var data = char(collect)
parser.current_state = ParserState.CSI_ENTRY
parse(parser, data)
assert_eq(parser.current_state, ParserState.CSI_INTERMEDIATE)
assert_eq(parser.collect, data)
parser.reset()

View file

@ -1,202 +0,0 @@
# Copyright (c) 2019 The xterm.js authors. All rights reserved.
# Ported to GDScript by the GodotXterm authors.
# License MIT
extends 'res://addons/gut/test.gd'
const Params = preload("res://addons/godot_xterm/parser/params.gd")
class TestParams:
extends 'res://addons/gut/test.gd'
var params
func before_each():
params = Params.new()
func test_respects_ctor_args():
params = Params.new(12, 23)
assert_eq(params.params.size(), 12)
assert_eq(params.sub_params.size(), 23)
assert_eq(params.to_array(), [])
func test_add_param():
params.add_param(1)
assert_eq(params.length, 1)
assert_eq(params.params.slice(0, params.length - 1), [1])
assert_eq(params.to_array(), [1])
params.add_param(23)
assert_eq(params.length, 2)
assert_eq(params.params.slice(0, params.length - 1), [1, 23])
assert_eq(params.to_array(), [1, 23])
assert_eq(params.sub_params_length, 0)
func test_add_sub_param():
params.add_param(1)
params.add_sub_param(2)
params.add_sub_param(3)
assert_eq(params.length, 1)
assert_eq(params.sub_params_length, 2)
assert_eq(params.to_array(), [1, [2, 3]])
params.add_param(12345)
params.add_sub_param(-1)
assert_eq(params.length, 2)
assert_eq(params.sub_params_length, 3)
assert_eq(params.to_array(), [1, [2,3], 12345, [-1]])
func test_should_not_add_sub_params_without_previous_param():
params.add_sub_param(2)
params.add_sub_param(3)
assert_eq(params.length, 0)
assert_eq(params.sub_params_length, 0)
assert_eq(params.to_array(), [])
params.add_param(1)
params.add_sub_param(2)
params.add_sub_param(3)
assert_eq(params.length, 1)
assert_eq(params.sub_params_length, 2)
assert_eq(params.to_array(), [1, [2, 3]])
func test_reset():
params.add_param(1)
params.add_sub_param(2)
params.add_sub_param(3)
params.add_param(12345)
params.reset()
assert_eq(params.length, 0)
assert_eq(params.sub_params_length, 0)
assert_eq(params.to_array(), [])
params.add_param(1)
params.add_sub_param(2)
params.add_sub_param(3)
params.add_param(12345)
params.add_sub_param(-1)
assert_eq(params.length, 2)
assert_eq(params.sub_params_length, 3)
assert_eq(params.to_array(), [1, [2, 3], 12345, [-1]])
func test_from_array_to_array():
var data = []
assert_eq(params.from_array(data).to_array(), data)
data = [1, [2, 3], 12345, [-1]]
assert_eq(params.from_array(data).to_array(), data)
data = [38, 2, 50, 100, 150]
assert_eq(params.from_array(data).to_array(), data)
data = [38, 2, 50, 100, [150]]
assert_eq(params.from_array(data).to_array(), data)
data = [38, [2, 50, 100, 150]]
assert_eq(params.from_array(data).to_array(), data)
# strip empty sub params
data = [38, [2, 50, 100, 150], 5, [], 6]
assert_eq(Params.from_array(data).to_array(), [38, [2, 50, 100, 150], 5, 6])
# ignore leading sub params
data = [[1,2], 12345, [-1]]
assert_eq(Params.from_array(data).to_array(), [12345, [-1]])
class TestParse:
extends 'res://addons/gut/test.gd'
var params
func parse(params, s):
params.reset()
params.add_param(0)
if typeof(s) == TYPE_STRING:
s = [s]
for chunk in s:
var i = 0
while i < chunk.length():
# Start for
var code = chunk.to_ascii()[i]
var do = true
while do:
match code:
0x3b:
params.add_param(0)
0x3a:
params.add_sub_param(-1)
_:
params.add_digit(code - 48)
code = chunk.to_ascii()[i] if i < chunk.length() else 0
i+=1
do = i < s.size() and code > 0x2f and code < 0x3c
i-=1
# End for
i+=1
func before_each():
params = Params.new()
func test_param_defaults_to_0(): # ZDM (Zero Default Mode)
parse(params, '')
assert_eq(params.to_array(), [0])
func test_sub_param_defaults_to_neg_1():
parse(params, ':')
assert_eq(params.to_array(), [0, [-1]])
func test_reset_on_new_sequence():
parse(params, '1;2;3')
assert_eq(params.to_array(), [1, 2, 3])
parse(params, '4')
assert_eq(params.to_array(), [4])
parse(params, '4::123:5;6;7')
assert_eq(params.to_array(), [4, [-1, 123, 5], 6, 7])
parse(params, '')
assert_eq(params.to_array(), [0])
func test_should_handle_length_restrictions_correctly():
params = Params.new(3, 3)
parse(params, '1;2;3')
assert_eq(params.to_array(), [1, 2, 3])
parse(params, '4')
assert_eq(params.to_array(), [4])
parse(params, '4::123:5;6;7')
assert_eq(params.to_array(), [4, [-1, 123, 5], 6, 7])
parse(params, '')
assert_eq(params.to_array(), [0])
# overlong params
parse(params, '4;38:2::50:100:150;48:5:22')
assert_eq(params.to_array(), [4, 38, [2, -1, 50], 48])
# overlong sub params
parse(params, '4;38:2::50:100:150;48:5:22')
assert_eq(params.to_array(), [4, 38, [2, -1, 50], 48])
func test_typical_sequences():
# SGR with semicolon syntax
parse(params, '0;4;38;2;50;100;150;48;5;22')
assert_eq(params.to_array(), [0, 4, 38, 2, 50, 100, 150, 48, 5, 22])
# SGR mixed style (partly wrong)
parse(params, '0;4;38;2;50:100:150;48;5:22')
assert_eq(params.to_array(), [0, 4, 38, 2, 50, [100, 150], 48, 5, [22]])
# SGR colon style
parse(params, '0;4;38:2::50:100:150;48:5:22')
assert_eq(params.to_array(), [0, 4, 38, [2, -1, 50, 100, 150], 48, [5, 22]])
func test_clamp_parsed_params():
parse(params, '2147483648')
assert_eq(params.to_array(), [0x7FFFFFFF])
func test_clamp_parsed_sub_params():
parse(params, ':2147483648')
assert_eq(params.to_array(), [0, [0x7FFFFFFF]])
func test_should_cancel_subdigits_if_beyond_params_limit():
parse(params, ';;;;;;;;;10;;;;;;;;;;20;;;;;;;;;;30;31;32;33;34;35::::::::')
assert_eq(params.to_array(), [
0, 0, 0, 0, 0, 0, 0, 0, 0, 10,
0, 0, 0, 0, 0, 0, 0, 0, 0, 20,
0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 31, 32
])
# func test_should_carry_forward_is_sub_state():
# parse(params, ['1:22:33', '44'])
# assert_eq(params.to_array(), [1, [22, 3344]])

View file

@ -1,35 +0,0 @@
# Copyright 2020 The GodotXterm authors. All rights reserved.
# License MIT
extends "res://addons/gut/test.gd"
const CanvasRenderingContext2D = preload("res://addons/godot_xterm/renderer/canvas_rendering_context_2d.gd")
const RegularFont = preload("res://addons/godot_xterm/fonts/source_code_pro/source_code_pro_regular.tres")
const BoldFont = preload("res://addons/godot_xterm/fonts/source_code_pro/source_code_pro_bold.tres")
var ctx
func before_each():
ctx = CanvasRenderingContext2D.new()
func test_measure_text():
assert_eq(ctx.measure_text("a").width, RegularFont.get_string_size("a").x)
func test_save_and_restore():
# fill_style
ctx.fill_style = Color.red
ctx.save()
ctx.fill_style = Color.blue
assert_eq(ctx.fill_style, Color.blue)
ctx.restore()
assert_eq(ctx.fill_style, Color.red)
# font
ctx.font = RegularFont
ctx.save()
ctx.font = BoldFont
assert_eq(ctx.font, BoldFont)
ctx.restore()
assert_eq(ctx.font, RegularFont)

View file

@ -1,38 +0,0 @@
# Copyright (c) 2018 The xterm.js authors. All rights reserved.
# Ported to GDScript by the GodotXterm authors.
# License MIT
extends "res://addons/gut/test.gd"
const CharacterJoinerRegistry = preload("res://addons/godot_xterm/renderer/character_joiner_registry.gd")
const Buffer = preload("res://addons/godot_xterm/buffer/buffer.gd")
const BufferLine = preload("res://addons/godot_xterm/buffer/buffer_line.gd")
const CircularList = preload("res://addons/godot_xterm/circular_list.gd")
const CellData = preload("res://addons/godot_xterm/buffer/cell_data.gd")
const AttributeData = preload("res://addons/godot_xterm/buffer/attribute_data.gd")
const TestUtils = preload("res://test/test_utils.gd")
var registry
func line_data(data):
var tline = BufferLine.new(0)
for d in data:
var line = d[0]
var attr = d[1] if d.size() > 1 else 0
var offset = tline.length
tline.resize(tline.length + line.split('').size(), CellData.from_char_data([0, '', 0, 0]))
func before_each():
var buffer_service = TestUtils.MockBufferService.new(16, 10)
var lines = buffer_service.buffer.lines
lines.set_el(0, line_data([['a -> b -> c -> d']]))
lines.set_el(1, line_data([['a -> b => c -> d']]))
lines.set_el(2, line_data([['a -> b -', 0xFFFFFFFF], ['> c -> d', 0]]))
registry = CharacterJoinerRegistry.new(buffer_service)
func test_has_no_joiners_upon_creation():
assert_eq(registry.get_joined_characters(0), [])

View file

@ -1,201 +0,0 @@
# Copyright (c) 2016 The xterm.js authors. All rights reserved.
# Ported to GDScript by the GodotXterm authors.
# License MIT
extends "res://addons/gut/test.gd"
const CIRCULAR_LIST_PATH = "res://addons/godot_xterm/circular_list.gd"
const CircularList = preload(CIRCULAR_LIST_PATH)
var list
func before_each():
list = CircularList.new(5)
func test_push():
list.push("1")
list.push("2")
list.push("3")
list.push("4")
list.push("5")
assert_eq(list.get_line(0), "1")
assert_eq(list.get_line(1), "2")
assert_eq(list.get_line(2), "3")
assert_eq(list.get_line(3), "4")
assert_eq(list.get_line(4), "5")
func test_splice_deletes_items():
list = CircularList.new(2)
list.push("1")
list.push("2")
list.splice(0, 1)
assert_eq(list.length, 1)
assert_eq(list.get_el(0), "2")
list.push("3")
list.splice(1, 1)
assert_eq(list.length, 1)
assert_eq(list.get_el(0), "2")
func test_splice_inserts_items():
list = CircularList.new(2)
list.push("1")
list.splice(0, 0, ["2"])
assert_eq(list.length, 2)
assert_eq(list.get_el(0), "2")
assert_eq(list.get_el(1), "1")
list.splice(1, 0, ["3"])
assert_eq(list.length, 2)
assert_eq(list.get_el(0), "3")
assert_eq(list.get_el(1), "1")
func test_splice_deletes_items_then_inserts_items():
list = CircularList.new(3)
list.push("1")
list.push("2")
list.splice(0, 1, ["3", "4"])
assert_eq(list.length, 3)
assert_eq(list.get_el(0), "3")
assert_eq(list.get_el(1), "4")
assert_eq(list.get_el(2), "2")
func test_splice_wraps_the_array_correctly_when_more_items_are_inserted_than_deleted():
list = CircularList.new(3)
list.push("1")
list.push("2")
list.splice(1, 0, ["3", "4"])
assert_eq(list.length, 3)
assert_eq(list.get_el(0), "3")
assert_eq(list.get_el(1), "4")
assert_eq(list.get_el(2), "2")
class TestShiftElements:
extends "res://addons/gut/test.gd"
var list
func before_each():
list = CircularList.new(5)
func test_does_not_mutate_the_list_when_count_is_0():
list.push(1)
list.push(2)
list.shift_elements(0, 0, 1)
assert_eq(list.length, 2)
assert_eq(list.get_el(0), 1)
assert_eq(list.get_el(1), 2)
func test_pushes_errors_for_invalid_args():
list = partial_double(CIRCULAR_LIST_PATH).new()
list.max_length = 5
list.push(1)
list.shift_elements(-1, 1, 1)
assert_called(list, "push_error", ["start argument out of range"])
list.shift_elements(1, 1, 1)
assert_called(list, "push_error", ["start argument out of range"])
list.shift_elements(0, 1, -1)
assert_called(list, "push_error", ["cannot shift elements in list beyond index 0"])
func test_trim_start_removes_items_from_the_beginning_of_the_list():
list.push("1")
list.push("2")
list.push("3")
list.push("4")
list.push("5")
list.trim_start(1)
assert_eq(list.length, 4)
assert_eq(list.get_el(0), "2")
assert_eq(list.get_el(1), "3")
assert_eq(list.get_el(2), "4")
assert_eq(list.get_el(3), "5")
list.trim_start(2)
assert_eq(list.length, 2)
assert_eq(list.get_el(0), "4")
assert_eq(list.get_el(1), "5")
func test_trim_start_removes_all_items_if_the_requested_trim_amount_is_larger_than_the_lists_length():
list.push("1")
list.trim_start(2)
assert_eq(list.length, 0)
func test_shifts_an_element_forward():
list.push(1)
list.push(2)
list.shift_elements(0, 1, 1)
assert_eq(list.length, 2)
assert_eq(list.get_el(0), 1)
assert_eq(list.get_el(1), 1)
func test_shifts_elements_forward():
list.push(1)
list.push(2)
list.push(3)
list.push(4)
list.shift_elements(0, 2, 2)
assert_eq(list.length, 4)
assert_eq(list.get_el(0), 1)
assert_eq(list.get_el(1), 2)
assert_eq(list.get_el(2), 1)
assert_eq(list.get_el(3), 2)
func test_shifts_elements_forward_expanding_the_list_if_needed():
list.push(1)
list.push(2)
list.shift_elements(0, 2, 2)
assert_eq(list.length, 4)
assert_eq(list.get_el(0), 1)
assert_eq(list.get_el(1), 2)
assert_eq(list.get_el(2), 1)
assert_eq(list.get_el(3), 2)
func test_shifts_elements_forward_wrapping_the_list_if_needed():
list.push(1)
list.push(2)
list.push(3)
list.push(4)
list.push(5)
list.shift_elements(2, 2, 3)
assert_eq(list.length, 5)
assert_eq(list.get_el(0), 3)
assert_eq(list.get_el(1), 4)
assert_eq(list.get_el(2), 5)
assert_eq(list.get_el(3), 3)
assert_eq(list.get_el(4), 4)
func test_shifts_an_element_backwards():
list.push(1)
list.push(2)
list.shift_elements(1, 1, -1)
assert_eq(list.length, 2)
assert_eq(list.get_el(0), 2)
assert_eq(list.get_el(1), 2)
func test_shiftS_elements_backwards():
list.push(1)
list.push(2)
list.push(3)
list.push(4)
list.shift_elements(2, 2, -2)
assert_eq(list.length, 4)
assert_eq(list.get_el(0), 3)
assert_eq(list.get_el(1), 4)
assert_eq(list.get_el(2), 3)
assert_eq(list.get_el(3), 4)

View file

@ -1,288 +0,0 @@
# Copyright (c) 2017 The xterm.js authors. All rights reserved.
# Ported to GDScript by the GodotXterm authors.
# License MIT
extends "res://addons/gut/test.gd"
const TestUtils = preload("res://test/test_utils.gd")
const InputHandler = preload("res://addons/godot_xterm/input_handler.gd")
const CharsetService = preload("res://addons/godot_xterm/services/charset_service.gd")
const Params = preload("res://addons/godot_xterm/parser/params.gd")
const CoreService = preload("res://addons/godot_xterm/services/core_service.gd")
const Constants = preload("res://addons/godot_xterm/buffer/constants.gd")
const OptionsService = preload("res://addons/godot_xterm/services/options_service.gd")
const CursorStyle = Constants.CursorStyle
var options_service
var buffer_service
var charset_service
var core_service
var input_handler
func get_lines(buffer_service, limit: int) -> Array:
var res = []
if not limit:
limit = buffer_service.rows
for i in range(limit):
var line = buffer_service.buffer.lines.get_el(i)
if line:
res.append(line.translate_to_string(true))
return res
func repeat(string: String, times: int) -> String:
var s = ""
for i in range(times):
s += string
return s
func term_content(buffer_service, trim: bool) -> PoolStringArray:
var result = PoolStringArray([])
for i in buffer_service.rows:
result.append(buffer_service.buffer.lines.get_el(i).translate_to_string(trim))
return result;
func before_each():
options_service = TestUtils.MockOptionsService.new()
buffer_service = TestUtils.MockBufferService.new(80, 30, options_service)
charset_service = CharsetService.new()
core_service = CoreService.new()
input_handler = InputHandler.new(buffer_service, core_service, charset_service, options_service)
func test_save_and_restore_cursor():
buffer_service.buffer.x = 1
buffer_service.buffer.y = 2
buffer_service.buffer.ybase = 0
input_handler._cur_attr_data.fg = 3
# Save cursor position
input_handler.save_cursor()
assert_eq(buffer_service.buffer.x, 1)
assert_eq(buffer_service.buffer.y, 2)
assert_eq(input_handler._cur_attr_data.fg, 3)
# Change the cursor position
buffer_service.buffer.x = 10
buffer_service.buffer.y = 20
input_handler._cur_attr_data.fg = 30
# Restore cursor position
input_handler.restore_cursor()
assert_eq(buffer_service.buffer.x, 1)
assert_eq(buffer_service.buffer.y, 2)
assert_eq(input_handler._cur_attr_data.fg, 3)
func test_set_cursor_style():
input_handler.set_cursor_style(Params.from_array([0]))
assert_eq(options_service.options.cursor_style, CursorStyle.BLOCK)
assert_eq(options_service.options.cursor_blink, true)
options_service.options = OptionsService.TerminalOptions.new()
input_handler.set_cursor_style(Params.from_array([1]))
assert_eq(options_service.options.cursor_style, CursorStyle.BLOCK)
assert_eq(options_service.options.cursor_blink, true)
options_service.options = OptionsService.TerminalOptions.new()
input_handler.set_cursor_style(Params.from_array([2]))
assert_eq(options_service.options.cursor_style, CursorStyle.BLOCK)
assert_eq(options_service.options.cursor_blink, false)
options_service.options = OptionsService.TerminalOptions.new()
input_handler.set_cursor_style(Params.from_array([3]))
assert_eq(options_service.options.cursor_style, CursorStyle.UNDERLINE)
assert_eq(options_service.options.cursor_blink, true)
options_service.options = OptionsService.TerminalOptions.new()
input_handler.set_cursor_style(Params.from_array([4]))
assert_eq(options_service.options.cursor_style, CursorStyle.UNDERLINE)
assert_eq(options_service.options.cursor_blink, false)
options_service.options = OptionsService.TerminalOptions.new()
input_handler.set_cursor_style(Params.from_array([5]))
assert_eq(options_service.options.cursor_style, CursorStyle.BAR)
assert_eq(options_service.options.cursor_blink, true)
options_service.options = OptionsService.TerminalOptions.new()
input_handler.set_cursor_style(Params.from_array([6]))
assert_eq(options_service.options.cursor_style, CursorStyle.BAR)
assert_eq(options_service.options.cursor_blink, false)
func test_set_mode_toggles_bracketed_paste_mode():
# Set bracketed paste mode
input_handler.set_mode_private(Params.from_array([2004]))
assert_true(core_service.dec_private_modes.bracketed_paste_mode)
# Reset bracketed paste mode
input_handler.reset_mode_private(Params.from_array([2004]))
assert_false(core_service.dec_private_modes.bracketed_paste_mode)
func test_erase_in_line():
buffer_service = TestUtils.MockBufferService.new(80, 30, options_service)
input_handler = InputHandler.new(buffer_service, core_service, charset_service, options_service)
# fill 6 lines to test 3 different states
input_handler.parse(repeat("a", buffer_service.cols))
input_handler.parse(repeat("a", buffer_service.cols))
input_handler.parse(repeat("a", buffer_service.cols))
# params[0] - right erase
buffer_service.buffer.y = 0
buffer_service.buffer.x = 70
input_handler.erase_in_line(Params.from_array([0]))
assert_eq(buffer_service.buffer.lines.get_line(0).translate_to_string(false),
repeat("a", 70) + " ")
# params[1] - left erase
buffer_service.buffer.y = 1
buffer_service.buffer.x = 70
input_handler.erase_in_line(Params.from_array([1]))
assert_eq(buffer_service.buffer.lines.get_line(1).translate_to_string(false),
repeat(" ", 70) + " aaaaaaaaa")
# params[1] - left erase
buffer_service.buffer.y = 2
buffer_service.buffer.x = 70
input_handler.erase_in_line(Params.from_array([2]))
assert_eq(buffer_service.buffer.lines.get_line(2).translate_to_string(false),
repeat(" ", buffer_service.cols))
func test_erase_in_display():
buffer_service = TestUtils.MockBufferService.new(80, 7, options_service)
input_handler = InputHandler.new(buffer_service, core_service, charset_service, options_service)
# fill display with a's
for _i in range(buffer_service.rows):
input_handler.parse(repeat("a", buffer_service.cols))
# params [0] - right and below erase
buffer_service.buffer.y = 5
buffer_service.buffer.x = 40
input_handler.erase_in_display(Params.from_array([0]))
assert_eq(term_content(buffer_service, false), PoolStringArray([
repeat("a", buffer_service.cols),
repeat("a", buffer_service.cols),
repeat("a", buffer_service.cols),
repeat("a", buffer_service.cols),
repeat("a", buffer_service.cols),
repeat("a", 40) + repeat(" ", buffer_service.cols - 40),
repeat(" ", buffer_service.cols),
]))
assert_eq(term_content(buffer_service, true), PoolStringArray([
repeat("a", buffer_service.cols),
repeat("a", buffer_service.cols),
repeat("a", buffer_service.cols),
repeat("a", buffer_service.cols),
repeat("a", buffer_service.cols),
repeat("a", 40),
""
]))
# reset
for _i in range(buffer_service.rows):
input_handler.parse(repeat("a", buffer_service.cols))
# params [1] - left and above
buffer_service.buffer.y = 5;
buffer_service.buffer.x = 40;
input_handler.erase_in_display(Params.from_array([1]))
assert_eq(term_content(buffer_service, false), PoolStringArray([
repeat(" ", buffer_service.cols),
repeat(" ", buffer_service.cols),
repeat(" ", buffer_service.cols),
repeat(" ", buffer_service.cols),
repeat(" ", buffer_service.cols),
repeat(" ", 41) + repeat("a", buffer_service.cols - 41),
repeat("a", buffer_service.cols),
]))
assert_eq(term_content(buffer_service, true), PoolStringArray([
"",
"",
"",
"",
"",
repeat(" ", 41) + repeat("a", buffer_service.cols - 41),
repeat("a", buffer_service.cols),
]))
# reset
for _i in range(buffer_service.rows):
input_handler.parse(repeat("a", buffer_service.cols))
# params [2] - whole screen
buffer_service.buffer.y = 5;
buffer_service.buffer.x = 40;
input_handler.erase_in_display(Params.from_array([2]));
assert_eq(term_content(buffer_service, false), PoolStringArray([
repeat(" ", buffer_service.cols),
repeat(" ", buffer_service.cols),
repeat(" ", buffer_service.cols),
repeat(" ", buffer_service.cols),
repeat(" ", buffer_service.cols),
repeat(" ", buffer_service.cols),
repeat(" ", buffer_service.cols),
]))
assert_eq(term_content(buffer_service, true), PoolStringArray([
"",
"",
"",
"",
"",
"",
"",
]))
# reset and add a wrapped line
buffer_service.buffer.y = 0;
buffer_service.buffer.x = 0;
input_handler.parse(repeat("a", buffer_service.cols)) # line 0
input_handler.parse(repeat("a", buffer_service.cols + 9)) # line 1 and 2
for i in range(3, buffer_service.rows):
input_handler.parse(repeat("a", buffer_service.cols))
# params[1] left and above with wrap
# confirm precondition that line 2 is wrapped
assert_true(buffer_service.buffer.lines.get_line(2).is_wrapped)
buffer_service.buffer.y = 2
buffer_service.buffer.x = 40
input_handler.erase_in_display(Params.from_array([1]))
assert_false(buffer_service.buffer.lines.get_line(2).is_wrapped)
# reset and add a wrapped line
buffer_service.buffer.y = 0
buffer_service.buffer.x = 0
input_handler.parse(repeat("a", buffer_service.cols)) # line 0
input_handler.parse(repeat("a", buffer_service.cols + 9)) # line 1 and 2
for i in range(3, buffer_service.rows):
input_handler.parse(repeat("a", buffer_service.cols))
# params[1] left and above with wrap
# confirm precondition that line 2 is wrapped
assert_true(buffer_service.buffer.lines.get_line(2).is_wrapped)
buffer_service.buffer.y = 1
buffer_service.buffer.x = 90 # Cursor is beyond last column
input_handler.erase_in_display(Params.from_array([1]));
assert_false(buffer_service.buffer.lines.get_line(2).is_wrapped)
func test_print_does_not_cause_an_infinite_loop():
var container = []
container.resize(10)
container[0] = 0x200B
input_handler.print(container, 0, 1)
# FIXME
func skip_test_clear_cells_to_the_right_on_early_wrap_around():
buffer_service.resize(5, 5)
options_service.options.scrollback = 1
input_handler.parse('12345')
buffer_service.buffer.x = 0
input_handler.parse("¥¥¥")
assert_eq(get_lines(buffer_service, 2), PoolStringArray(["¥¥", ""]))

View file

@ -1,222 +0,0 @@
# Copyright (c) 2019 The xterm.js authors. All rights reserved.
# Ported to GDScript by the GodotXterm authors.
# License MIT
extends 'res://addons/gut/test.gd'
const Params = preload("res://addons/godot_xterm/parser/params.gd")
class TestParams:
extends 'res://addons/gut/test.gd'
var params
func before_each():
params = Params.new()
func test_respects_ctor_args():
params = Params.new(12, 23)
assert_eq(params.params.size(), 12)
assert_eq(params.sub_params.size(), 23)
assert_eq(params.to_array(), [])
func test_add_param():
params.add_param(1)
assert_eq(params.length, 1)
assert_eq(params.params.slice(0, params.length - 1), [1])
assert_eq(params.to_array(), [1])
params.add_param(23)
assert_eq(params.length, 2)
assert_eq(params.params.slice(0, params.length - 1), [1, 23])
assert_eq(params.to_array(), [1, 23])
assert_eq(params.sub_params_length, 0)
func test_add_sub_param():
params.add_param(1)
params.add_sub_param(2)
params.add_sub_param(3)
assert_eq(params.length, 1)
assert_eq(params.sub_params_length, 2)
assert_eq(params.to_array(), [1, [2, 3]])
params.add_param(12345)
params.add_sub_param(-1)
assert_eq(params.length, 2)
assert_eq(params.sub_params_length, 3)
assert_eq(params.to_array(), [1, [2,3], 12345, [-1]])
func test_should_not_add_sub_params_without_previous_param():
params.add_sub_param(2)
params.add_sub_param(3)
assert_eq(params.length, 0)
assert_eq(params.sub_params_length, 0)
assert_eq(params.to_array(), [])
params.add_param(1)
params.add_sub_param(2)
params.add_sub_param(3)
assert_eq(params.length, 1)
assert_eq(params.sub_params_length, 2)
assert_eq(params.to_array(), [1, [2, 3]])
func test_reset():
params.add_param(1)
params.add_sub_param(2)
params.add_sub_param(3)
params.add_param(12345)
params.reset()
assert_eq(params.length, 0)
assert_eq(params.sub_params_length, 0)
assert_eq(params.to_array(), [])
params.add_param(1)
params.add_sub_param(2)
params.add_sub_param(3)
params.add_param(12345)
params.add_sub_param(-1)
assert_eq(params.length, 2)
assert_eq(params.sub_params_length, 3)
assert_eq(params.to_array(), [1, [2, 3], 12345, [-1]])
func test_from_array_to_array():
var data = []
assert_eq(params.from_array(data).to_array(), data)
data = [1, [2, 3], 12345, [-1]]
assert_eq(params.from_array(data).to_array(), data)
data = [38, 2, 50, 100, 150]
assert_eq(params.from_array(data).to_array(), data)
data = [38, 2, 50, 100, [150]]
assert_eq(params.from_array(data).to_array(), data)
data = [38, [2, 50, 100, 150]]
assert_eq(params.from_array(data).to_array(), data)
# strip empty sub params
data = [38, [2, 50, 100, 150], 5, [], 6]
assert_eq(Params.from_array(data).to_array(), [38, [2, 50, 100, 150], 5, 6])
# ignore leading sub params
data = [[1,2], 12345, [-1]]
assert_eq(Params.from_array(data).to_array(), [12345, [-1]])
func test_has_sub_params_get_sub_params():
params = Params.from_array([38, [2, 50, 100, 150], 5, [], 6])
assert_eq(params.has_sub_params(0), true)
assert_eq(params.get_sub_params(0), [2, 50, 100, 150])
assert_eq(params.has_sub_params(1), false)
assert_eq(params.get_sub_params(1), null)
assert_eq(params.has_sub_params(2), false)
assert_eq(params.get_sub_params(2), null)
class TestParse:
extends 'res://addons/gut/test.gd'
var params
func parse(params, s):
params.reset()
params.add_param(0)
if typeof(s) == TYPE_STRING:
s = [s]
for chunk in s:
var i = 0
while i < chunk.length():
# Start for
var code = chunk.to_ascii()[i]
var do = true
while do:
match code:
0x3b:
params.add_param(0)
0x3a:
params.add_sub_param(-1)
_:
params.add_digit(code - 48)
code = chunk.to_ascii()[i] if i < chunk.length() else 0
i+=1
do = i < s.size() and code > 0x2f and code < 0x3c
i-=1
# End for
i+=1
func before_each():
params = Params.new()
func test_param_defaults_to_0(): # ZDM (Zero Default Mode)
parse(params, '')
assert_eq(params.to_array(), [0])
func test_sub_param_defaults_to_neg_1():
parse(params, ':')
assert_eq(params.to_array(), [0, [-1]])
func test_reset_on_new_sequence():
parse(params, '1;2;3')
assert_eq(params.to_array(), [1, 2, 3])
parse(params, '4')
assert_eq(params.to_array(), [4])
parse(params, '4::123:5;6;7')
assert_eq(params.to_array(), [4, [-1, 123, 5], 6, 7])
parse(params, '')
assert_eq(params.to_array(), [0])
func test_should_handle_length_restrictions_correctly():
params = Params.new(3, 3)
parse(params, '1;2;3')
assert_eq(params.to_array(), [1, 2, 3])
parse(params, '4')
assert_eq(params.to_array(), [4])
parse(params, '4::123:5;6;7')
assert_eq(params.to_array(), [4, [-1, 123, 5], 6, 7])
parse(params, '')
assert_eq(params.to_array(), [0])
# overlong params
parse(params, '4;38:2::50:100:150;48:5:22')
assert_eq(params.to_array(), [4, 38, [2, -1, 50], 48])
# overlong sub params
parse(params, '4;38:2::50:100:150;48:5:22')
assert_eq(params.to_array(), [4, 38, [2, -1, 50], 48])
func test_typical_sequences():
# SGR with semicolon syntax
parse(params, '0;4;38;2;50;100;150;48;5;22')
assert_eq(params.to_array(), [0, 4, 38, 2, 50, 100, 150, 48, 5, 22])
# SGR mixed style (partly wrong)
parse(params, '0;4;38;2;50:100:150;48;5:22')
assert_eq(params.to_array(), [0, 4, 38, 2, 50, [100, 150], 48, 5, [22]])
# SGR colon style
parse(params, '0;4;38:2::50:100:150;48:5:22')
assert_eq(params.to_array(), [0, 4, 38, [2, -1, 50, 100, 150], 48, [5, 22]])
func test_clamp_parsed_params():
parse(params, '2147483648')
assert_eq(params.to_array(), [0x7FFFFFFF])
func test_clamp_parsed_sub_params():
parse(params, ':2147483648')
assert_eq(params.to_array(), [0, [0x7FFFFFFF]])
func test_should_cancel_subdigits_if_beyond_params_limit():
parse(params, ';;;;;;;;;10;;;;;;;;;;20;;;;;;;;;;30;31;32;33;34;35::::::::')
assert_eq(params.to_array(), [
0, 0, 0, 0, 0, 0, 0, 0, 0, 10,
0, 0, 0, 0, 0, 0, 0, 0, 0, 20,
0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 31, 32
])