use strict; use warnings; use Geo::Gpx; use Test::More; BEGIN { eval "use Test::XML"; plan skip_all => "Test::XML unavailable" if $@; } use Test::More tests => 4; my %refxml = (); my $k = undef; while ( ) { if ( /^==\s+(\S+)\s+==$/ ) { $k = $1; } elsif ( defined( $k ) ) { $refxml{$k} .= $_; } } my $gpx = Geo::Gpx->new(); my @wpt = ( { # All standard GPX fields lat => 54.786989, lon => -2.344214, ele => 512, time => time(), magvar => 0, geoidheight => 0, name => 'My house & home', cmt => 'Where I live', desc => '<>', src => 'Testing', link => { href => 'http://hexten.net/', text => 'Hexten', type => 'Blah' }, sym => 'pin', type => 'unknown', fix => 'dgps', sat => 3, hdop => 10, vdop => 10, pdop => 10, ageofdgpsdata => 45, dgpsid => 247 }, { # Fewer fields lat => -38.870059, lon => -151.210030, name => 'Sydney, AU' } ); $gpx->waypoints( \@wpt ); # Quick fix for dumbass dependency on RNG being the same everywhere my $rp = 0; my @rn = ( 0.03984, 0.08913, 0.12012, 0.84698, 0.35285, 0.00580, 0.37354, 0.33931, 0.88578, 0.78503, 0.69597, 0.19332, 0.76844, 0.08150, 0.47062, 0.64957, 0.00072, 0.57271, 0.73318, 0.80986, 0.96169, 0.96567, 0.52550, 0.57476, 0.21792, 0.07187, 0.95170, 0.19820, 0.07930, 0.86521, 0.37511, 0.52225, 0.48271, 0.23808, 0.70230, 0.23426, 0.05024, 0.44965, 0.96768, 0.17396, 0.11877, 0.65996, 0.89178, 0.67894, 0.30362, 0.11972, 0.87709, 0.70132, 0.69666, 0.46293, 0.11827, 0.35612, 0.14679, 0.56480, 0.43109, 0.21226, 0.59054, 0.78612, 0.79592, 0.94235, 0.03657, 0.34607, 0.91482, 0.47672, 0.32947, 0.53454, 0.70178, 0.02437, 0.07496, 0.49284, 0.16772, 0.82976, 0.27625, 0.12485, 0.68737, 0.32405, 0.06580, 0.13189, 0.90450, 0.03470, 0.00016, 0.24118, 0.26281, 0.76458, 0.37970, 0.98307, 0.25990, 0.80449, 0.94870, 0.19664, 0.38404, 0.35733, 0.69219, 0.14925, 0.38206, 0.62497, 0.66942, 0.35608, 0.05149, 0.72594, ); sub not_rand { $rp = 0 if $rp == @rn; return $rn[ $rp++ ]; } my $lat = 54.786989; my $lon = -2.344214; my $next = 1; sub get_point { my $fmt = shift; my $dlat = not_rand( 1 ) - 0.5; my $dlon = not_rand( 1 ) - 0.5; $lat += $dlat; $lon += $dlon; if ( $fmt ) { return { lat => $lat, lon => $lon, name => sprintf( $fmt, $next++ ) }; } else { return { lat => $lat, lon => $lon }; } } my @rte = ( { name => 'Route 1', points => [ map { get_point( 'WPT%d' ) } ( 1 .. 3 ) ] }, { name => 'Route 2', points => [ map { get_point( 'WPT%d' ) } ( 1 .. 2 ) ] } ); $gpx->routes( \@rte ); my @trk = ( { name => 'Track 1', segments => [ { points => [ map { get_point() } ( 1 .. 3 ) ] }, { points => [ map { get_point() } ( 1 .. 1 ) ] } ] }, { name => 'Track 2', segments => [ { points => [ map { get_point() } ( 1 .. 5 ) ] } ] } ); $gpx->tracks( \@trk ); $gpx->name( 'Test' ); $gpx->desc( 'Test data' ); $gpx->author( { name => 'Andy Armstrong', email => { id => 'andy', domain => 'hexten.net' }, link => { href => 'http://hexten.net/', text => 'Hexten' } } ); $gpx->copyright( '(c) Anyone' ); $gpx->link( { href => 'http://www.topografix.com/GPX', text => 'GPX Spec', type => 'unknown' } ); $gpx->time( time() ); $gpx->keywords( [ 'this', 'that', 'the other' ] ); for my $version ( keys %refxml ) { my $xml = normalise( $refxml{$version} ); my $gen = normalise( $gpx->xml( $version ) ); is_xml( $gen, $xml, 'generated version ' . $version ); # Parse reference XMLs my $ngpx = Geo::Gpx->new( xml => $refxml{$version} ); my $ngen = normalise( $ngpx->xml() ); is_xml( $ngen, $xml, 'reparsed version ' . $version ); } sub save_if_diff { my ( $base, $gen, $orig ) = @_; if ( $gen ne $orig ) { save( "$base-orig.gpx", $orig ); save( "$base-gen.gpx", $gen ); } } sub save { my ( $name, $xml ) = @_; open( my $fh, '>', $name ) or die "Can't write $name ($!)\n"; print $fh $xml; close( $fh ); } sub normalise { my $xml = shift; # Remove leading spaces in case we decide to indent the output $xml =~ s{^\s+}{}msg; my $fix_time = sub { my $tm = shift; $tm =~ s{\d}{9}g; $tm =~ s{[+-]}{-}g; return $tm; }; $xml =~ s{()}{$1 . $fix_time->($2) . $3}eg; my $fix_coord = sub { my $co = shift; return sprintf( "%.6f", $co ); }; $xml =~ s{((?:lat|lon)=\")([^\"]+)(\")}{$1 . $fix_coord->($2) . $3}eg; return $xml; } __END__ == 1.0 == Test Test data Andy Armstrong andy@hexten.net this, that, the other (c) Anyone http://www.topografix.com/GPX GPX Spec Route 1 WPT1 WPT2 WPT3 Route 2 WPT4 WPT5 Track 1 Track 2 45 Where I live <<Chez moi>> 247 512 dgps 0 10 http://hexten.net/ Hexten 0 My house & home 10 3 Testing pin unknown 10 Sydney, AU == 1.1 == Test Test data Hexten Andy Armstrong this, that, the other (c) Anyone GPX Spec unknown Route 1 WPT1 WPT2 WPT3 Route 2 WPT4 WPT5 Track 1 Track 2 45 Where I live <<Chez moi>> 247 512 dgps 0 10 Hexten Blah 0 My house & home 10 3 Testing pin unknown 10 Sydney, AU