<commit_before>package killable

import (
	"errors"
	"runtime"
	"sync"
	"testing"
	"time"
)

func doneTimeout(done <-chan struct{}) bool {
	runtime.Gosched()
	select {
	case <-done:
		return false
	case <-time.After(time.Millisecond * 500):
		return true
	}
}

func doneTimeoutErr(t *testing.T, done <-chan struct{}, msg string) {
	if doneTimeout(done) {
		t.Errorf(msg)
	}
}

func TestKillShouldCloseDyingAndDead(t *testing.T) {
	k := New()
	k.Kill(nil)
	doneTimeoutErr(t, k.Dying(), "Dying chan not closed")
	doneTimeoutErr(t, k.Dead(), "Dying chan not closed")
}

func TestErrShouldBlock(t *testing.T) {
	var (
		k    = New()
		done = make(chan struct{})
		err  = errors.New("oohh noooess")
	)
	go func() {
		if k.Err() != err {
			t.Errorf("Err() returned wrong error")
		}
		close(done)
	}()
	k.Kill(err)
	doneTimeoutErr(t, done, "Err() didn't return")
}

func TestDoShouldReturnErr(t *testing.T) {
	var (
		k   = New()
		err = errors.New("the error")
	)
	if Do(k, func() error {
		return err
	}) != err {
		t.Errorf("Do didn't return correct error")
	}
}

func TestDoShouldReturnErrDying(t *testing.T) {
	var (
		k    = New()
		done = make(chan struct{})
	)
	go func() {
		if Do(k, func() error {
			time.Sleep(time.Second)
			return nil
		}) != ErrDying {
			t.Errorf("Do didn't return ErrDying")
		}
		close(done)
	}()
	k.Kill(nil)
	doneTimeoutErr(t, done, "Do didn't return")
}

func TestDoShouldNotRunWhenDying(t *testing.T) {
	k := New()
	k.Kill(nil)
	if Do(k, func() error {
		t.Errorf("Do should not run if Killable is Dead")
		return nil
	}) != ErrDying {
		t.Errorf("Do should return ErrDying if invoked on a Dying Killable")
	}
}

func TestShouldNotDieUntilDoReturns(t *testing.T) {
	var (
		k    = New()
		done = make(chan struct{})
	)
	Do(k, func() error {
		defer close(done)
		k.Kill(nil)
		<-k.Dying()
		if !doneTimeout(k.Dead()) {
			t.Errorf("Killable should not be dead until Do returns")
		}
		return nil
	})
	<-done
	doneTimeoutErr(t, k.Dead(), "Killable should be dead after Do returns")
}

func TestShouldNotDieUntilMultipleDoReturns(t *testing.T) {
	var (
		k  = New()
		wg sync.WaitGroup
	)
	fn := func() error {
		defer wg.Done()
		k.Kill(nil)
		<-k.Dying()
		if !doneTimeout(k.Dead()) {
			t.Errorf("Killable should not be dead until Do returns")
		}
		return nil
	}
	wg.Add(4)
	go Do(k, fn)
	go Do(k, fn)
	go Do(k, fn)
	go Do(k, fn)
	wg.Wait()
	doneTimeoutErr(t, k.Dead(), "Killable should be dead after Do returns")
}

func TestGoShouldKillWithReturnedError(t *testing.T) {
	var (
		k   = New()
		err = errors.New("this is my error, there are many like it, but this one is mine")
	)
	Go(k, func() error {
		return err
	})
	doneTimeoutErr(t, k.Dying(), "Killable didn't enter dying state")
	if k.Err() != err {
		t.Errorf("Killable didn't recieve correct error")
	}
}

