# Check that the XML output is correct.
# Also checks that tabs aren't tampered with.
use strict;
use warnings;
use Test::More;
use Text::VimColor;
use IO::File;
my $NS = 'http://ns.laxan.com/text-vimcolor/1';
my %SYNTYPES = map { $_ => 1 } qw(
Comment Constant Identifier Statement Preproc
Type Special Underlined Error Todo
);
my @EXPECTED_PERL_SYN = qw(
Comment
Statement Identifier
Statement Constant Statement
Statement Constant Identifier Constant
Constant Special Constant
);
my @EXPECTED_NOFT_SYN = qw(
Comment
Constant
Constant
);
eval " use XML::Parser ";
if ($@) {
plan skip_all => 'XML::Parser module required for these tests.';
exit 0;
}
else {
plan tests => 12;
}
# Syntax color a Perl program, and check the XML output for well-formedness
# and validity. The tests are run with and without a root element in the
# output, and with both filename and string as input.
my $filename = 't/has_tabs.pl';
my $file = IO::File->new($filename, 'r')
or die "error opening file '$filename': $!";
my $data = do { local $/; <$file> };
my $syntax = Text::VimColor->new(
file => $filename,
);
my $syntax_noroot = Text::VimColor->new(
file => $filename, xml_root_element => 0,
);
my $syntax_str = Text::VimColor->new(
string => $data,
);
my $syntax_str_noroot = Text::VimColor->new(
string => $data, xml_root_element => 0,
);
my %syntax = (
'no root element, filename input' => $syntax_noroot,
'no root element, string input' => $syntax_str_noroot,
'root element, filename input' => $syntax,
'root element, string input' => $syntax_str,
);
# These are filled in by the handler subs below.
my $text;
my $root_elem_count;
my $inside_element;
my @syntax_types;
my $parser = XML::Parser->new(
Handlers => {
Start => \&handle_start,
End => \&handle_end,
Char => \&handle_text,
Default => \&handle_default,
},
);
foreach my $test_type (sort keys %syntax) {
#diag("Doing XML tests for configuration '$test_type'.");
my $syn = $syntax{$test_type};
my $xml = $syn->xml;
# The ones without root elements need to be faked.
if ($test_type =~ /no root/) {
$xml = "$xml";
}
# Reset globals.
$text = '';
$root_elem_count = 0;
$inside_element = 0;
@syntax_types = ();
$parser->parse($xml);
is($text, $data,
"check that text from XML output matches original");
is($root_elem_count, 1,
"there should only be one root element");
if ($test_type =~ /string/) {
# Only expected to find string literals and comments.
is_deeply(\@EXPECTED_NOFT_SYN, \@syntax_types,
"check that the syntax types marked come in the right order");
}
else {
is_deeply(\@EXPECTED_PERL_SYN, \@syntax_types,
"check that the syntax types marked come in the right order");
}
}
sub handle_text
{
my ($expat, $s) = @_;
$text .= $s;
}
sub handle_start
{
my ($expat, $element, %attr) = @_;
$element =~ /^syn:(.*)\z/
or fail("element <$element> has wrong prefix"), return;
$element = $1;
fail("element shouldn't be nested in something")
if $inside_element;
if ($element eq 'syntax') {
++$root_elem_count;
fail("namespace declaration missing from root element")
unless $attr{'xmlns:syn'};
fail("wrong namespace declaration in root element")
unless $attr{'xmlns:syn'} eq $NS;
}
else {
$inside_element = 1;
fail("bad element ")
if !$SYNTYPES{$element};
fail("element shouldn't have any attributes")
if keys %attr;
push @syntax_types, $element;
}
}
sub handle_end
{
my ($expat, $element) = @_;
$element =~ /^syn:(.*)\z/
or fail("element <$element> has wrong prefix"), return;
$element = $1;
$inside_element = 0;
if ($element ne 'syntax' && !$SYNTYPES{$element}) {
fail("bad element ");
return;
}
}
sub handle_default
{
my ($expat, $s) = @_;
return unless $s =~ /\S/;
die "unexpected XML event for text '$s'\n";
}
# vim:ft=perl ts=3 sw=3 expandtab: