The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!./perl

BEGIN { require './test.pl'; }

plan( tests => 34 );

# simple error object.
do {
    my $err = error::create("my message", @("filetest.t", 33, 11));
    ok $err, "error object created";
    is ref $err, "error";
    is $err->{?description}, "my message";
    is $err->description, "my message", "message function";
    is $err->stacktrace, " at filetest.t line 33 character 11.\n",
      "stacktrace function";
    is $err->message, "my message at filetest.t line 33 character 11.\n",
      "message function";
};

# a bit more complex one, with stack trace.
do {
    my ($line1, $line2, $line3);
    sub new_error { return error::create("my message"); } $line1 = __LINE__;
    sub new_error2 { return new_error(); } $line2 = __LINE__;
    my $err = new_error2(); $line3 = __LINE__;
    is( (nelems $err->{?stack}), 2);
    is((join '**', $err->{?stack}[0]), "../lib/error.t**$line2**29**main::new_error**");
    is((join '**', $err->{?stack}[1]), "../lib/error.t**$line3**15**main::new_error2**");
    is $err->description, "my message";
    is $err->stacktrace, <<MSG;

    main::new_error called at ../lib/error.t line $line2 character 29.
    main::new_error2 called at ../lib/error.t line $line3 character 15.
MSG
};

# creating the error object using 'die' inside an 'eval'
do {
    my ($line1, $line2);
    try { $line1 = __LINE__;
           $line2 = __LINE__; die "foobar";
       };
    is defined $^EVAL_ERROR, 1, '$@ is set';
    is ref $^EVAL_ERROR, "error", '$@ is an error object';
    is $^EVAL_ERROR->{?description}, "foobar";
    is $^EVAL_ERROR->description, "foobar";
    is $^EVAL_ERROR->stacktrace, <<MSG;
 at ../lib/error.t line $line2 character 31.
    (eval) called at ../lib/error.t line $line1 character 5.
MSG
};

# creating the error object using 'die' inside an 'eval' in an 'eval'
do {
    my $err;
    my ($line1, $line2);
    try { $line2 = __LINE__;
        try { die "my die"; }; $line1 = __LINE__;
        $err = $^EVAL_ERROR;
    };
    is defined $err, 1, '$@ is set';
    is ref $err, "error", '$@ is error object';
    is $err->description, "my die";
    is $err->stacktrace, <<MSG;
 at ../lib/error.t line $line1 character 15.
    (eval) called at ../lib/error.t line $line1 character 9.
    (eval) called at ../lib/error.t line $line2 character 5.
MSG
};

# die without arguments, reuses $@
do {
    my ($line1, $line2);
    try { $line2 = __LINE__;
        try { die "reuse die"; }; $line1 = __LINE__;
        die;
    };
    is ref $^EVAL_ERROR, "error", '$@ is an error object';
    is $^EVAL_ERROR->description, "reuse die";
    is $^EVAL_ERROR->stacktrace, <<MSG;
 at ../lib/error.t line $line1 character 15.
    (eval) called at ../lib/error.t line $line1 character 9.
    (eval) called at ../lib/error.t line $line2 character 5.
reraised at ../lib/error.t line $($line1+1) character 9.
MSG
};

# Internal Perl_croak routines also make error objects
do {
    my $line1;
    try { my $foo = "xx"; $$foo; }; $line1 = __LINE__;
    is defined $^EVAL_ERROR, 1, '$@ is set';
    is ref $^EVAL_ERROR, 'error', '$@ is an error object';
    is $^EVAL_ERROR->description, "Can't use PLAINVALUE as a SCALAR REF";
    is $^EVAL_ERROR->stacktrace, <<MSG;
 at ../lib/error.t line $line1 character 27.
    (eval) called at ../lib/error.t line $line1 character 5.
MSG
};

# Writing the standard message
do {
    fresh_perl_is("die 'foobar'",
                  'foobar at - line 1 character 1.');
};

# Compilation error
do {
    fresh_perl_is('BEGIN { die "foobar" }', <<MSG );
foobar at - line 1 character 9.
    BEGIN called at - line 1 character 1.
MSG
};

# yyerror
do {
    eval 'undef "foo"'; my $line = __LINE__;
    is defined $^EVAL_ERROR, 1, '$@ is set';
    is ref $^EVAL_ERROR, 'error', '$@ is error object';
    is $^EVAL_ERROR->description, "Can't modify constant item in undef operator";
    is $^EVAL_ERROR->stacktrace, <<MSG ;
 at (eval 9) line 1 character 12.
    (eval) called at ../lib/error.t line $line character 5.
MSG
};

# Compilation error with '#line X'
do {
    fresh_perl_is("\$x = 1;\n\$y = 1;\n", <<'MSG' );
Global symbol "$x" requires explicit package name at - line 1, near "$x "
Global symbol "$y" requires explicit package name at - line 2, near "$y "
Execution of - aborted due to compilation errors.
MSG
};