package TestCase::Extension {
  use TestCase;
  use TestCase::Simple;

  native sub ref_byte_sum : byte ($x_in : byte, $x_in2 : byte, $x_out : byte&);
  sub ref_byte : int () {
    my $out : byte;
    my $out_ref = \$out;
    
    ref_byte_sum(1, INT8_MIN(), $out_ref);
    
    if ($$out_ref == INT8_MIN() + 1) {
      return 1;
    }
    
    return 0;
  }

  native sub ref_short_sum : short ($x_in : short, $x_in2 : short, $x_out : short&);
  sub ref_short : int () {
    my $out : short;
    my $out_ref = \$out;
    
    ref_short_sum(1, INT16_MIN(), $out_ref);
    
    if ($$out_ref == INT16_MIN() + 1) {
      return 1;
    }
    
    return 0;
  }

  native sub ref_int_sum : int ($x_in : int, $x_in2 : int, $x_out : int&);
  sub ref_int : int () {
    my $out : int;
    my $out_ref = \$out;
    
    ref_int_sum(1, INT32_MIN(), $out_ref);
    
    if ($$out_ref == INT32_MIN() + 1) {
      return 1;
    }
    
    return 0;
  }

  native sub ref_long_sum : long ($x_in : long, $x_in2 : long, $x_out : long&);
  sub ref_long : int () {
    my $out : long;
    my $out_ref = \$out;
    
    ref_long_sum(1, INT64_MIN(), $out_ref);
    
    if ($$out_ref == INT64_MIN() + 1) {
      return 1;
    }
    
    return 0;
  }
  
  native sub ref_float_sum : float ($x_in : float, $x_in2 : float, $x_out : float&);
  sub ref_float : int () {
    my $out : float;
    my $out_ref = \$out;
    
    ref_float_sum(0.25f, FLT_MIN(), $out_ref);
    
    if ($$out_ref == FLT_MIN() + 0.25f) {
      return 1;
    }
    
    return 0;
  }

  native sub ref_double_sum : double ($x_in : double, $x_in2 : double, $x_out : double&);
  sub ref_double : int () {
    my $out : double;
    my $out_ref = \$out;
    
    ref_double_sum(0.25, DBL_MIN(), $out_ref);
    
    if ($$out_ref == DBL_MIN() + 0.25) {
      return 1;
    }
    
    return 0;
  }

  sub set_bfield : int () {
    my $simple = TestCase::Simple->new;
    
    native_set_bfield($simple);
    
    if ($simple->{byte_value} == INT8_MIN()) {
      return 1;
    }
    
    return 0;
  }
  native sub native_set_bfield : void ($simple : TestCase::Simple);

  sub set_sfield : int () {
    my $simple = TestCase::Simple->new;
    
    native_set_sfield($simple);
    
    if ($simple->{short_value} == INT16_MIN()) {
      return 1;
    }
    
    return 0;
  }
  native sub native_set_sfield : void ($simple : TestCase::Simple);

  sub set_ifield : int () {
    my $simple = TestCase::Simple->new;
    
    native_set_ifield($simple);
    
    if ($simple->{int_value} == INT32_MIN()) {
      return 1;
    }
    
    return 0;
  }
  native sub native_set_ifield : void ($simple : TestCase::Simple);

  sub set_lfield : int () {
    my $simple = TestCase::Simple->new;
    
    native_set_lfield($simple);
    
    if ($simple->{long_value} == INT64_MIN()) {
      return 1;
    }
    
    return 0;
  }
  native sub native_set_lfield : void ($simple : TestCase::Simple);

  sub set_ffield : int () {
    my $simple = TestCase::Simple->new;
    
    native_set_ffield($simple);
    
    if ($simple->{float_value} == FLT_MIN()) {
      return 1;
    }
    
    return 0;
  }
  native sub native_set_ffield : void ($simple : TestCase::Simple);
  
  sub set_dfield : int () {
    my $simple = TestCase::Simple->new;
    
    native_set_dfield($simple);
    
    if ($simple->{double_value} == DBL_MIN()) {
      return 1;
    }
    
    return 0;
  }
  native sub native_set_dfield : void ($simple : TestCase::Simple);

  sub set_ofield : int () {
    my $simple = TestCase::Simple->new;
    
    native_set_ofield($simple);
    
    if ($simple->{object_value}{x} == 3) {
      return 1;
    }
    
    return 0;
  }
  native sub native_set_ofield : int ($simple : TestCase::Simple);

  sub bfield : int () {
    my $simple = TestCase::Simple->new;
    $simple->{byte_value} = INT8_MIN();
    
    my $success = native_get_bfield($simple);
    
    return $success;
  }
  native sub native_get_bfield : int ($simple : TestCase::Simple);

  sub sfield : int () {
    my $simple = TestCase::Simple->new;
    $simple->{short_value} = INT16_MIN();
    
    my $success = native_get_sfield($simple);
    
    return $success;
  }
  native sub native_get_sfield : int ($simple : TestCase::Simple);

  sub ifield : int () {
    my $simple = TestCase::Simple->new;
    $simple->{int_value} = INT32_MIN();
    
    my $success = native_get_ifield($simple);
    
    return $success;
  }
  native sub native_get_ifield : int ($simple : TestCase::Simple);

  sub lfield : int () {
    my $simple = TestCase::Simple->new;
    $simple->{long_value} = INT64_MIN();
    
    my $success = native_get_lfield($simple);
    
    return $success;
  }
  native sub native_get_lfield : int ($simple : TestCase::Simple);

  sub ffield : int () {
    my $simple = TestCase::Simple->new;
    $simple->{float_value} = FLT_MIN();
    
    my $success = native_get_ffield($simple);
    
    return $success;
  }
  native sub native_get_ffield : int ($simple : TestCase::Simple);

  sub dfield : int () {
    my $simple = TestCase::Simple->new;
    $simple->{double_value} = DBL_MIN();
    
    my $success = native_get_dfield($simple);
    
    return $success;
  }
  native sub native_get_dfield : int ($simple : TestCase::Simple);

  sub ofield : int () {
    my $simple = TestCase::Simple->new;
    $simple->{object_value} = TestCase::Minimal->new;
    $simple->{object_value}{x} = 5;
    
    my $success = native_get_ofield($simple);
    
    return $success;
  }
  native sub native_get_ofield : int ($simple : TestCase::Simple);
  
  sub spvm_extension_add_iarray : int () {
    my $nums1 = new int[] {1, 2, 3};
    my $nums2 = new int[] {4, 5, 6};
    
    my $nums3 = add_iarray($nums1, $nums2);
    
    if ($nums3->[0] == 5) {
      if ($nums3->[1] == 7) {
        if ($nums3->[2] == 9) {
          return 1;
        }
      }
    }
    
    return 0;
  }

  sub spvm_extension : int () {
    my $total = sum(2, 3);
    
    if ($total == 5) {
      return 1;
    }
    
    return 0;
  }
  
  sub native_use_strlen_test : int () {
    my $string = "abcde";
    my $length = native_use_strlen($string);
    if ($length == 5) {
      return 1;
    }
    
    return 0;
  }

  native sub native_use_strlen : int ($string : string);

  native sub native_env_bfield : byte ($test_case : TestCase);
  native sub native_env_sfield : short ($test_case : TestCase);
  native sub native_env_ifield : int ($test_case : TestCase);
  native sub native_env_lfield : long ($test_case : TestCase);
  native sub native_env_ffield : float ($test_case : TestCase);
  native sub native_env_dfield : double ($test_case : TestCase);
  native sub native_env_ofield : TestCase::Minimal ($test_case : TestCase);
  
  sub native_env_set_field : int () {
    
    my $test_case = TestCase->new();
    
    $test_case->{x_byte} = (byte)1;
    $test_case->{x_short} = (short)2;
    $test_case->{x_int} = 3;
    $test_case->{x_long} = 4L;
    $test_case->{x_float} = 0.5f;
    $test_case->{x_double} = 0.025;
    my $minimal1 = TestCase::Minimal->new();
    $test_case->{minimal} = $minimal1;
    
    my $x_byte1 = native_env_bfield($test_case);
    my $x_short1 = native_env_sfield($test_case);
    my $x_int1 = native_env_ifield($test_case);
    my $x_long1 = native_env_lfield($test_case);
    my $x_float1 = native_env_ffield($test_case);
    my $x_double1 = native_env_dfield($test_case);
    my $minimal2 = native_env_ofield($test_case);
    
    if ((int)$x_byte1 == (int)(byte)1) {
      if ((int)$x_short1 == (int)(short)2) {
        if ($x_int1 == 3) {
          if ($x_long1 == 4L) {
            if ($x_float1 == 0.5f) {
              if ($x_double1 == 0.025) {
                if ($minimal1 == $minimal2) {
                  return 1;
                }
              }
            }
          }
        }
      }
    }
  }

  native sub sum : int ($num1 : int, $num2 : int);
  
  native sub add_iarray : int[] ($nums1 : int[], $nums2 : int[]);

  sub call_void_sub_exception : int () {
    eval {
      call_void_sub_exception_native();
    };
    
    if ($@) {
      return 1;
    }
    
    return 0;
  }

  sub call_byte_sub_exception : int () {
    eval {
      call_byte_sub_exception_native();
    };
    
    if ($@) {
      return 1;
    }
    
    return 0;
  }

  sub call_short_sub_exception : int () {
    eval {
      call_short_sub_exception_native();
    };
    
    if ($@) {
      return 1;
    }
    
    return 0;
  }

  sub call_int_sub_exception : int () {
    eval {
      call_int_sub_exception_native();
    };
    
    if ($@) {
      return 1;
    }
    
    return 0;
  }

  sub call_long_sub_exception : int () {
    eval {
      call_long_sub_exception_native();
    };
    
    if ($@) {
      return 1;
    }
    
    return 0;
  }

  sub call_float_sub_exception : int () {
    eval {
      call_float_sub_exception_native();
    };
    
    if ($@) {
      return 1;
    }
    
    return 0;
  }

  sub call_double_sub_exception : int () {
    eval {
      call_double_sub_exception_native();
    };
    
    if ($@) {
      return 1;
    }
    
    return 0;
  }
  
  sub call_object_sub_exception : int () {
    eval {
      call_object_sub_exception_native();
    };
    
    if ($@) {
      return 1;
    }
    
    return 0;
  }
  
  native sub call_void_sub_exception_native : void ();
  native sub call_byte_sub_exception_native : byte ();
  native sub call_short_sub_exception_native : short ();
  native sub call_int_sub_exception_native : int ();
  native sub call_long_sub_exception_native : long ();
  native sub call_float_sub_exception_native : float ();
  native sub call_double_sub_exception_native : double ();
  native sub call_object_sub_exception_native : double ();

  
  native sub mortal_api : int ();
  native sub enter_scope_leave_scope : int ();
  
  sub my_value : int ($value : int) { return $value; }
  
  native sub native_call_sub : int ();
}
