// Copyright 2012 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.

package race_test

import (
	"testing"
)

func TestRaceMapRW(t *testing.T) {
	m := make(map[int]int)
	ch := make(chan bool, 1)
	go func() {
		_ = m[1]
		ch <- true
	}()
	m[1] = 1
	<-ch
}

func TestRaceMapRW2(t *testing.T) {
	m := make(map[int]int)
	ch := make(chan bool, 1)
	go func() {
		_, _ = m[1]
		ch <- true
	}()
	m[1] = 1
	<-ch
}

func TestRaceMapRWArray(t *testing.T) {
	// Check instrumentation of unaddressable arrays (issue 4578).
	m := make(map[int][2]int)
	ch := make(chan bool, 1)
	go func() {
		_ = m[1][1]
		ch <- true
	}()
	m[2] = [2]int{1, 2}
	<-ch
}

func TestNoRaceMapRR(t *testing.T) {
	m := make(map[int]int)
	ch := make(chan bool, 1)
	go func() {
		_, _ = m[1]
		ch <- true
	}()
	_ = m[1]
	<-ch
}

func TestRaceMapRange(t *testing.T) {
	m := make(map[int]int)
	ch := make(chan bool, 1)
	go func() {
		for range m {
		}
		ch <- true
	}()
	m[1] = 1
	<-ch
}

func TestRaceMapRange2(t *testing.T) {
	m := make(map[int]int)
	ch := make(chan bool, 1)
	go func() {
		for range m {
		}
		ch <- true
	}()
	m[1] = 1
	<-ch
}

func TestNoRaceMapRangeRange(t *testing.T) {
	m := make(map[int]int)
	// now the map is not empty and range triggers an event
	// should work without this (as in other tests)
	// so it is suspicious if this test passes and others don't
	m[0] = 0
	ch := make(chan bool, 1)
	go func() {
		for range m {
		}
		ch <- true
	}()
	for range m {
	}
	<-ch
}

func TestRaceMapLen(t *testing.T) {
	m := make(map[string]bool)
	ch := make(chan bool, 1)
	go func() {
		_ = len(m)
		ch <- true
	}()
	m[""] = true
	<-ch
}

func TestRaceMapDelete(t *testing.T) {
	m := make(map[string]bool)
	ch := make(chan bool, 1)
	go func() {
		delete(m, "")
		ch <- true
	}()
	m[""] = true
	<-ch
}

func TestRaceMapLenDelete(t *testing.T) {
	m := make(map[string]bool)
	ch := make(chan bool, 1)
	go func() {
		delete(m, "a")
		ch <- true
	}()
	_ = len(m)
	<-ch
}

func TestRaceMapVariable(t *testing.T) {
	ch := make(chan bool, 1)
	m := make(map[int]int)
	go func() {
		m = make(map[int]int)
		ch <- true
	}()
	m = make(map[int]int)
	<-ch
}

func TestRaceMapVariable2(t *testing.T) {
	ch := make(chan bool, 1)
	m := make(map[int]int)
	go func() {
		m[1] = 1
		ch <- true
	}()
	m = make(map[int]int)
	<-ch
}

func TestRaceMapVariable3(t *testing.T) {
	ch := make(chan bool, 1)
	m := make(map[int]int)
	go func() {
		_ = m[1]
		ch <- true
	}()
	m = make(map[int]int)
	<-ch
}

type Big struct {
	x [17]int32
}

func TestRaceMapLookupPartKey(t *testing.T) {
	k := &Big{}
	m := make(map[Big]bool)
	ch := make(chan bool, 1)
	go func() {
		k.x[8] = 1
		ch <- true
	}()
	_ = m[*k]
	<-ch
}

func TestRaceMapLookupPartKey2(t *testing.T) {
	k := &Big{}
	m := make(map[Big]bool)
	ch := make(chan bool, 1)
	go func() {
		k.x[8] = 1
		ch <- true
	}()
	_, _ = m[*k]
	<-ch
}
func TestRaceMapDeletePartKey(t *testing.T) {
	k := &Big{}
	m := make(map[Big]bool)
	ch := make(chan bool, 1)
	go func() {
		k.x[8] = 1
		ch <- true
	}()
	delete(m, *k)
	<-ch
}

func TestRaceMapInsertPartKey(t *testing.T) {
	k := &Big{}
	m := make(map[Big]bool)
	ch := make(chan bool, 1)
	go func() {
		k.x[8] = 1
		ch <- true
	}()
	m[*k] = true
	<-ch
}

func TestRaceMapInsertPartVal(t *testing.T) {
	v := &Big{}
	m := make(map[int]Big)
	ch := make(chan bool, 1)
	go func() {
		v.x[8] = 1
		ch <- true
	}()
	m[1] = *v
	<-ch
}

// Test for issue 7561.
func TestRaceMapAssignMultipleReturn(t *testing.T) {
	connect := func() (int, error) { return 42, nil }
	conns := make(map[int][]int)
	conns[1] = []int{0}
	ch := make(chan bool, 1)
	var err error
	go func() {
		conns[1][0], err = connect()
		ch <- true
	}()
	x := conns[1][0]
	_ = x
	<-ch
}

// BigKey and BigVal must be larger than 256 bytes,
// so that compiler sets KindGCProg for them.
type BigKey [1000]*int

type BigVal struct {
	x int
	y [1000]*int
}

func TestRaceMapBigKeyAccess1(t *testing.T) {
	m := make(map[BigKey]int)
	var k BigKey
	ch := make(chan bool, 1)
	go func() {
		_ = m[k]
		ch <- true
	}()
	k[30] = new(int)
	<-ch
}

func TestRaceMapBigKeyAccess2(t *testing.T) {
	m := make(map[BigKey]int)
	var k BigKey
	ch := make(chan bool, 1)
	go func() {
		_, _ = m[k]
		ch <- true
	}()
	k[30] = new(int)
	<-ch
}

func TestRaceMapBigKeyInsert(t *testing.T) {
	m := make(map[BigKey]int)
	var k BigKey
	ch := make(chan bool, 1)
	go func() {
		m[k] = 1
		ch <- true
	}()
	k[30] = new(int)
	<-ch
}

func TestRaceMapBigKeyDelete(t *testing.T) {
	m := make(map[BigKey]int)
	var k BigKey
	ch := make(chan bool, 1)
	go func() {
		delete(m, k)
		ch <- true
	}()
	k[30] = new(int)
	<-ch
}

func TestRaceMapBigValInsert(t *testing.T) {
	m := make(map[int]BigVal)
	var v BigVal
	ch := make(chan bool, 1)
	go func() {
		m[1] = v
		ch <- true
	}()
	v.y[30] = new(int)
	<-ch
}

func TestRaceMapBigValAccess1(t *testing.T) {
	m := make(map[int]BigVal)
	var v BigVal
	ch := make(chan bool, 1)
	go func() {
		v = m[1]
		ch <- true
	}()
	v.y[30] = new(int)
	<-ch
}

func TestRaceMapBigValAccess2(t *testing.T) {
	m := make(map[int]BigVal)
	var v BigVal
	ch := make(chan bool, 1)
	go func() {
		v, _ = m[1]
		ch <- true
	}()
	v.y[30] = new(int)
	<-ch
}
