Blame t/07-zonefile.t

Packit e6c8bb
# $Id: 07-zonefile.t 1601 2017-10-10 14:17:01Z willem $	-*-perl-*-
Packit e6c8bb
Packit e6c8bb
use strict;
Packit e6c8bb
use IO::File;
Packit e6c8bb
Packit e6c8bb
use Test::More tests => 91;
Packit e6c8bb
Packit e6c8bb
					## vvv	verbatim from Domain.pm
Packit e6c8bb
use constant ASCII => ref eval {
Packit e6c8bb
	require Encode;
Packit e6c8bb
	Encode::find_encoding('ascii');
Packit e6c8bb
};
Packit e6c8bb
Packit e6c8bb
use constant UTF8 => scalar eval {	## not UTF-EBCDIC  [see UTR#16 3.6]
Packit e6c8bb
	Encode::encode_utf8( chr(182) ) eq pack( 'H*', 'C2B6' );
Packit e6c8bb
};
Packit e6c8bb
Packit e6c8bb
use constant LIBIDN  => defined eval 'require Net::LibIDN';
Packit e6c8bb
use constant LIBIDN2 => ref eval 'require Net::LibIDN2; Net::LibIDN2->can("idn2_to_ascii_8")';
Packit e6c8bb
					## ^^^	verbatim from Domain.pm
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
use constant LIBIDNOK => LIBIDN && scalar eval {
Packit e6c8bb
	my $cn = pack( 'U*', 20013, 22269 );
Packit e6c8bb
	Net::LibIDN::idn_to_ascii( $cn, 'utf-8' ) eq 'xn--fiqs8s';
Packit e6c8bb
};
Packit e6c8bb
Packit e6c8bb
use constant LIBIDN2OK => LIBIDN2 && scalar eval {
Packit e6c8bb
	my $cn = pack( 'U*', 20013, 22269 );
Packit e6c8bb
	Net::LibIDN2::idn2_to_ascii_8( $cn, 9 ) eq 'xn--fiqs8s';
Packit e6c8bb
};
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
use_ok('Net::DNS::ZoneFile');
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
my @file;
Packit e6c8bb
my $seq;
Packit e6c8bb
Packit e6c8bb
END {
Packit e6c8bb
	unlink $_ foreach @file;
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
sub source {				## zone file builder
Packit e6c8bb
	my $text = shift;
Packit e6c8bb
	my @args = @_;
Packit e6c8bb
Packit e6c8bb
	my $tag	 = ++$seq;
Packit e6c8bb
	my $file = "zone$tag.txt";
Packit e6c8bb
Packit e6c8bb
	my $handle = new IO::File( $file, '>' );		# create test file
Packit e6c8bb
	die "Failed to create $file" unless $handle;
Packit e6c8bb
	eval { binmode($handle) };				# suppress encoding layer
Packit e6c8bb
	push @file, $file;
Packit e6c8bb
Packit e6c8bb
	print $handle $text;
Packit e6c8bb
	close $handle;
Packit e6c8bb
Packit e6c8bb
	return new Net::DNS::ZoneFile( $file, @args );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
my $recursive = join ' ', '$INCLUDE', source('$INCLUDE zone1.txt')->name;
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{
Packit e6c8bb
	eval { new Net::DNS::ZoneFile(undef); };
Packit e6c8bb
	my $exception = $1 if $@ =~ /^(.+)\n/;
Packit e6c8bb
	ok( $exception ||= '', "new(): invalid argument\t[$exception]" );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{
Packit e6c8bb
	eval { new Net::DNS::ZoneFile( [] ); };
Packit e6c8bb
	my $exception = $1 if $@ =~ /^(.+)\n/;
Packit e6c8bb
	ok( $exception ||= '', "new(): not a file handle\t[$exception]" );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{
Packit e6c8bb
	eval { new Net::DNS::ZoneFile('zone0.txt'); };		# presumed not to exist
Packit e6c8bb
	my $exception = $1 if $@ =~ /^(.+)\n/;
Packit e6c8bb
	ok( $exception ||= '', "new(): non-existent file\t[$exception]" );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{					## public methods
Packit e6c8bb
	my $zonefile = source('');
Packit e6c8bb
	ok( $zonefile->isa('Net::DNS::ZoneFile'), 'new ZoneFile object' );
Packit e6c8bb
Packit e6c8bb
	ok( defined $zonefile->name,   'zonefile->name always defined' );
Packit e6c8bb
	ok( defined $zonefile->line,   'zonefile->line always defined' );
Packit e6c8bb
	ok( defined $zonefile->origin, 'zonefile->origin always defined' );
Packit e6c8bb
	ok( !defined $zonefile->ttl,   'zonefile->ttl initially undefined' );
Packit e6c8bb
	my @rr = $zonefile->read;
Packit e6c8bb
	is( scalar(@rr),     0, 'zonefile->read to end of file' );
Packit e6c8bb
	is( $zonefile->line, 0, 'zonefile->line zero if file empty' );
Packit e6c8bb
Packit e6c8bb
	is( $zonefile->origin, '.', 'zonefile->origin defaults to DNS root' );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{					## initial origin
Packit e6c8bb
	my $tld = 'test';
Packit e6c8bb
	my $absolute = source( '', "$tld." );
Packit e6c8bb
	is( $absolute->origin, "$tld.", 'new ZoneFile with absolute origin' );
Packit e6c8bb
Packit e6c8bb
	my $relative = source( '', "$tld" );
Packit e6c8bb
	is( $relative->origin, "$tld.", 'new ZoneFile->origin always absolute' );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{					## line numbering
Packit e6c8bb
	my $lines    = 10;
Packit e6c8bb
	my $zonefile = source( "\n" x $lines );
Packit e6c8bb
	is( $zonefile->line, 0, 'zonefile->line zero before calling read()' );
Packit e6c8bb
	my @rr = $zonefile->read;
Packit e6c8bb
	is( $zonefile->line, $lines, 'zonefile->line number incremented by read()' );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{
Packit e6c8bb
	my $zonefile = source <<'EOF';
Packit e6c8bb
$TTL
Packit e6c8bb
EOF
Packit e6c8bb
	eval { $zonefile->read; };
Packit e6c8bb
	my $exception = $1 if $@ =~ /^(.+)\n/;
Packit e6c8bb
	ok( $exception ||= '', "exception:\t[$exception]" );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{
Packit e6c8bb
	my $zonefile = source <<'EOF';
Packit e6c8bb
$INCLUDE
Packit e6c8bb
EOF
Packit e6c8bb
	eval { $zonefile->read; };
Packit e6c8bb
	my $exception = $1 if $@ =~ /^(.+)\n/;
Packit e6c8bb
	ok( $exception ||= '', "exception:\t[$exception]" );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{
Packit e6c8bb
	my $zonefile = source <<'EOF';
Packit e6c8bb
$ORIGIN
Packit e6c8bb
EOF
Packit e6c8bb
	eval { $zonefile->read; };
Packit e6c8bb
	my $exception = $1 if $@ =~ /^(.+)\n/;
Packit e6c8bb
	ok( $exception ||= '', "exception:\t[$exception]" );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{
Packit e6c8bb
	my $zonefile = source <<'EOF';
Packit e6c8bb
$GENERATE
Packit e6c8bb
EOF
Packit e6c8bb
	eval { $zonefile->read; };
Packit e6c8bb
	my $exception = $1 if $@ =~ /^(.+)\n/;
Packit e6c8bb
	ok( $exception ||= '', "exception:\t[$exception]" );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{
Packit e6c8bb
	my $zonefile = source <<'EOF';
Packit e6c8bb
$BOGUS
Packit e6c8bb
EOF
Packit e6c8bb
	eval { $zonefile->read; };
Packit e6c8bb
	my $exception = $1 if $@ =~ /^(.+)\n/;
Packit e6c8bb
	ok( $exception ||= '', "exception:\t[$exception]" );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{					## $TTL directive at start of zone file
Packit e6c8bb
	my $zonefile = source <<'EOF';
Packit e6c8bb
$TTL 54321
Packit e6c8bb
rr0		SOA	mname rname 99 6h 1h 1w 12345
Packit e6c8bb
EOF
Packit e6c8bb
	is( $zonefile->read->ttl, 54321, 'SOA TTL set from $TTL directive' );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{					## no $TTL directive, default implicit
Packit e6c8bb
	my $zonefile = source <<'EOF';
Packit e6c8bb
rr0		SOA	mname rname 99 6h 1h 1w 0
Packit e6c8bb
rr1		NULL
Packit e6c8bb
EOF
Packit e6c8bb
	is( $zonefile->read->ttl, 0, 'SOA TTL set from zero SOA minimum field' );
Packit e6c8bb
	is( $zonefile->read->ttl, 0, 'implicit zero default from SOA record' );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{					## $TTL directive following implicit default
Packit e6c8bb
	my $zonefile = source <<'EOF';
Packit e6c8bb
rr0		SOA	mname rname 99 6h 1h 1w 12345
Packit e6c8bb
rr1		NULL
Packit e6c8bb
$TTL 54321
Packit e6c8bb
rr2		NULL
Packit e6c8bb
rr3	3h	NULL
Packit e6c8bb
EOF
Packit e6c8bb
	is( $zonefile->read->ttl, 12345, 'SOA TTL set from SOA minimum field' );
Packit e6c8bb
	is( $zonefile->read->ttl, 12345, 'implicit default from SOA record' );
Packit e6c8bb
	is( $zonefile->read->ttl, 54321, 'explicit default from $TTL directive' );
Packit e6c8bb
	is( $zonefile->read->ttl, 10800, 'explicit TTL value overrides default' );
Packit e6c8bb
	is( $zonefile->ttl,	  54321, '$zonefile->ttl set from $TTL directive' );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{					## $INCLUDE directive
Packit e6c8bb
	my $include = source <<'EOF';
Packit e6c8bb
rr2	NULL
Packit e6c8bb
EOF
Packit e6c8bb
Packit e6c8bb
	my $directive = join ' ', '$INCLUDE', $include->name, '.';
Packit e6c8bb
	my $misdirect = join ' ', '$INCLUDE zone0.txt	; presumed not to exist';
Packit e6c8bb
	my $zonefile  = source <<"EOF";
Packit e6c8bb
rr1	NULL
Packit e6c8bb
$directive
Packit e6c8bb
rr3	NULL
Packit e6c8bb
$recursive
Packit e6c8bb
$misdirect
Packit e6c8bb
EOF
Packit e6c8bb
Packit e6c8bb
	my $fn1 = $zonefile->name;
Packit e6c8bb
	my $rr1 = $zonefile->read;
Packit e6c8bb
	is( $rr1->name,	     'rr1', 'zonefile->read expected record' );
Packit e6c8bb
	is( $zonefile->name, $fn1,  'zonefile->name identifies file' );
Packit e6c8bb
	is( $zonefile->line, 1,	    'zonefile->line identifies record' );
Packit e6c8bb
Packit e6c8bb
	my $fn2 = $include->name;
Packit e6c8bb
	my $rr2 = $zonefile->read;
Packit e6c8bb
	my $sfx = $zonefile->origin;
Packit e6c8bb
	is( $rr2->name,	     'rr2', 'zonefile->read expected record' );
Packit e6c8bb
	is( $zonefile->name, $fn2,  'zonefile->name identifies file' );
Packit e6c8bb
	is( $zonefile->line, 1,	    'zonefile->line identifies record' );
Packit e6c8bb
Packit e6c8bb
	my $rr3 = $zonefile->read;
Packit e6c8bb
	is( $rr3->name,	     'rr3', 'zonefile->read expected record' );
Packit e6c8bb
	is( $zonefile->name, $fn1,  'zonefile->name identifies file' );
Packit e6c8bb
	is( $zonefile->line, 3,	    'zonefile->line identifies record' );
Packit e6c8bb
Packit e6c8bb
	{
Packit e6c8bb
		my @rr = eval { $zonefile->read };
Packit e6c8bb
		my $exception = $1 if $@ =~ /^(.+)\n/;
Packit e6c8bb
		ok( $exception ||= '', "recursive include\t[$exception]" );
Packit e6c8bb
	}
Packit e6c8bb
Packit e6c8bb
	{
Packit e6c8bb
		my @rr = eval { $zonefile->read };
Packit e6c8bb
		my $exception = $1 if $@ =~ /^(.+)\n/;
Packit e6c8bb
		ok( $exception ||= '', "non-existent include\t[$exception]" );
Packit e6c8bb
	}
Packit e6c8bb
	is( $zonefile->name, $fn1, 'zonefile->name identifies file' );
Packit e6c8bb
	is( $zonefile->line, 5,	   'zonefile->line identifies directive' );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
my $zonefile;
Packit e6c8bb
{					## $ORIGIN directive
Packit e6c8bb
	my $nested = source <<'EOF';
Packit e6c8bb
nested	NULL
Packit e6c8bb
EOF
Packit e6c8bb
Packit e6c8bb
	my $origin  = 'example.com';
Packit e6c8bb
	my $ORIGIN  = '$ORIGIN';
Packit e6c8bb
	my $inner   = join ' ', '$INCLUDE', $nested->name;
Packit e6c8bb
	my $include = source <<"EOF";
Packit e6c8bb
$ORIGIN $origin
Packit e6c8bb
@	NS	host
Packit e6c8bb
$inner 
Packit e6c8bb
@	NULL
Packit e6c8bb
$ORIGIN relative
Packit e6c8bb
@	NULL
Packit e6c8bb
EOF
Packit e6c8bb
Packit e6c8bb
	my $outer = join ' ', '$INCLUDE', $include->name;
Packit e6c8bb
	$zonefile = source <<"EOF";
Packit e6c8bb
$outer 
Packit e6c8bb
outer	NULL
Packit e6c8bb
Packit e6c8bb
$ORIGIN $origin
Packit e6c8bb
	NULL
Packit e6c8bb
EOF
Packit e6c8bb
Packit e6c8bb
	my $ns = $zonefile->read;
Packit e6c8bb
	is( $ns->name,	  $origin,	  '@	NS	has expected name' );
Packit e6c8bb
	is( $ns->nsdname, "host.$origin", '@	NS	has expected rdata' );
Packit e6c8bb
Packit e6c8bb
	my $rr = $zonefile->read;
Packit e6c8bb
	my $expect = join '.', 'nested', $origin;
Packit e6c8bb
	is( $rr->name, $expect, 'scope of $ORIGIN encompasses nested $INCLUDE' );
Packit e6c8bb
Packit e6c8bb
	is( $zonefile->read->name, $origin, 'scope of $ORIGIN continues after $INCLUDE' );
Packit e6c8bb
Packit e6c8bb
	is( $zonefile->read->name, "relative.$origin", '$ORIGIN can be relative to current $ORIGIN' );
Packit e6c8bb
Packit e6c8bb
	is( $zonefile->read->name, 'outer', 'scope of $ORIGIN curtailed by end of file' );
Packit e6c8bb
	is( $zonefile->read->name, $origin, 'implicit owner following $ORIGIN directive' );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{					## $GENERATE directive
Packit e6c8bb
	my $zonefile = source <<'EOF';
Packit e6c8bb
$GENERATE 0-0		@	TXT	$
Packit e6c8bb
$GENERATE 10-30/10	@	TXT	$
Packit e6c8bb
$GENERATE 30-10/-10	@	TXT	$
Packit e6c8bb
$GENERATE 123-123	@	TXT	${,,}
Packit e6c8bb
$GENERATE 123-123	@	TXT	${0,0,d}
Packit e6c8bb
$GENERATE 123-123	@	TXT	${0,0,o}
Packit e6c8bb
$GENERATE 123-123	@	TXT	${0,0,x}
Packit e6c8bb
$GENERATE 123-123	@	TXT	${0,0,X}
Packit e6c8bb
$GENERATE 123-123	@	TXT	${0,4,X}
Packit e6c8bb
$GENERATE 123-123	@	TXT	${4096,4,X}
Packit e6c8bb
$GENERATE 11259375	@	TXT	${0,6,n}
Packit e6c8bb
$GENERATE 11259375	@	TXT	${0,16,N}
Packit e6c8bb
$GENERATE 0-0		@	TXT	${0,0,Z}
Packit e6c8bb
EOF
Packit e6c8bb
	is( $zonefile->read->rdstring, '0',		   'generate TXT $' );
Packit e6c8bb
	is( $zonefile->read->rdstring, '10',		   'generate TXT $ with step 10' );
Packit e6c8bb
	is( $zonefile->read->rdstring, '20',		   'generate TXT $ with step 10' );
Packit e6c8bb
	is( $zonefile->read->rdstring, '30',		   'generate TXT $ with step 10' );
Packit e6c8bb
	is( $zonefile->read->rdstring, '30',		   'generate TXT $ with step -10' );
Packit e6c8bb
	is( $zonefile->read->rdstring, '20',		   'generate TXT $ with step -10' );
Packit e6c8bb
	is( $zonefile->read->rdstring, '10',		   'generate TXT $ with step -10' );
Packit e6c8bb
	is( $zonefile->read->rdstring, '123',		   'generate TXT ${,,}' );
Packit e6c8bb
	is( $zonefile->read->rdstring, '123',		   'generate TXT ${0,0,d}' );
Packit e6c8bb
	is( $zonefile->read->rdstring, '173',		   'generate TXT ${0,0,o}' );
Packit e6c8bb
	is( $zonefile->read->rdstring, '7b',		   'generate TXT ${0,0,x}' );
Packit e6c8bb
	is( $zonefile->read->rdstring, '7B',		   'generate TXT ${0,0,X}' );
Packit e6c8bb
	is( $zonefile->read->rdstring, '007B',		   'generate TXT ${0,4,X}' );
Packit e6c8bb
	is( $zonefile->read->rdstring, '107B',		   'generate TXT ${4096,4,X}' );
Packit e6c8bb
	is( $zonefile->read->rdstring, 'f.e.d.',	   'generate TXT ${0,6,n}' );
Packit e6c8bb
	is( $zonefile->read->rdstring, 'F.E.D.C.B.A.0.0.', 'generate TXT ${0,16,N}' );
Packit e6c8bb
	eval { $zonefile->read; };
Packit e6c8bb
	my $exception = $1 if $@ =~ /^(.+)\n/;
Packit e6c8bb
	ok( $exception ||= '', "unknown format:\t[$exception]" );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{
Packit e6c8bb
	my $zonefile = source <<'EOF';
Packit e6c8bb
$TTL 1234
Packit e6c8bb
$ORIGIN example.
Packit e6c8bb
hosta	A	192.0.2.1
Packit e6c8bb
; whole line comment
Packit e6c8bb
	; indented comment
Packit e6c8bb
; vvv empty line
Packit e6c8bb
Packit e6c8bb
; ^^^ empty line
Packit e6c8bb
; vvv line with white space
Packit e6c8bb
	     
Packit e6c8bb
; ^^^ line with white space
Packit e6c8bb
	MX	10 hosta	; end of line comment
Packit e6c8bb
Packit e6c8bb
	TXT	( multiline	; interspersed ( mischievously )
Packit e6c8bb
		resource	; with	( confusing )
Packit e6c8bb
		record	)	; comments
Packit e6c8bb
	TXT	(string)
Packit e6c8bb
	TXT	"(string)"
Packit e6c8bb
EOF
Packit e6c8bb
	is( $zonefile->read->name, 'hosta.example', 'name of simple RR as expected' );
Packit e6c8bb
	is( $zonefile->read->name, 'hosta.example', 'name of simple RR propagated from previous RR' );
Packit e6c8bb
	my $multilineRR = $zonefile->read;
Packit e6c8bb
	is( $multilineRR->name,	   'hosta.example',		'name of multiline RR propagated from previous RR' );
Packit e6c8bb
	is( $multilineRR->txtdata, 'multiline resource record', 'multiline RR correctly reassembled' );
Packit e6c8bb
	my $following = $zonefile->read;
Packit e6c8bb
	is( $following->name,	      'hosta.example', 'name of following RR as expected' );
Packit e6c8bb
	is( $following->txtdata,      'string',	       'superfluous brackets ignored' );
Packit e6c8bb
	is( $zonefile->read->txtdata, '(string)',      'quoted brackets protected' );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{					## CLASS coersion
Packit e6c8bb
	my $zonefile = source <<'EOF';
Packit e6c8bb
rr0	CH	NULL
Packit e6c8bb
rr1	CLASS1	NULL
Packit e6c8bb
rr2	CLASS2	NULL
Packit e6c8bb
rr3	CLASS3	NULL
Packit e6c8bb
EOF
Packit e6c8bb
	my $rr = $zonefile->read;
Packit e6c8bb
	foreach ( $zonefile->read ) {
Packit e6c8bb
		is( $_->class, $rr->class, 'rr->class matches initial record' );
Packit e6c8bb
	}
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{					## compatibility with defunct Net::DNS::ZoneFile 1.04 distro
Packit e6c8bb
	my $listref = Net::DNS::ZoneFile->read( $zonefile->name );
Packit e6c8bb
	ok( scalar(@$listref), 'read(): entire zone file' );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{
Packit e6c8bb
	my $listref = Net::DNS::ZoneFile->read( $zonefile->name, '.' );
Packit e6c8bb
	ok( scalar(@$listref), 'read(): zone file via path' );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{
Packit e6c8bb
	eval {
Packit e6c8bb
		local $SIG{__WARN__} = sub { };			# presumed not to exist
Packit e6c8bb
		my $listref = Net::DNS::ZoneFile->read( '/zone0.txt', '.' );
Packit e6c8bb
	};
Packit e6c8bb
	my $exception = $1 if $@ =~ /^(.+)\n/;
Packit e6c8bb
	ok( $exception ||= '', "read(): non-existent file\t[$exception]" );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{
Packit e6c8bb
	eval {
Packit e6c8bb
		local $SIG{__WARN__} = sub { };			# presumed not to exist
Packit e6c8bb
		my $listref = Net::DNS::ZoneFile->read( 'zone0.txt', 't' );
Packit e6c8bb
	};
Packit e6c8bb
	my $exception = $1 if $@ =~ /^(.+)\n/;
Packit e6c8bb
	ok( $exception ||= '', "read(): non-existent file\t[$exception]" );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{
Packit e6c8bb
	my $listref = Net::DNS::ZoneFile::read( $zonefile->name, '.' );
Packit e6c8bb
	ok( scalar(@$listref), 'read(): called as subroutine (not object-oriented)' );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{
Packit e6c8bb
	my $string  = "";
Packit e6c8bb
	my $listref = Net::DNS::ZoneFile->parse( \$string );
Packit e6c8bb
	is( scalar(@$listref), 0, 'parse(): empty string' );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{
Packit e6c8bb
	my $string = <<'EOF';
Packit e6c8bb
a1.example A 192.0.2.1
Packit e6c8bb
a2.example A 192.0.2.2
Packit e6c8bb
EOF
Packit e6c8bb
	my $listref = Net::DNS::ZoneFile->parse( \$string );	# this also tests readfh()
Packit e6c8bb
	is( scalar(@$listref), 2, 'parse(): RR string' );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{
Packit e6c8bb
	my $string = <<'EOF';
Packit e6c8bb
a1.example A 192.0.2.1
Packit e6c8bb
$BOGUS
Packit e6c8bb
a2.example A 192.0.2.2
Packit e6c8bb
EOF
Packit e6c8bb
	local $SIG{__WARN__} = sub { };
Packit e6c8bb
	my $listref = Net::DNS::ZoneFile->parse( \$string );
Packit e6c8bb
	is( $listref, undef, 'parse(): erroneous string' );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{
Packit e6c8bb
	my $string = <<'EOF';
Packit e6c8bb
a1.example A 192.0.2.1
Packit e6c8bb
a2.example A 192.0.2.2
Packit e6c8bb
EOF
Packit e6c8bb
	my @list = Net::DNS::ZoneFile->parse($string);
Packit e6c8bb
	is( scalar(@list), 2, 'parse(): RR string into array' );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{
Packit e6c8bb
	my $string = <<'EOF';
Packit e6c8bb
a1.example A 192.0.2.1
Packit e6c8bb
$BOGUS
Packit e6c8bb
a2.example A 192.0.2.2
Packit e6c8bb
EOF
Packit e6c8bb
	local $SIG{__WARN__} = sub { };
Packit e6c8bb
	my @list = Net::DNS::ZoneFile->parse($string);
Packit e6c8bb
	is( scalar(@list), 1, 'parse(): erroneous string into array' );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
{
Packit e6c8bb
	my $listref = Net::DNS::ZoneFile::parse('a.example. A 192.0.2.1');
Packit e6c8bb
	ok( scalar(@$listref), 'parse(): called as subroutine (not object-oriented)' );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
SKIP: {					## Non-ASCII zone content
Packit e6c8bb
	skip( 'Unicode/UTF-8 not supported', 4 ) unless UTF8;
Packit e6c8bb
Packit e6c8bb
	my $greek = pack 'C*', 103, 114, 9, 84, 88, 84, 9, 229, 224, 241, 231, 234, 225, 10;
Packit e6c8bb
	my $file1 = source($greek);
Packit e6c8bb
	my $fh1	  = new IO::File( $file1->name, '<:encoding(ISO8859-7)' );		       # Greek
Packit e6c8bb
	my $zone1 = new Net::DNS::ZoneFile($fh1);
Packit e6c8bb
	my $txtgr = $zone1->read;
Packit e6c8bb
	my $text  = pack 'U*', 949, 944, 961, 951, 954, 945;
Packit e6c8bb
	is( $txtgr->txtdata, $text, 'ISO8859-7 TXT rdata' );
Packit e6c8bb
Packit e6c8bb
	eval { binmode(DATA) };					# suppress encoding layer
Packit e6c8bb
	my $jptxt = join "\n", <DATA>;
Packit e6c8bb
	my $file2 = source($jptxt);
Packit e6c8bb
	my $fh2	  = new IO::File( $file2->name, '<:utf8' );	# UTF-8 character encoding
Packit e6c8bb
	my $zone2 = new Net::DNS::ZoneFile($fh2);
Packit e6c8bb
	my $txtrr = $zone2->read;				# TXT RR with kanji RDATA
Packit e6c8bb
	my @rdata = $txtrr->txtdata;
Packit e6c8bb
	my $rdata = $txtrr->txtdata;
Packit e6c8bb
	is( length($rdata), 12, 'Unicode/UTF-8 TXT rdata' );
Packit e6c8bb
	is( scalar(@rdata), 1,	'Unicode/UTF-8 TXT contiguous' );
Packit e6c8bb
Packit e6c8bb
	skip( 'Non-ASCII domain - IDNA not supported', 1 ) unless LIBIDNOK || LIBIDN2OK;
Packit e6c8bb
Packit e6c8bb
	my $jpnull = $zone2->read;				# NULL RR with kanji owner name
Packit e6c8bb
	is( $jpnull->name, 'xn--wgv71a', 'Unicode/UTF-8 domain name' );
Packit e6c8bb
}
Packit e6c8bb
Packit e6c8bb
Packit e6c8bb
exit;
Packit e6c8bb
Packit e6c8bb
__END__
Packit e6c8bb
jp	TXT	古池や 蛙飛込む 水の音		; Unicode text string
Packit e6c8bb
日本	NULL						; Unicode domain name
Packit e6c8bb