package TestCase::Lib::SPVM::ShortList {
  use SPVM::ShortList;
  use SPVM::ArrayUtil (equals_array_short);
  use SPVM::NumberUtil (INT8_MIN, INT8_MAX, INT16_MIN, INT16_MAX, INT32_MIN, INT32_MAX, INT64_MIN, INT64_MAX, FLT_MIN, FLT_MAX, DBL_MIN, DBL_MAX);

  sub new : int () {
    {
      my $list = SPVM::ShortList->new([(short)3, 5, INT16_MAX()]);
      
      unless ($list->get(0) == 3) {
        return 0;
      }
      
      unless ($list->get(1) == 5) {
        return 0;
      }

      unless ($list->get(2) == INT16_MAX()) {
        return 0;
      }
      
      my $length = $list->length;
      unless ($length == 3) {
        return 0;
      }
    }

    # new with undef
    {
      my $list = SPVM::ShortList->new(undef);
      
      unless ($list->length == 0) {
        return 0;
      }
    }
    
    
    return 1;
  }

  sub new_len : int () {
    {
      my $list = SPVM::ShortList->new_len(32);
      
      unless ($list->length == 32) {
        return 0;
      }
    }
    
    return 1;
  }

  sub insert : int () {
    # Insert to first
    {
      my $list = SPVM::ShortList->new([(short)1, 2, 3]);
      $list->insert(0 => 4);
      unless (equals_array_short($list->to_array, [(short)4, 1, 2, 3])) {
        return 0;
      }
    }

    # Insert
    {
      my $list = SPVM::ShortList->new([(short)1, 2, 3]);
      $list->insert(2 => 4);
      unless (equals_array_short($list->to_array, [(short)1, 2, 4, 3])) {
        return 0;
      }
    }

    # Insert to last
    {
      my $list = SPVM::ShortList->new([(short)1, 2, 3]);
      $list->insert(3 => 4);
      unless (equals_array_short($list->to_array, [(short)1, 2, 3, 4])) {
        return 0;
      }
    }

    # Extend
    {
      my $list = SPVM::ShortList->new([(short)1, 2, 3]);
      $list->insert(0 => 4);
    }
    
    # Exception - insert to -1
    eval {
      my $list = SPVM::ShortList->new([(short)1, 2, 3]);
      $list->insert(-1 => 2);
    };
    unless ($@) {
      return 0;
    }
    $@ = undef;

    # Exception - insert to length + 1
    eval {
      my $list = SPVM::ShortList->new([(short)1, 2, 3]);
      $list->insert(4 => 2);
    };
    unless ($@) {
      return 0;
    }
    $@ = undef;
    
    return 1;
  }

  sub remove : int () {
    # Remove
    {
      my $list = SPVM::ShortList->new([(short)1, 2, 3, 4]);
      my $value = $list->remove(1);
      unless (equals_array_short($list->to_array, [(short)1, 3, 4])) {
        return 0;
      }
      unless ($value == 2) {
        return 0;
      }
    }

    # Remove last
    {
      my $list = SPVM::ShortList->new([(short)1, 2, 3]);
      $list->remove(2);
      unless (equals_array_short($list->to_array, [(short)1, 2])) {
        return 0;
      }
    }

    # Remove first
    {
      my $list = SPVM::ShortList->new([(short)1, 2, 3]);
      $list->remove(0);
      unless (equals_array_short($list->to_array, [(short)2, 3])) {
        return 0;
      }
    }

    # Exception - remove to -1
    eval {
      my $list = SPVM::ShortList->new([(short)1, 2, 3]);
      $list->remove(-1);
    };
    unless ($@) {
      return 0;
    }
    $@ = undef;

    # Exception - remove to length
    eval {
      my $list = SPVM::ShortList->new([(short)1, 2, 3]);
      $list->remove(3);
    };
    unless ($@) {
      return 0;
    }
    $@ = undef;
    
    return 1;
  }

  sub to_array : int () {
    {
      my $list = SPVM::ShortList->new([(short)3, 5, INT16_MAX()]);
      
      my $array = $list->to_array;
      
      unless ($array isa short[]) {
        return 0;
      }
      
      unless ($array->[0] == 3) {
        return 0;
      }

      unless ($array->[1] == 5) {
        return 0;
      }

      unless ($array->[2] == INT16_MAX()) {
        return 0;
      }
      
      my $length = @$array;
      unless ($length == 3) {
        return 0;
      }
    }
    
    return 1;
  }

  sub get : int () {
    {
      my $list = SPVM::ShortList->new([(short)3, 5, INT16_MAX()]);
      
      unless ($list->get(0) == 3) {
        return 0;
      }

      unless ($list->get(0) isa short) {
        return 0;
      }

      unless ($list->get(1) == 5) {
        return 0;
      }

      unless ($list->get(2) == INT16_MAX()) {
        return 0;
      }
      
      my $length = $list->length;
      unless ($length == 3) {
        return 0;
      }
      
      eval {
        $list->get(-1);
      };
      unless ($@) {
        return 0;
      }
      
      eval {
        $list->get(3);
      };
      unless ($@) {
        return 0;
      }
      
      $@ = undef;
    }
    
    return 1;
  }

  sub set : int () {
    {
      my $list = SPVM::ShortList->new([(short)0, 0, 0]);
      
      $list->set(0 => 3);
      $list->set(1 => 5);
      $list->set(2 => INT16_MAX());
      
      unless ($list->get(0) == 3) {
        return 0;
      }

      unless ($list->get(1) == 5) {
        return 0;
      }

      unless ($list->get(2) == INT16_MAX()) {
        return 0;
      }
      
      my $length = $list->length;
      unless ($length == 3) {
        return 0;
      }
      
      eval {
        $list->get(-1);
      };
      unless ($@) {
        return 0;
      }
      
      eval {
        $list->get(3);
      };
      unless ($@) {
        return 0;
      }
      
      $@ = undef;
    }
    
    return 1;
  }

  sub set_array : int () {
    # Set array
    {
      my $list = SPVM::ShortList->new([(short)1, 2, 3]);
      $list->set_array([(short)3, 4, 5]);
      unless (SPVM::ArrayUtil->equals_array_short($list->to_array, [(short)3, 4, 5])) {
        return 0;
      }
    }
    
    # Exception - Array must be defined
    {
      my $list = SPVM::ShortList->new([(short)1, 2, 3]);
      eval { $list->set_array(undef); };
      unless ($@) {
        return 0;
      }
    }

    # Exception - The length of argument array must be same as the length of current list array
    {
      my $list = SPVM::ShortList->new([(short)1, 2, 3]);
      eval { $list->set_array([(short)1, 2, 3, 4]); };
      unless ($@) {
        return 0;
      }
    }
    
    $@ = undef;
    
    return 1;
  }

  sub push : int () {
    # push
    {
      my $list = SPVM::ShortList->new_len(0);
      
      $list->push(3);
      $list->push(5);
      $list->push(INT16_MAX());
      
      my $length = $list->length;
      unless ($length == 3) {
        return 0;
      }
      
      unless ($list->get(0) == 3 && $list->get(1) == 5 && $list->get(2) == INT16_MAX()) {
        return 0;
      }
    }
    
    # internal _extend tests
    {
      my $list = SPVM::ShortList->new_len(0);
      
      for (my $i = 0; $i < 100; $i++) {
        $list->push(1);
      }
      
      my $length = $list->length;
      unless ($length == 100) {
        return 0;
      }
      
      for (my $i = 0; $i < 100; $i++) {
        unless ($list->get($i) == 1) {
          return 0;
        }
      }
    }
    
    
    return 1;
  }

  sub pop : int () {
    # pop
    {
      my $list = SPVM::ShortList->new_len(0);
      
      $list->push(3);
      $list->push(5);
      $list->push(INT16_MAX());
      
      my $pop0 = $list->pop;
      unless ($pop0 == INT16_MAX()) {
        return 0;
      }
      unless ($pop0 isa short) {
        return 0;
      }

      unless ($list->pop == 5) {
        return 0;
      }

      unless ($list->pop == 3) {
        return 0;
      }
      
      my $length = $list->length;
      unless ($length == 0) {
        return 0;
      }
      
      eval {
        $list->pop;
      };
      unless ($@) {
        return 0;
      }
      $@ = undef;
    }
    
    return 1;
  }

  sub unshift : int () {
    # unshift
    {
      my $list = SPVM::ShortList->new_len(0);
      
      $list->unshift(3);
      $list->unshift(5);
      $list->unshift(INT16_MAX());
      
      my $length = $list->length;
      unless ($length == 3) {
        return 0;
      }
      
      unless ($list->get(0) == INT16_MAX() && $list->get(1) == 5 && $list->get(2) == 3) {
        return 0;
      }
    }
    
    # internal _extend tests
    {
      my $list = SPVM::ShortList->new_len(0);
      
      for (my $i = 0; $i < 100; $i++) {
        $list->unshift(1);
      }
      
      my $length = $list->length;
      unless ($length == 100) {
        return 0;
      }
      
      for (my $i = 0; $i < 100; $i++) {
        unless ($list->get($i) == 1) {
          return 0;
        }
      }
    }
    
    return 1;
  }

  sub shift : int () {
    # shift
    {
      my $list = SPVM::ShortList->new_len(0);
      
      $list->unshift(3);
      $list->unshift(5);
      $list->unshift(INT16_MAX());
      
      unless ($list->shift == INT16_MAX()) {
        return 0;
      }

      unless ($list->shift == 5) {
        return 0;
      }

      unless ($list->shift == 3) {
        return 0;
      }
      
      my $length = $list->length;
      unless ($length == 0) {
        return 0;
      }
      
      eval {
        $list->shift;
      };
      unless ($@) {
        return 0;
      }
      $@ = undef;
    }
    
    return 1;
  }

  sub length : int () {
    # length
    {
      my $list = SPVM::ShortList->new_len(0);
      
      $list->unshift(3);
      $list->unshift(5);
      $list->unshift(INT16_MAX());
      
      my $length = $list->length;
      unless ($length == 3) {
        return 0;
      }
    }
    
    return 1;
  }

  sub resize : int () {
    my $a = (short)1;
    my $b = (short)2;
    my $c = (short)3;

    # 3 to 3
    {
      my $list = SPVM::ShortList->new(new short[0]);
      $list->push($a);
      $list->push($b);
      $list->push($c);
      $list->resize(3);
      unless ($list->length == 3) {
        return 0;
      }
      unless ($list->get(0) == $a && $list->get(1) == $b && $list->get(2) == $c) {
        return 0;
      }
    }
    
    # 3 to 0
    {
      my $list = SPVM::ShortList->new(new short[0]);
      $list->push($a);
      $list->push($b);
      $list->push($c);
      $list->resize(0);
      unless ($list->length == 0) {
        return 0;
      }
    }

    
    # 3 to 4
    {
      my $list = SPVM::ShortList->new(new short[0]);
      $list->push($a);
      $list->push($b);
      $list->push($c);
      $list->resize(4);
      unless ($list->length == 4) {
        return 0;
      }
      unless ($list->get(3) == 0 && $list->get(0) == $a && $list->get(1) == $b && $list->get(2) == $c) {
        return 0;
      }
    }
    
    # 3 to 32(over capacity)
    {
      my $list = SPVM::ShortList->new(new short[0]);
      $list->push($a);
      $list->push($b);
      $list->push($c);
      $list->resize(32);
      unless ($list->length == 32) {
        return 0;
      }
      unless ($list->get(3) == 0 && $list->get(31) == 0) {
        return 0;
      }
    }

    # 3 to 2 and 2 to 3 again
    {
      my $list = SPVM::ShortList->new([(short)1, 2, 3]);
      $list->resize(2);
      unless ($list->length == 2) {
        return 0;
      }
      
      $list->resize(3);
      unless ($list->length == 3) {
        return 0;
      }
      unless ($list->get(2) == 0) {
        return 0;
      }
    }
    
    # Exception - New length must be more than or equals to 0
    {
      my $list = SPVM::ShortList->new(new short[0]);
      $list->push($a);
      $list->push($b);
      $list->push($c);
      eval { $list->resize(-1); };
      unless ($@) {
        return 0;
      }
    }
    
    $@ = undef;
    return 1;
  }

}