package TestCase::Weaken {
  use TestCase::Data::Weaken;
  
  has x_int : int;
  has x_self : TestCase::Weaken;
  has x_weaken : TestCase::Data::Weaken;
  has weaken1 : TestCase::Data::Weaken;
  has weaken2 : TestCase::Data::Weaken;
  has weaken3 : TestCase::Data::Weaken;
  has weaken4 : TestCase::Data::Weaken;

  sub weaken_field_cross_reference_weaken_both : int () {
    my $weaken1 = new TestCase::Data::Weaken;
    $weaken1->{x} = 1;

    my $weaken2 = new TestCase::Data::Weaken;
    $weaken2->{x} = 2;
    
    # Cross reference
    $weaken1->{data_weaken} = $weaken2;
    $weaken2->{data_weaken} = $weaken1;
    
    # Weaken both
    weaken $weaken2->{data_weaken};
    
    return 0;
  }

  sub weaken_field_cross_reference : int () {
    my $weaken1 = new TestCase::Data::Weaken;
    $weaken1->{x} = 1;
    
    my $weaken2 = new TestCase::Data::Weaken;
    $weaken2->{x} = 2;
    
    # Cross reference
    $weaken1->{data_weaken} = $weaken2;
    $weaken2->{data_weaken} = $weaken1;
    
    # Weaken
    weaken $weaken1->{data_weaken};
    
    # Exists object
    if ($weaken1->{x} == 1) {
      if ($weaken2->{x} == 2) {
        return 1;
      }
    }
    return 0;
  }

  sub weaken_field_cross_reference_weaken_twice : int () {
    my $weaken1 = new TestCase::Data::Weaken;
    $weaken1->{x} = 1;

    my $weaken2 = new TestCase::Data::Weaken;
    $weaken2->{x} = 2;
    
    # Cross reference
    $weaken1->{data_weaken} = $weaken2;
    $weaken2->{data_weaken} = $weaken1;
    
    # Weaken twice
    weaken $weaken1->{data_weaken};
    weaken $weaken1->{data_weaken};

    # Exists object
    if ($weaken1->{x} == 1) {
      if ($weaken2->{x} == 2) {
        return 1;
      }
    }
    
    return 0;
  }

  sub weaken_field_self_reference : int () {
    my $self = new TestCase::Weaken;
    $self->{x_int} = 5;
    
    # Self reference
    $self->{x_self} = $self;
    
    # Weaken
    weaken $self->{x_self};
    
    # Exists object
    if ($self->{x_int} == 5) {
      return 1;
    }
    
    return 0;
  }

  sub weaken_field_weaken_ref_count1_object : int () {
    my $weaken1 = new TestCase::Data::Weaken;
    my $weaken2 = new TestCase::Data::Weaken;
    
    $weaken2->{data_weaken} = $weaken1;
    
    # object reference count become 1.
    $weaken1 = undef;
    
    # Weaken(data_weaken is freed because data_weaken reference count is 1);
    weaken $weaken2->{data_weaken};
    
    if ($weaken2->{data_weaken} == undef) {
      return 1;
    }
    
    return 0;
  }

  sub weaken_field_circular_reference : int () {
    my $weaken1 = new TestCase::Data::Weaken;
    $weaken1->{x} =1;
    
    my $weaken2 = new TestCase::Data::Weaken;
    $weaken2->{x} = 2;
    
    my $weaken3 = new TestCase::Data::Weaken;
    $weaken3->{x} = 3;
    
    # Circular reference
    $weaken3->{data_weaken} = $weaken1;
    $weaken1->{data_weaken} = $weaken2;
    $weaken2->{data_weaken} = $weaken3;
    
    # Weaken
    weaken $weaken3->{data_weaken};
    
    if ($weaken1->{x} == 1 && $weaken2->{x} == 2 && $weaken3->{x} == 3) {
      return 1;
    }
    
    return 0;
  }

  sub weaken_field_circular_reference_weaken_twice : int () {
    my $weaken1 = new TestCase::Data::Weaken;
    $weaken1->{x} =1;
    
    my $weaken2 = new TestCase::Data::Weaken;
    $weaken2->{x} = 2;
    
    my $weaken3 = new TestCase::Data::Weaken;
    $weaken3->{x} = 3;
    
    # Circular reference
    $weaken3->{data_weaken} = $weaken1;
    $weaken1->{data_weaken} = $weaken2;
    $weaken2->{data_weaken} = $weaken3;
    
    # Weaken
    weaken $weaken3->{data_weaken};
    weaken $weaken2->{data_weaken};
    
    if ($weaken1->{x} == 1 && $weaken2->{x} == 2 && $weaken3->{x} == 3) {
      return 1;
    }
    
    return 0;
  }

  sub weaken_field_circular_reference_weaken_triple : int () {
    my $weaken1 = new TestCase::Data::Weaken;
    $weaken1->{x} =1;
    
    my $weaken2 = new TestCase::Data::Weaken;
    $weaken2->{x} = 2;
    
    my $weaken3 = new TestCase::Data::Weaken;
    $weaken3->{x} = 3;
    
    # Circular reference
    $weaken3->{data_weaken} = $weaken1;
    $weaken1->{data_weaken} = $weaken2;
    $weaken2->{data_weaken} = $weaken3;
    
    # Weaken
    weaken $weaken3->{data_weaken};
    weaken $weaken2->{data_weaken};
    weaken $weaken1->{data_weaken};
    
    if ($weaken1->{x} == 1 && $weaken2->{x} == 2 && $weaken3->{x} == 3) {
      return 1;
    }
    
    return 0;
  }

  sub weaken_field_assign_undef_to_weakened_field : int () {
    my $weaken1 = new TestCase::Data::Weaken;
    
    my $weaken2 = new TestCase::Data::Weaken;
    $weaken2->{x} = 2;
    
    # Cross reference
    $weaken2->{data_weaken} = $weaken1;
    $weaken1->{data_weaken} = $weaken2;
    
    weaken $weaken2->{data_weaken};
    $weaken2->{data_weaken} = undef;
    
    if ($weaken2->{data_weaken} == undef) {
      if ($weaken2->{x} == 2) {
        return 1;
      }
    }
    return 0;
  }
  
  sub weaken_field_assign_undef_to_assinged_object : int () {
    my $weaken1 = new TestCase::Data::Weaken;
    my $weaken2 = new TestCase::Data::Weaken;

    $weaken2->{data_weaken} = $weaken1;
    $weaken1->{data_weaken} = $weaken2;
    
    weaken $weaken2->{data_weaken};
    $weaken1 = undef;
    
    if ($weaken2->{data_weaken} == undef) {
      return 1;
    }
    return 0;
  }

  sub weaken_field_cross_reference_array : int () {
    my $weakens = new TestCase::Data::Weaken[2];
    $weakens->[0] = new TestCase::Data::Weaken;
    $weakens->[0]{x} = 10;
    $weakens->[1] = new TestCase::Data::Weaken;
    $weakens->[1]{x} = 11;
    
    # Cross reference
    $weakens->[0]{data_weaken} = $weakens->[1];
    $weakens->[1]{data_weaken} = $weakens->[0];
    
    # Weaken
    weaken $weakens->[0]{data_weaken};
    
    # Exists object
    if ($weakens->[0]{x} == 10) {
      if ($weakens->[1]{x} == 11) {
        return 1;
      }
    }
    return 0;
  }

  sub weaken_field_undef : int () {
    my $weaken1 = new TestCase::Data::Weaken;
    weaken $weaken1->{data_weaken};
    
    unless ($weaken1->{data_weaken}) {
      return 1;
    }
    
    return 0;
  }

  sub weaken_field_cross_reference_assign_var : int () {
    my $weaken1 = new TestCase::Data::Weaken;
    $weaken1->{x} = 1;
    
    my $weaken2 = new TestCase::Data::Weaken;
    $weaken2->{x} = 2;
    
    # Cross reference
    $weaken1->{data_weaken} = $weaken2;
    $weaken2->{data_weaken} = $weaken1;
    
    # Weaken
    weaken $weaken1->{data_weaken};
    
    # Assign var($var isn't weak reference)
    my $var = $weaken1->{data_weaken};
    
    return 1;
  }

  sub weaken_array_element_cross_reference : int () {
    my $weaken1 = new TestCase::Data::Weaken;
    my $weaken2 = new TestCase::Data::Weaken;
    my $weakens = [$weaken1, $weaken2];
    
    $weakens->[0]{x} = 1;
    $weakens->[1]{x} = 2;
    
    # Weaken
    weaken $weakens->[0];
    
    if ($weakens->[0]{x} == 1 && $weakens->[1]{x} == 2) {
      return 1;
    }
    
    return 0;
  }

  sub weaken_array_element_circular_reference_with_many_cases : int () {
    my $weaken1 = new TestCase::Data::Weaken;
    my $weaken2 = new TestCase::Data::Weaken;
    my $weaken3 = new TestCase::Data::Weaken;
    my $weakens = [$weaken1, $weaken2, $weaken3];
    
    $weakens->[0]{x} = 1;
    $weakens->[1]{x} = 2;
    $weakens->[2]{x} = 3;
    
    # Weaken
    weaken $weakens->[0];
    weaken $weakens->[1];
    
    my $var = $weakens->[0];
    $weaken2 = undef;
    
    if ($weakens->[0]{x} == 1 && $weakens->[1]{x} == 2 && $weakens->[2]{x} == 3) {
      return 1;
    }
    
    return 0;
  }
  sub weaken_array_element_object_array : int () {
    my $objects1 = new object[1];
    my $objects2 = new object[2];
    
    $objects1->[0] = $objects2;
    $objects2->[0] = $objects1;
    
    weaken $objects1->[0];
    
    if ($objects1->[0] && $objects2->[0]) {
      return 1;
    }
  }
}
