diff options
Diffstat (limited to 'scripts')
-rwxr-xr-x | scripts/legacy2luatest.pl | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/scripts/legacy2luatest.pl b/scripts/legacy2luatest.pl new file mode 100755 index 0000000000..0628ac0a1d --- /dev/null +++ b/scripts/legacy2luatest.pl @@ -0,0 +1,262 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use 5.010; +use autodie; + +use File::Basename; +use File::Spec::Functions; + +sub read_in_file { + my $in_file = $_[0]; + + # Will contain lines before first STARTTEST + # as Lua comments. + my @description_lines = (); + + # Will contain alternating blocks of lines of textual input + # (text between ENDTEST and EOF/next STARTTEST) and test commands + # (commands between STARTTEST and ENDTEST) as Lua code. + my @test_body_lines = (); + + # Will contain current command block, i.e. lines + # between STARTTEST and ENDTEST. + my @command_lines = (); + + # Will contain current input block, i.e. lines + # between ENDTEST and STARTTEST. + my @input_lines = (); + + open my $in_file_handle, '<', $in_file; + + use constant EMIT_DESCRIPTION => 0; + use constant EMIT_COMMAND => 1; + use constant EMIT_INPUT => 2; + use constant END_INPUT => 3; + + my %states = ( + # Add test description to @description_lines. + EMIT_DESCRIPTION() => sub { + if (/^STARTTEST/) { + return EMIT_COMMAND; + } + + # If not an empty line, emit as Lua comment. + if (!/^$/) { + push @description_lines, '-- ' . $_; + } + + return EMIT_DESCRIPTION; + }, + # Add test commands to @command_lines. + EMIT_COMMAND() => sub { + if (/^ENDTEST/) { + return EMIT_INPUT; + } + + # If line starts with ':"', emit a comment. + if (/^:"/) { + # If it's an empty comment, just add an empty line + # to improve readability. + push @command_lines, (/^$/ ? '' : '-- ' . $_); + } else { + # Extract possible inline comment. + if (/^[^"]*"[^"]*$/) { + # Remove command part and prepended whitespace. + s/^(.*?)\s*"\s*//; + + # Capitalize first character and emit as Lua comment. + my $comment = '-- ' . ucfirst $_; + + # Add trailing dot if not already there. + $comment .= '.' unless $comment =~ /\.$/; + + push @command_lines, ''; + push @command_lines, $comment; + + # Set implicit variable to command without comment. + $_ = $1; + } + + # Only continue if remaining command is not empty. + if (!/^:?\s*$/) { + # Replace terminal escape characters with <esc>. + s/\e/<esc>/g; + + my $startstr = "'"; + my $endstr = "'"; + + # If line contains single quotes or backslashes, use double + # square brackets to wrap string. + if (/'/ || /\\/) { + $startstr = '[['; + $endstr = ']]'; + } + + # Emit 'feed' if not a search ('/') or ex (':') command. + if (!/^\// && !/^:/) { + # If command does not end with <esc>, insert trailing <cr>. + my $command = 'feed(' . $startstr . $_; + $command .= '<cr>' unless /<esc>$/; + $command .= $endstr . ')'; + + push @command_lines, $command; + } else { + # Remove prepending ':'. + s/^://; + push @command_lines, 'execute(' . $startstr . $_ . $endstr . ')'; + } + } + } + + return EMIT_COMMAND; + }, + # Add input to @input_lines. + EMIT_INPUT() => sub { + if (/^STARTTEST/) { + return END_INPUT; + } + + push @input_lines, ' ' . $_; + return EMIT_INPUT; + }, + # The END_INPUT state is used to push lines from current + # input and command blocks into @test_body_lines + # in the correct order. + END_INPUT() => sub { + # Only keep first input line if it is not empty. + my $first_input_line = shift @input_lines; + if ($first_input_line =~ /^$/) { + unshift @input_lines, $first_input_line; + } + + # If there are input lines left, wrap them with + # `insert` command and add before the previous command + # block. + if (@input_lines) { + my $last_input_line = pop @input_lines; + unshift @command_lines, ''; + unshift @command_lines, $last_input_line . ']])'; + unshift @command_lines, @input_lines; + unshift @command_lines, "insert([["; + + push @test_body_lines, @command_lines; + + @command_lines = (); + @input_lines = (); + } + + return EMIT_COMMAND; + } + ); + + my $state = EMIT_DESCRIPTION; + + while (<$in_file_handle>) { + # Remove trailing newline character and process line. + chomp; + $state = $states{$state}->($_); + } + + # If not all input lines have been processed, + # do it now. + if (@input_lines) { + $states{END_INPUT()}->(); + } + + close $in_file_handle; + + return (\@description_lines, \@test_body_lines); +} + +sub read_ok_file { + my $ok_file = $_[0]; + my @assertions = (); + + if (-f $ok_file) { + push @assertions, ''; + push @assertions, "-- Assert buffer contents."; + push @assertions, "expect([["; + + open my $ok_file_handle, '<', $ok_file; + + while (<$ok_file_handle>) { + # Remove trailing newline character and process line. + chomp; + push @assertions, ' ' . $_; + } + + close $ok_file_handle; + + $assertions[-1] .= "]])"; + } + + return \@assertions; +} + +my $legacy_testfile = $ARGV[0]; +my $out_dir = $ARGV[1]; + +if ($#ARGV != 1) { + say "Convert a legacy Vim test to a Neovim lua spec."; + say ''; + say "Usage: $0 legacy-testfile output-directory"; + say ''; + say "legacy-testfile: Path to .in or .ok file."; + say "output-directory: Directory where Lua spec will be saved to."; + say ''; + say "Note: Only works reliably for fairly simple tests."; + say " Manual adjustments to generated spec files are required."; + exit 1; +} + +my @legacy_suffixes = ('.in', '.ok'); +my ($test_name, $base_path, $suffix) = fileparse($legacy_testfile, @legacy_suffixes); +my $in_file = catfile($base_path, $test_name . '.in'); +my $ok_file = catfile($base_path, $test_name . '.ok'); + +my $spec_file = catfile($out_dir, $test_name . '_spec.lua'); + +if (! -f $in_file) { + say "Test input file $in_file not found."; + exit 2; +} + +if (! -d $out_dir) { + say "Output directory $out_dir does not exist."; + exit 3; +} + +if (-f $spec_file) { + say "Output file $spec_file already exists."; + exit 4; +} + +# Read .in and .ok files. +my ($description_lines, $test_body_lines) = read_in_file $in_file; +my $assertion_lines = read_ok_file $ok_file; + +# Append assertions to test body. +push @{$test_body_lines}, @{$assertion_lines} if @{$assertion_lines}; + +# Write spec file. +open my $spec_file_handle, ">", $spec_file; + +print $spec_file_handle <<"EOS"; +@{[join "\n", @{$description_lines}]} + +local helpers = require('test.functional.helpers') +local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert +local execute, expect = helpers.execute, helpers.expect + +describe('$test_name', function() + setup(clear) + + it('is working', function() +@{[join "\n", map { /^$/ ? '' : ' ' . $_ } @{$test_body_lines}]} + end) +end) +EOS + +close $spec_file_handle; |