The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl
# Copyright (c) 2011 - Olof Johansson <olof@cpan.org>
# All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.

use warnings;
use strict;
use Test::More;
use Regexp::Common qw/Chess/;

my $re = $RE{Chess}{SAN};

sub gen_variants {
	my $base = shift;
	my $msg = shift;
	my $opts = shift;

	my %ret;

	$ret{$base} = $msg unless $opts->{onlycapture};

	if(! $opts->{nocapture}) {
		my $capture = $base;
		$capture =~ s/(?=[a-h][1-8]$|[a-h][1-8]=[NBQR]$)/x/;
		$ret{"$capture"} = "$msg (capture)";
		$ret{"$capture+"} = "$msg (capture+check)";
		$ret{"$capture#"} = "$msg (capture+checkmate)";
	}

	if(! $opts->{onlycapture}) {
		$ret{"$base+"} = "$msg (check)";
		$ret{"$base#"} = "$msg (checkmate)";
	}

	return %ret;
}

# N.b. Test::More escapes hashes (#) as they are otherwise
#      part of the TAP syntax (directive delimiter).

my %good = (
	gen_variants('Ka1', 'King moves'),
	gen_variants('Qh8', 'Queen moves'),
	gen_variants('a6', 'Pawn moves'),
	map({ gen_variants("a8=$_->[0]", "White pawn promotion to $_->[1]") }
		([qw/Q queen/], [qw/N knight/], [qw/B bishop/], [qw/R rook/])),
	map({ gen_variants("a1=$_->[0]", "Black pawn promotion to $_->[1]") }
		([qw/Q queen/], [qw/N knight/], [qw/B bishop/], [qw/R rook/])),
	gen_variants('O-O', 'Castling king side', {nocapture=>1}),
	gen_variants('O-O-O', 'Castling queen side', {nocapture=>1}),
	gen_variants('Bb2a3', 'Coordinate disambiguation, bishop'),
	gen_variants('Nbb3', 'File disambiguation, knight'),
	gen_variants('R5c3', 'File disambiguation, rook'),
	gen_variants('ba3', 'File disambiguation, pawn', {onlycapture=>1}),
	gen_variants('Rf8', 'Rook to f8 (no promotion)'),
	gen_variants('Qd1', 'Queen to d1 (no promotion)'),
);

my %bad = (
	gen_variants('i1', 'invalid file (pawn)'),
	gen_variants('h9', 'invalid rank (pawn)'),
	gen_variants('i0', 'invalid file and rank (pawn)'),
	gen_variants('a8=K', 'pawn promotion to king'),
	gen_variants('a8', 'pawn moves to rank 8 w/o promotion'),
	'' => 'empty string',
	'Qxxa3' => 'multiple capture characters',
	'Qxa3##' => 'multiple checkmate characters',
	'Qxa3++' => 'multiple check characters',
	'b1b2a3' => "three coordinates",
	'O-o' => "mixing capital and lower letters (castling)",
	'B2a' => "coordinates with wrong order",
);

plan tests => keys(%good) + keys(%bad) + 1;

my $undef;
ok(  /^$re$/, "Should match '$_' ($good{$_})")    for(keys %good);
ok(! /^$re$/, "Should not match '$_' ($bad{$_})") for(keys %bad );

{
	no warnings qw/uninitialized/;
	ok($undef !~ /^$re$/, "Should not match undef");
}