mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	Add legacy test conversion script.
This commit is contained in:
		 Florian Walch
					Florian Walch
				
			
				
					committed by
					
						 Thiago de Arruda
						Thiago de Arruda
					
				
			
			
				
	
			
			
			 Thiago de Arruda
						Thiago de Arruda
					
				
			
						parent
						
							5f99be1efe
						
					
				
				
					commit
					bc6ac59928
				
			
							
								
								
									
										262
									
								
								scripts/legacy2luatest.pl
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										262
									
								
								scripts/legacy2luatest.pl
									
									
									
									
									
										Executable file
									
								
							| @@ -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; | ||||
		Reference in New Issue
	
	Block a user