// run

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Test switch statements.

package main

import "os"

func assert(cond bool, msg string) {
	if !cond {
		print("assertion fail: ", msg, "\n")
		panic(1)
	}
}

func main() {
	i5 := 5
	i7 := 7
	hello := "hello"

	switch true {
	case i5 < 5:
		assert(false, "<")
	case i5 == 5:
		assert(true, "!")
	case i5 > 5:
		assert(false, ">")
	}

	switch {
	case i5 < 5:
		assert(false, "<")
	case i5 == 5:
		assert(true, "!")
	case i5 > 5:
		assert(false, ">")
	}

	switch x := 5; true {
	case i5 < x:
		assert(false, "<")
	case i5 == x:
		assert(true, "!")
	case i5 > x:
		assert(false, ">")
	}

	switch x := 5; true {
	case i5 < x:
		assert(false, "<")
	case i5 == x:
		assert(true, "!")
	case i5 > x:
		assert(false, ">")
	}

	switch i5 {
	case 0:
		assert(false, "0")
	case 1:
		assert(false, "1")
	case 2:
		assert(false, "2")
	case 3:
		assert(false, "3")
	case 4:
		assert(false, "4")
	case 5:
		assert(true, "5")
	case 6:
		assert(false, "6")
	case 7:
		assert(false, "7")
	case 8:
		assert(false, "8")
	case 9:
		assert(false, "9")
	default:
		assert(false, "default")
	}

	switch i5 {
	case 0, 1, 2, 3, 4:
		assert(false, "4")
	case 5:
		assert(true, "5")
	case 6, 7, 8, 9:
		assert(false, "9")
	default:
		assert(false, "default")
	}

	switch i5 {
	case 0:
	case 1:
	case 2:
	case 3:
	case 4:
		assert(false, "4")
	case 5:
		assert(true, "5")
	case 6:
	case 7:
	case 8:
	case 9:
	default:
		assert(i5 == 5, "good")
	}

	switch i5 {
	case 0:
		dummy := 0
		_ = dummy
		fallthrough
	case 1:
		dummy := 0
		_ = dummy
		fallthrough
	case 2:
		dummy := 0
		_ = dummy
		fallthrough
	case 3:
		dummy := 0
		_ = dummy
		fallthrough
	case 4:
		dummy := 0
		_ = dummy
		assert(false, "4")
	case 5:
		dummy := 0
		_ = dummy
		fallthrough
	case 6:
		dummy := 0
		_ = dummy
		fallthrough
	case 7:
		dummy := 0
		_ = dummy
		fallthrough
	case 8:
		dummy := 0
		_ = dummy
		fallthrough
	case 9:
		dummy := 0
		_ = dummy
		fallthrough
	default:
		dummy := 0
		_ = dummy
		assert(i5 == 5, "good")
	}

	fired := false
	switch i5 {
	case 0:
		dummy := 0
		_ = dummy
		fallthrough // tests scoping of cases
	case 1:
		dummy := 0
		_ = dummy
		fallthrough
	case 2:
		dummy := 0
		_ = dummy
		fallthrough
	case 3:
		dummy := 0
		_ = dummy
		fallthrough
	case 4:
		dummy := 0
		_ = dummy
		assert(false, "4")
	case 5:
		dummy := 0
		_ = dummy
		fallthrough
	case 6:
		dummy := 0
		_ = dummy
		fallthrough
	case 7:
		dummy := 0
		_ = dummy
		fallthrough
	case 8:
		dummy := 0
		_ = dummy
		fallthrough
	case 9:
		dummy := 0
		_ = dummy
		fallthrough
	default:
		dummy := 0
		_ = dummy
		fired = !fired
		assert(i5 == 5, "good")
	}
	assert(fired, "fired")

	count := 0
	switch i5 {
	case 0:
		count = count + 1
		fallthrough
	case 1:
		count = count + 1
		fallthrough
	case 2:
		count = count + 1
		fallthrough
	case 3:
		count = count + 1
		fallthrough
	case 4:
		count = count + 1
		assert(false, "4")
	case 5:
		count = count + 1
		fallthrough
	case 6:
		count = count + 1
		fallthrough
	case 7:
		count = count + 1
		fallthrough
	case 8:
		count = count + 1
		fallthrough
	case 9:
		count = count + 1
		fallthrough
	default:
		assert(i5 == count, "good")
	}
	assert(fired, "fired")

	switch hello {
	case "wowie":
		assert(false, "wowie")
	case "hello":
		assert(true, "hello")
	case "jumpn":
		assert(false, "jumpn")
	default:
		assert(false, "default")
	}

	fired = false
	switch i := i5 + 2; i {
	case i7:
		fired = true
	default:
		assert(false, "fail")
	}
	assert(fired, "var")

	// switch on nil-only comparison types
	switch f := func() {}; f {
	case nil:
		assert(false, "f should not be nil")
	default:
	}

	switch m := make(map[int]int); m {
	case nil:
		assert(false, "m should not be nil")
	default:
	}

	switch a := make([]int, 1); a {
	case nil:
		assert(false, "m should not be nil")
	default:
	}

	// switch on interface.
	switch i := interface{}("hello"); i {
	case 42:
		assert(false, `i should be "hello"`)
	case "hello":
		assert(true, "hello")
	default:
		assert(false, `i should be "hello"`)
	}

	// switch on implicit bool converted to interface
	// was broken: see issue 3980
	switch i := interface{}(true); {
	case i:
		assert(true, "true")
	case false:
		assert(false, "i should be true")
	default:
		assert(false, "i should be true")
	}

	// switch on interface with constant cases differing by type.
	// was rejected by compiler: see issue 4781
	type T int
	type B bool
	type F float64
	type S string
	switch i := interface{}(float64(1.0)); i {
	case nil:
		assert(false, "i should be float64(1.0)")
	case (*int)(nil):
		assert(false, "i should be float64(1.0)")
	case 1:
		assert(false, "i should be float64(1.0)")
	case T(1):
		assert(false, "i should be float64(1.0)")
	case F(1.0):
		assert(false, "i should be float64(1.0)")
	case 1.0:
		assert(true, "true")
	case "hello":
		assert(false, "i should be float64(1.0)")
	case S("hello"):
		assert(false, "i should be float64(1.0)")
	case true, B(false):
		assert(false, "i should be float64(1.0)")
	case false, B(true):
		assert(false, "i should be float64(1.0)")
	}

	// switch on array.
	switch ar := [3]int{1, 2, 3}; ar {
	case [3]int{1, 2, 3}:
		assert(true, "[1 2 3]")
	case [3]int{4, 5, 6}:
		assert(false, "ar should be [1 2 3]")
	default:
		assert(false, "ar should be [1 2 3]")
	}

	// switch on channel
	switch c1, c2 := make(chan int), make(chan int); c1 {
	case nil:
		assert(false, "c1 did not match itself")
	case c2:
		assert(false, "c1 did not match itself")
	case c1:
		assert(true, "chan")
	default:
		assert(false, "c1 did not match itself")
	}

	// empty switch
	switch {
	}

	// empty switch with default case.
	fired = false
	switch {
	default:
		fired = true
	}
	assert(fired, "fail")

	// Default and fallthrough.
	count = 0
	switch {
	default:
		count++
		fallthrough
	case false:
		count++
	}
	assert(count == 2, "fail")

	// fallthrough to default, which is not at end.
	count = 0
	switch i5 {
	case 5:
		count++
		fallthrough
	default:
		count++
	case 6:
		count++
	}
	assert(count == 2, "fail")

	i := 0
	switch x := 5; {
	case i < x:
		os.Exit(0)
	case i == x:
	case i > x:
		os.Exit(1)
	}
}