func TestGoShouldNotKillWithReturnedNil(t *testing.T) {
	k := New()
	Go(k, func() error {<commit_msg>fix test<commit_after>package killable

import (
	"errors"
	"runtime"
	"sync"
	"testing"
	"time"
)

func doneTimeout(done <-chan struct{}) bool {
	runtime.Gosched()
	select {
	case <-done:
		return false
	case <-time.After(time.Millisecond * 500):
		return true
	}
}

func doneTimeoutErr(t *testing.T, done <-chan struct{}, msg string) {
	if doneTimeout(done) {
		t.Errorf(msg)
	}
}

func TestKillShouldCloseDyingAndDead(t *testing.T) {
	k := New()
	k.Kill(nil)
	doneTimeoutErr(t, k.Dying(), "Dying chan not closed")
	doneTimeoutErr(t, k.Dead(), "Dying chan not closed")
}

func TestErrShouldBlock(t *testing.T) {
	var (
		k    = New()
		done = make(chan struct{})
		err  = errors.New("oohh noooess")
	)
	go func() {
		if k.Err() != err {
			t.Errorf("Err() returned wrong error")
		}
		close(done)
	}()
	k.Kill(err)
	doneTimeoutErr(t, done, "Err() didn't return")
}

func TestDoShouldReturnErr(t *testing.T) {
	var (
		k   = New()
		err = errors.New("the error")
	)
	if Do(k, func() error {
		return err
	}) != err {
		t.Errorf("Do didn't return correct error")
	}
}

func TestDoShouldReturnErrDying(t *testing.T) {
	var (
		k    = New()
		done = make(chan struct{})
	)
	go func() {
		if Do(k, func() error {
			time.Sleep(time.Second)
			return nil
		}) != ErrDying {
			t.Errorf("Do didn't return ErrDying")
		}
		close(done)
	}()
	k.Kill(nil)
	doneTimeoutErr(t, done, "Do didn't return")
}

func TestDoShouldNotRunWhenDying(t *testing.T) {
	k := New()
	k.Kill(nil)
	if Do(k, func() error {
		t.Errorf("Do should not run if Killable is Dead")
		return nil
	}) != ErrDying {
		t.Errorf("Do should return ErrDying if invoked on a Dying Killable")
	}
}

func TestShouldNotDieUntilDoReturns(t *testing.T) {
	var (
		k    = New()
		done = make(chan struct{})
	)
	Do(k, func() error {
		defer close(done)
		k.Kill(nil)
		<-k.Dying()
		if !doneTimeout(k.Dead()) {
			t.Errorf("Killable should not be dead until Do returns")
		}
		return nil
	})
	<-done
	doneTimeoutErr(t, k.Dead(), "Killable should be dead after Do returns")
}

func TestShouldNotDieUntilMultipleDoReturns(t *testing.T) {
	var (
		k  = New()
		wg sync.WaitGroup
	)
	fn := func() error {
		wg.Done()
		defer wg.Done()
		<-k.Dying()
		if !doneTimeout(k.Dead()) {
			t.Errorf("Killable should not be dead until Do returns")
		}
		return nil
	}
	wg.Add(4)
	go Do(k, fn)
	go Do(k, fn)
	go Do(k, fn)
	go Do(k, fn)
	wg.Wait()
	wg.Add(4)
	k.Kill(nil)
	wg.Wait()
	doneTimeoutErr(t, k.Dead(), "Killable should be dead after Do returns")
}

func TestGoShouldKillWithReturnedError(t *testing.T) {
	var (
		k   = New()
		err = errors.New("this is my error, there are many like it, but this one is mine")
	)
	Go(k, func() error {
		return err
	})
	doneTimeoutErr(t, k.Dying(), "Killable didn't enter dying state")
	if k.Err() != err {
		t.Errorf("Killable didn't recieve correct error")
	}
}

func TestGoShouldNotKillWithReturnedNil(t *testing.T) {
	k := New()
	Go(k, func() error {
{'fraction_non_alphanumeric': 0.15821049022968803, 'fraction_numerical': 0.0015426808364758314, 'mean_word_length': 3.5267649340574088, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '757750', 'n_tokens_mistral': 2485, 'n_tokens_neox': 2299, 'n_words': 604}