Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-54652

[Groovy] Invalid switch case flow on empty "block"

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Open (View Workflow)
    • Priority: Minor
    • Resolution: Unresolved
    • Environment:
    • Similar Issues:

      Description

      In standard C-based language (such as Java, Groovy, ...), switch cases ends with break keyword. When there's no statement that break the flow, the next case is executed. For example:

      String value = "foo";
      switch (value) {
          case "rab":
              System.out.println("rab");
          case "oof":
              System.out.println("oof");
              break;
      
          case "foo":
              System.out.println("foo");
          case "bar":
              System.out.println("bar");
              break;
      }
      

      It must print "foobar".

      However, following pipeline prints: 1, null and 2.

      def switchCase(value) {
      	switch (value) {
      		case 'foo':
      			return 1
      		case 'bar':
      		default:
      			return 2
      	}
      }
      
      pipeline {
      	agent any
      
      	options {
      		buildDiscarder(logRotator(numToKeepStr:'5'))
      		disableConcurrentBuilds()
      		timestamps()
      		skipDefaultCheckout()
      	}
      
      	stages {
      		stage('Switch') {
      			steps {
      				echo "foo  -> '${switchCase('foo')}'"
      				echo "bar  -> '${switchCase('bar')}'"
      				echo "null -> '${switchCase(null)}'"
      			}
      		}
      	}
      }
      

      You can check its valid on Groovy through: https://groovyconsole.appspot.com/

        Attachments

          Activity

          Hide
          gdemengin Guillaume DeMengin added a comment - - edited

          still failing with 2.303.2

          actually the issue is with default statement only, this code is failing on the last assert 

          // test default
          
          test0_reached_case1 = false
          test0_reached_case2 = false
          test0_reached_default = false
          a = 0
          switch(a) {
              case 1:
                  test0_reached_case1 = true
                  break
              case 2:
                  test0_reached_case2 = true
                  break
              default:
                  test0_reached_default = true
          }
          assert ! test0_reached_case1
          assert ! test0_reached_case2
          assert test0_reached_default
          
          
          // test break
          
          test1_reached_case1 = false
          test1_reached_case2 = false
          test1_reached_default = false
          a = 1
          switch(a) {
              case 1:
                  test1_reached_case1 = true
                  break
              case 2:
                  test1_reached_case2 = true
                  break
              default:
                  test1_reached_default = true
          }
          assert test1_reached_case1
          assert ! test1_reached_case2
          assert ! test1_reached_default
          
          
          // test no break between 2 cases
          
          test2_reached_case1 = false
          test2_reached_case2 = false
          test2_reached_default = false
          a = 1
          switch(a) {
              case 1:
                  test2_reached_case1 = true
              case 2:
                  test2_reached_case2 = true
                  break
              default:
                  test2_reached_default = true
          }
          assert test2_reached_case1
          assert test2_reached_case2
          assert ! test2_reached_default
          
          
          // test no break before default
          
          test3_reached_case1 = false
          test3_reached_case2 = false
          test3_reached_case3 = false
          test3_reached_default = false
          a = 1
          switch(a) {
              case 1:
                  test3_reached_case1 = true
              case 2:
                  test3_reached_case2 = true
              case 3:
                  test3_reached_case3 = true
              default:
                  test3_reached_default = true
          }
          assert test3_reached_case1
          assert test3_reached_case2
          assert test3_reached_case3
          
          // it fails here
          assert test3_reached_default
          
          print 'happy End!'
          

          we lost countless hours before realizing that the code to handle unexpected cases below default should be repeated under the last case statement

           

          how can it be "Minor" ? code is not doing what it's supposed to do , and using default as a fallback is pretty common in swith cases.

          Show
          gdemengin Guillaume DeMengin added a comment - - edited still failing with 2.303.2 actually the issue is with default statement only, this code is failing on the last assert  // test default test0_reached_case1 = false test0_reached_case2 = false test0_reached_default = false a = 0 switch (a) { case 1: test0_reached_case1 = true break case 2: test0_reached_case2 = true break default : test0_reached_default = true } assert ! test0_reached_case1 assert ! test0_reached_case2 assert test0_reached_default // test break test1_reached_case1 = false test1_reached_case2 = false test1_reached_default = false a = 1 switch (a) { case 1: test1_reached_case1 = true break case 2: test1_reached_case2 = true break default : test1_reached_default = true } assert test1_reached_case1 assert ! test1_reached_case2 assert ! test1_reached_default // test no break between 2 cases test2_reached_case1 = false test2_reached_case2 = false test2_reached_default = false a = 1 switch (a) { case 1: test2_reached_case1 = true case 2: test2_reached_case2 = true break default : test2_reached_default = true } assert test2_reached_case1 assert test2_reached_case2 assert ! test2_reached_default // test no break before default test3_reached_case1 = false test3_reached_case2 = false test3_reached_case3 = false test3_reached_default = false a = 1 switch (a) { case 1: test3_reached_case1 = true case 2: test3_reached_case2 = true case 3: test3_reached_case3 = true default : test3_reached_default = true } assert test3_reached_case1 assert test3_reached_case2 assert test3_reached_case3 // it fails here assert test3_reached_default print 'happy End!' we lost countless hours before realizing that the code to handle unexpected cases below default should be repeated under the last case statement   how can it be "Minor" ? code is not doing what it's supposed to do , and using default as a fallback is pretty common in swith cases.

            People

            Assignee:
            Unassigned Unassigned
            Reporter:
            loganmzz Logan Mzz
            Votes:
            2 Vote for this issue
            Watchers:
            3 Start watching this issue

              Dates

              Created:
              Updated: