class TestCase::Statement::Switch {
  
  enum {
    VALUE0,
    VALUE1,
    VALUE2,
  }

  static method switch : int () {
    
    # switch basec patterns
    {
      {
        my $success : int;
        switch (1) {
          case 1: {
            $success = 1;
            break;
          }
          case 3: {
            $success = 0;
            break;
          }
          case 10000: {
            $success = 0;
            break;
          }
          default:
        }
        unless ($success) {
          return 0;
        }
      }
      
      {
        my $success : int;
        switch (3) {
          case 1: {
            $success = 0;
            break;
          }
          case 3: {
            $success = 1;
            break;
          }
          case 10000: {
            $success = 0;
            break;
          }
          default:
        }
        unless ($success) {
          return 0;
        }
      }
      
      {
        my $success : int;
        switch (10000) {
          case 3: {
            $success = 0;
            break;
          }
          case 1: {
            $success = 0;
            break;
          }
          case 10000: {
            $success = 1;
            break;
          }
          default:
        }
        unless ($success) {
          return 0;
        }
      }
      
      {
        my $success4 : int;
        switch (2) {
          case 1: {
            break;
          }
          case 3: {
            break;
          }
          case 10000: {
            break;
          }
          default: {
            $success4 = 1;
          }
        }
        unless ($success4) {
          return 0;
        }
      }

      {
        my $success : int;
        
        switch(3) {
          case 3: {
            $success = 1;
            break;
          }
          case 4: {
            $success = 0;
            break;
          }
          case 5: {
            $success = 0;
            break;
          }
          default:
        }
        unless ($success) {
          return 0;
        }
      }
      
      {
        my $success : int;
        switch(4) {
          case 3: {
            $success = 0;
            break;
          }
          case 4: {
            $success = 1;
            break;
          }
          case 5: {
            $success = 0;
            break;
          }
          default:
        }
        unless ($success) {
          return 0;
        }
      }
      
      {
        my $success : int;
        switch(10) {
          case 3: {
            $success = 0;
            break;
          }
          case 4: {
            $success = 0;
            break;
          }
          case 5: {
            $success = 0;
            break;
          }
          default: {
            $success = 1;
          }
        }
        unless ($success) {
          return 0;
        }
      }
      
      # Only default
      {
        my $success : int;
        switch (1) {
          default: {
            $success = 1;
          }
        }
        unless ($success) {
          return 0;
        }
      }

      # No cases and default
      {
        my $success = 0;
        switch (1) {}
        $success = 1;
        unless ($success) {
          return 0;
        }
      }

      # No cases and default
      {
        my $success = 0;
        switch ((byte)1) {
          case 1: {
            $success = 1;
            break;
          }
        }
        unless ($success) {
          return 0;
        }
      }

      # break is added to the end of the block if it doesn't exist
      {
        my $success = 0;
        switch (1) {
          case 1: {
            $success = 1;
          }
          case 2: {
            $success = 2;
          }
        }
        unless ($success == 1) {
          return 0;
        }
      }
      {
        my $success = 0;
        switch (1) {
          case 1: {}
          case 2: {
            $success = 2;
          }
        }
        unless ($success == 0) {
          return 0;
        }
      }

      # break in default
      {
        my $success = 0;
        switch (1) {
          default: {
            $success = 1;
            break;
            $success = 2;
          }
        }
        unless ($success == 1) {
          return 0;
        }
      }
    }
    
    # Minus value
    {
      my $success : int;
      switch (-1) {
        case -1: {
          $success = 1;
          break;
        }
        case 3: {
          $success = 0;
          break;
        }
        case 10000: {
          $success = 0;
          break;
        }
        default:
      }
      unless ($success) {
        return 0;
      }
    }

    # int max
    {
      my $success : int;
      switch (2147483647) {
        case 2147483647: {
          $success = 1;
          break;
        }
        case 3: {
          $success = 0;
          break;
        }
        case 10000: {
          $success = 0;
          break;
        }
        default:
      }
      unless ($success) {
        return 0;
      }
    }

    # int min
    {
      my $success : int;
      switch (-2147483648) {
        case -2147483648: {
          $success = 1;
          break;
        }
        case 3: {
          $success = 0;
          break;
        }
        case 10000: {
          $success = 0;
          break;
        }
        default:
      }
      unless ($success) {
        return 0;
      }
    }
    
    # return statement in switch statement
    {
      my $ret = TestCase::Statement::Switch->switch_return_method();
      
      unless ($ret == 5) {
        return 0;
      }
    }
    
    # No default branch
    {
      my $i = 0;
      switch ($i) {
        case 1: {
          1;
          break;
        }
      }
      my $p = 5;
      
      unless ($p == 5) {
        return 0;
      }
    }
    
    # The operand type of case statement is byte type
    {
      my $char = (int)'[';
      
      my $success = 0;
      switch ($char) {
        case 3: {
          break;
        }
        case ']': {
          break;
        }
        case '[': {
          $success = 1;
          break;
        }
      }
      
      unless ($success) {
        return 0;
      }
    }
    
    # Nested switch statements
    {
      my $success : int;
      switch (3) {
        case 1: {
          $success = 0;
          break;
        }
        case 3: {
          switch (5) {
            case 2: {
              $success = 0;
              break;
            }
            case 5: {
              $success = 1;
              break;
            }
            case 6: {
              $success = 0;
              break;
            }
            default: {
              $success = 0;
              break;
            }
          }
          break;
        }
        case 10000: {
          $success = 0;
          break;
        }
        default:
      }
      
      unless ($success) {
        return 0;
      }
    }
    
    # default statement
    {
      # default statement
      {
        {
          my $num = 1;
          my $value = 3;
          switch ($num) {
            case 2 : {
              $value = 5;
              break;
            }
            default : {
              $value = 7;
            }
          }
          unless ($value == 7) {
            return 0;
          }
        }
        {
          my $num = 1;
          my $value = 3;
          switch ($num) {
            case 2 : {
              $value = 5;
              break;
            }
            case 3 : {
              $value = 5;
              break;
            }
            default : {
              $value = 7;
            }
          }
          unless ($value == 7) {
            return 0;
          }
        }
        {
          my $num = 1;
          my $value = 3;
          switch ($num) {
            case 2 : {
              $value = 5;
              break;
            }
            case 3 : {
              $value = 5;
              break;
            }
            case 4 : {
              $value = 5;
              break;
            }
            default : {
              $value = 7;
            }
          }
          unless ($value == 7) {
            return 0;
          }
        }
      }

      # no default statement
      {
        {
          my $num = 1;
          my $value = 3;
          switch ($num) {
            case 2 : {
              $value = 5;
              break;
            }
          }
          unless ($value == 3) {
            return 0;
          }
        }
        {
          my $num = 1;
          my $value = 3;
          switch ($num) {
            case 2 : {
              $value = 5;
              break;
            }
            case 3 : {
              $value = 5;
              break;
            }
          }
          unless ($value == 3) {
            return 0;
          }
        }
        {
          my $num = 1;
          my $value = 3;
          switch ($num) {
            case 2 : {
              $value = 5;
              break;
            }
            case 3 : {
              $value = 5;
              break;
            }
            case 4 : {
              $value = 5;
              break;
            }
          }
          unless ($value == 3) {
            return 0;
          }
        }
      }
    }
    
    # Enumeration
    {
      my $success : int;
      switch (1) {
        case &VALUE0: {
          $success = 0;
          break;
        }
        case &VALUE1: {
          $success = 1;
          break;
        }
        case &VALUE2: {
          $success = 0;
          break;
        }
        default:
      }
      unless ($success) {
        return 0;
      }
    }

    # Character literal
    {
      my $success : int;
      switch ('b') {
        case 'a': {
          $success = 0;
          break;
        }
        case 'b': {
          $success = 1;
          break;
        }
        case 'c': {
          $success = 0;
          break;
        }
        default: {
          warn "DDDDDD";
        }
      }
      unless ($success) {
        return 0;
      }
    }

    # Multiple case values at once
    {
      my $total = 0;
      for (my $i = 0; $i < 2; $i++) {
        switch ($i) {
          case 0 :
          case 1 :
          {
            $total++;
          }
        }
      }
      unless ($total == 2) {
        return 0;
      }
    }
    
    return 1;
  }
  static method switch_extra : int () {
    
    {
      # If a case statement exists and default doesn't exist, wrong branch is executed.
      {
        my $num = 1;
        my $branch_first_case = 0;
        switch ($num) {
          case 2 : {
            1; # If a statement exists and default doesn't exist, this branch is executed.
            $branch_first_case = 1;
            break;
          }
        }
        if ($branch_first_case) {
          return 0;
        }
      }
      
      # Add default in above case
      {
        my $num = 1;
        my $branch_first_case = 0;
        switch ($num) {
          case 2 : {
            1; # If a statement exists and default doesn't exist, this branch is executed.
            $branch_first_case = 1;
            break;
          }
          default : {}
        }
        if ($branch_first_case) {
          return 0;
        }
      }
      
      # break in while satement
      {
        my $num = 0;
        my $result = 0;
        switch ($num) {
          case 0: {
            while (1) {
              $result = 1;
              break;
            }
            $result = 2;
          }
        }
        unless ($result == 1) {
          return 0;
        }
      }

      # break in for satement
      {
        my $num = 0;
        my $result = 0;
        switch ($num) {
          case 0: {
            for (my $i = 0; $i < 5; $i++) {
              $result = 1;
              break;
            }
            $result = 2;
          }
        }
        unless ($result == 1) {
          return 0;
        }
      }

      # break in if satement
      {
        my $num = 0;
        my $result = 0;
        switch ($num) {
          case 0: {
            if (1) {
              $result = 1;
              break;
            }
            $result = 2;
          }
        }
        unless ($result == 1) {
          return 0;
        }
      }
      
    }
    
    return 1;
  }
  
  static method switch_return_method : int () {
    my $i = 2;
    switch ($i) {
      case 1: {
        return 3;
      }
      case 2: {
        return 5;
      }
    }
  }
}
