class TestCase::Exception {
  use TestCase::Minimal;
  use TestCase;
  use Comparator;
  use Regex;
  
  our $CALLBACK_DIE_LINE  : rw int;
  our $ZERO_DIVIDE_INT_LINE : rw int;
  
  static method exception_get_field_object_undef : int () {
    
    my $test_case : TestCase = undef;
    
    eval {
      $test_case->{x_byte};
    };
    if ($@) {
      return 1;
      
      eval {
        $test_case->{x_short};
      };
      
      if ($@) {
        return 1;

        eval {
          $test_case->{x_int};
        };
        
        if ($@) {
          eval {
            $test_case->{x_long};
          };
          
          if ($@) {
            eval {
              $test_case->{x_float};
            };
            
            if ($@) {
              eval {
                $test_case->{x_double};
              };
              
              if ($@) {
                eval {
                  $test_case->{x_test_case};
                };
                
                if ($@) {

                  return 1;
                }
              }
            }
          }
        }

      }
      
    }
    
    return 0;
  }
  
  static method exception_set_field_object_undef : int () {
    
    my $test_case : TestCase = undef;
    
    eval {
      $test_case->{x_byte} = (byte)1;
    };
    if ($@) {
      return 1;
      
      eval {
        $test_case->{x_short} = (short)1;
      };
      
      if ($@) {
        return 1;

        eval {
          $test_case->{x_int} = 1;
        };
        
        if ($@) {
          eval {
            $test_case->{x_long} = 1L;
          };
          
          if ($@) {
            eval {
              $test_case->{x_float} = 1f;
            };
            
            if ($@) {
              eval {
                $test_case->{x_double} = 1d;
              };
              
              if ($@) {
                eval {
                  $test_case->{x_test_case} = undef;
                };
                
                if ($@) {

                  return 1;
                }
              }
            }
          }
        }
      }
      
    }
    
    return 0;
  }
  static method exception_eval_call_spvm_method : int () {
    eval {
      TestCase::Exception->exception_die_return_int();
    };
    
    if ($@) {
      return 1;
    }
    
    return 0;
  }
  
  static method exception_call_stack : int () {
    TestCase::Exception->exception_die_return_int();
  }
  
  static method exception_die_return_byte : byte () {
    die "Error";
  }
  
  static method exception_die_return_short : short () {
    die "Error";
  }
  
  static method exception_die_return_int : int () {
    die "Error";
  }
  
  static method exception_die_return_long : long () {
    die "Error";
  }
  
  static method exception_die_return_float : float () {
    die "Error";
  }
  
  static method exception_die_return_double : double () {
    die "Error";
  }
  
  static method exception_die_return_object : TestCase::Minimal () {
    die "Error";
  }
  
  static method exception_die_return_void : void () {
    die "Error";
  }

  static method exception_die_return_int_eval_catch : int () {
    eval {
      die "Error";
    };
    
    
    if ($@) {
      return 1;
    }
    
    return 0;
  }
  # Exception
  static method exception_zero_divide_int : int () {
    TestCase::Exception->SET_ZERO_DIVIDE_INT_LINE(__LINE__); 1 / 0;
  }

  static method exception_callback : int () {
    
    my $comparator = (Comparator)method : int ($x1 : object, $x2 : object) {
      TestCase::Exception->SET_CALLBACK_DIE_LINE(__LINE__); die "Comparator Error"; 
    };
    
    $comparator->(undef, undef);
  }

  static method die : int () {
    {
      eval { die "Error"; };
      my $error = $@;
      unless (Fn->match($error, "^Error\n")) {
        return 0;
      }
    }
    {
      eval { die; };
      my $error = $@;
      unless (Fn->match($error, "^Died\n")) {
        return 0;
      }
    }
    
    $@ = undef;
    
    return 1;
  }
}