<commit_before>package onpar_test

import (
	"reflect"
	"testing"

	"github.com/apoydence/onpar"
)

func TestSingleNestedSpec(t *testing.T) {
	o, c := createScaffolding()

	t.Run("FakeSpecs", func(tt *testing.T) {
		o.Run(tt)
	})
	objs := chanToSlice(c)

	if len(objs) != 3 {
		t.Fatalf("expected objs (len=%d) to have len %d", len(objs), 3)
	}

	objA := findSpec(objs, "DA-A")
	if objA == nil {
		t.Fatal("unable to find spec A")
	}

	if len(objA.c) != 4 {
		t.Fatalf("expected objs (len=%d) to have len %d", len(objA.c), 4)
	}

	if !reflect.DeepEqual(objA.c, []string{"-BeforeEach", "DA-A", "DA-AfterEach", "-AfterEach"}) {
		t.Fatalf("invalid call order for spec A: %v", objA.c)
	}
}

func TestInvokeFirstChildAndPeerSpec(t *testing.T) {
	o, c := createScaffolding()

	t.Run("FakeSpecs", func(tt *testing.T) {
		o.Run(tt)
	})
	objs := chanToSlice(c)

	objB := findSpec(objs, "DB-B")
	if objB == nil {
		t.Fatal("unable to find spec B")
	}

	if len(objB.c) != 6 {
		t.Fatalf("expected objs (len=%d) to have len %d", len(objB.c), 6)
	}

	if !reflect.DeepEqual(objB.c, []string{"-BeforeEach", "DB-BeforeEach", "DB-B", "DB-AfterEach", "DA-AfterEach", "-AfterEach"}) {
		t.Fatalf("invalid call order for spec A: %v", objB.c)
	}
}

func TestInvokeSecondChildAndPeerSpec(t *testing.T) {
	o, c := createScaffolding()

	t.Run("FakeSpecs", func(tt *testing.T) {
		o.Run(tt)
	})
	objs := chanToSlice(c)

	objC := findSpec(objs, "DB-C")
	if objC == nil {
		t.Fatal("unable to find spec C")
	}

	if len(objC.c) != 6 {
		t.Fatalf("expected objs (len=%d) to have len %d", len(objC.c), 6)
	}

	if !reflect.DeepEqual(objC.c, []string{"-BeforeEach", "DB-BeforeEach", "DB-C", "DB-AfterEach", "DA-AfterEach", "-AfterEach"}) {
		t.Fatalf("invalid call order for spec A: %v", objC.c)
	}
}

func TestDoNotInvokeStrandedBeforeEach(t *testing.T) {
	o, c := createScaffolding()

	t.Run("FakeSpecs", func(tt *testing.T) {
		o.Run(tt)
	})
	objs := chanToSlice(c)

	objCBeforeEach := findSpec(objs, "DC-BeforeEach")
	if objCBeforeEach != nil {
		t.Fatal("should not have invoked BeforeEach")
	}
}

func TestDoNotInvokeStrandedAfterEach(t *testing.T) {
	o, c := createScaffolding()

	t.Run("FakeSpecs", func(tt *testing.T) {
		o.Run(tt)
	})
	objs := chanToSlice(c)

	objCBeforeEach := findSpec(objs, "DC-AfterEach")
	if objCBeforeEach != nil {
		t.Fatal("should not have invoked AfterEach")
	}
}

func createScaffolding() (*onpar.Onpar, <-chan *testObject) {
	o := onpar.New()
	objs := make(chan *testObject, 100)

	o.BeforeEach(func(t *testing.T) (int, string, *testObject) {
		obj := NewTestObject()
		obj.Use("-BeforeEach")

		objs <- obj

		return 99, "something", obj
	})

	o.AfterEach(func(t *testing.T, i int, s string, o *testObject) {
		o.Use("-AfterEach")
	})

	o.Group("DA", func() {
		o.AfterEach(func(t *testing.T, i int, s string, o *testObject) {
			if i != 99 {
				t.Fatalf("expected %d = %d", i, 99)
			}

			if s != "something" {
				t.Fatalf("expected %s = %s", s, "something")
			}

			o.Use("DA-AfterEach")
			o.Close()
		})

		o.Spec("A", func(t *testing.T, i int, s string, o *testObject) {
			if i != 99 {
				t.Fatalf("expected %d = %d", i, 99)
			}

			if s != "something" {
				t.Fatalf("expected %s = %s", s, "something")
			}

			o.Use("DA-A")
		})

		o.Group("DB", func() {
			o.BeforeEach(func(t *testing.T, i int, s string, o *testObject) float64 {
				o.Use("DB-BeforeEach")
				return 101
			})

			o.AfterEach(func(t *testing.T, i int, s string, o *testObject, f float64) {
				o.Use("DB-AfterEach")
			})

			o.Spec("B", func(t *testing.T, i int, s string, o *testObject, f float64) {
				o.Use("DB-B")
				if i != 99 {
					t.Fatalf("expected %d = %d", i, 99)
				}

				if s != "something" {
					t.Fatalf("expected %s = %s", s, "something")
				}

				if f != 101 {
					t.Fatalf("expected %f = %f", f, 101.0)
				}
			})

			o.Spec("C", func(t *testing.T, i int, s string, o *testObject, f float64) {
				o.Use("DB-C")
				if i != 99 {
					t.Fatalf("expected %d = %d", i, 99)
				}

				if s != "something" {
					t.Fatalf("expected %s = %s", s, "something")
				}

				if f != 101 {
					t.Fatalf("expected %f = %f", f, 101.0)
				}
			})
		})

		o.Group("DC", func() {
			o.BeforeEach(func(t *testing.T, i int, s string, o *testObject) {
				o.Use("DC-BeforeEach")
			})

			o.AfterEach(func(t *testing.T, i int, s string, o *testObject) {
				o.Use("DC-AfterEach")
			})
		})
	})

	return o, objs
}

func chanToSlice(c <-chan *testObject) []*testObject {
	var results []*testObject
	l := len(c)
	for i := 0; i < l; i++ {
		results = append(results, <-c)
	}
	return results
}

func findSpec(objs []*testObject, name string) *testObject {
	for _, obj := range objs {
		for _, specName := range obj.c {
			if name == specName {
				return obj
			}
		}
	}
	return nil
}

type testObject struct {
	c    []string
	done bool
}

func NewTestObject() *testObject {
	return &testObject{
		c: make([]string, 0),
	}
}

func (t *testObject) Use(i string) {
	t.c = append(t.c, i)
}

func (t *testObject) Close() {
	if t.done {
		panic("close() called too many times")
	}
	t.done = true
}
<commit_msg>Add assertions that stranded Before/AfterEach are not run<commit_after>package onpar_test

import (
	"reflect"
	"testing"

	"github.com/apoydence/onpar"
)

func TestSingleNestedSpec(t *testing.T) {
	o, c := createScaffolding()

	t.Run("FakeSpecs", func(tt *testing.T) {
		o.Run(tt)
	})
	objs := chanToSlice(c)

	if len(objs) != 3 {
		t.Fatalf("expected objs (len=%d) to have len %d", len(objs), 3)
	}

	objA := findSpec(objs, "DA-A")
	if objA == nil {
		t.Fatal("unable to find spec A")
	}

	if len(objA.c) != 4 {
		t.Fatalf("expected objs (len=%d) to have len %d", len(objA.c), 4)
	}

	if !reflect.DeepEqual(objA.c, []string{"-BeforeEach", "DA-A", "DA-AfterEach", "-AfterEach"}) {
		t.Fatalf("invalid call order for spec A: %v", objA.c)
	}
}

func TestInvokeFirstChildAndPeerSpec(t *testing.T) {
	o, c := createScaffolding()

	t.Run("FakeSpecs", func(tt *testing.T) {
		o.Run(tt)
	})
	objs := chanToSlice(c)

	objB := findSpec(objs, "DB-B")
	if objB == nil {
		t.Fatal("unable to find spec B")
	}

	if len(objB.c) != 6 {
		t.Fatalf("expected objs (len=%d) to have len %d", len(objB.c), 6)
	}

	if !reflect.DeepEqual(objB.c, []string{"-BeforeEach", "DB-BeforeEach", "DB-B", "DB-AfterEach", "DA-AfterEach", "-AfterEach"}) {
		t.Fatalf("invalid call order for spec A: %v", objB.c)
	}
}

func TestInvokeSecondChildAndPeerSpec(t *testing.T) {
	o, c := createScaffolding()

	t.Run("FakeSpecs", func(tt *testing.T) {
		o.Run(tt)
	})
	objs := chanToSlice(c)

	objC := findSpec(objs, "DB-C")
	if objC == nil {
		t.Fatal("unable to find spec C")
	}

	if len(objC.c) != 6 {
		t.Fatalf("expected objs (len=%d) to have len %d", len(objC.c), 6)
	}

	if !reflect.DeepEqual(objC.c, []string{"-BeforeEach", "DB-BeforeEach", "DB-C", "DB-AfterEach", "DA-AfterEach", "-AfterEach"}) {
		t.Fatalf("invalid call order for spec A: %v", objC.c)
	}
}

func TestDoNotInvokeStrandedBeforeEach(t *testing.T) {
	o, c := createScaffolding()

	t.Run("FakeSpecs", func(tt *testing.T) {
		o.Run(tt)
	})
	objs := chanToSlice(c)

	objCBeforeEach := findSpec(objs, "DC-BeforeEach")
	if objCBeforeEach != nil {
		t.Fatal("should not have invoked BeforeEach")
	}
}

func TestDoNotInvokeStrandedAfterEach(t *testing.T) {
	o, c := createScaffolding()

	t.Run("FakeSpecs", func(tt *testing.T) {
		o.Run(tt)
	})
	objs := chanToSlice(c)

	objCBeforeEach := findSpec(objs, "DC-AfterEach")
	if objCBeforeEach != nil {
		t.Fatal("should not have invoked AfterEach")
	}
}

func createScaffolding() (*onpar.Onpar, <-chan *testObject) {
	o := onpar.New()
	objs := make(chan *testObject, 100)

	o.BeforeEach(func(t *testing.T) (int, string, *testObject) {
		obj := NewTestObject()
		obj.Use("-BeforeEach")

		objs <- obj

		return 99, "something", obj
	})

	o.AfterEach(func(t *testing.T, i int, s string, o *testObject) {
		o.Use("-AfterEach")
	})

	o.Group("DA", func() {
		o.AfterEach(func(t *testing.T, i int, s string, o *testObject) {
			if i != 99 {
				t.Fatalf("expected %d = %d", i, 99)
			}

			if s != "something" {
				t.Fatalf("expected %s = %s", s, "something")
			}

			o.Use("DA-AfterEach")
			o.Close()
		})

		o.Spec("A", func(t *testing.T, i int, s string, o *testObject) {
			if i != 99 {
				t.Fatalf("expected %d = %d", i, 99)
			}

			if s != "something" {
				t.Fatalf("expected %s = %s", s, "something")
			}

			o.Use("DA-A")
		})

		o.Group("DB", func() {
			o.BeforeEach(func(t *testing.T, i int, s string, o *testObject) float64 {
				o.Use("DB-BeforeEach")
				return 101
			})

			o.AfterEach(func(t *testing.T, i int, s string, o *testObject, f float64) {
				o.Use("DB-AfterEach")
			})

			o.Spec("B", func(t *testing.T, i int, s string, o *testObject, f float64) {
				o.Use("DB-B")
				if i != 99 {
					t.Fatalf("expected %d = %d", i, 99)
				}

				if s != "something" {
					t.Fatalf("expected %s = %s", s, "something")
				}

				if f != 101 {
					t.Fatalf("expected %f = %f", f, 101.0)
				}
			})

			o.Spec("C", func(t *testing.T, i int, s string, o *testObject, f float64) {
				o.Use("DB-C")
				if i != 99 {
					t.Fatalf("expected %d = %d", i, 99)
				}

				if s != "something" {
					t.Fatalf("expected %s = %s", s, "something")
				}

				if f != 101 {
					t.Fatalf("expected %f = %f", f, 101.0)
				}
			})
		})

		o.Group("DC", func() {
			o.BeforeEach(func(t *testing.T, i int, s string, o *testObject) {
				o.Use("DC-BeforeEach")
				t.Fatalf("should not have been invoked")
			})

			o.AfterEach(func(t *testing.T, i int, s string, o *testObject) {
				o.Use("DC-AfterEach")
				t.Fatalf("should not have been invoked")
			})
		})
	})

	return o, objs
}

func chanToSlice(c <-chan *testObject) []*testObject {
	var results []*testObject
	l := len(c)
	for i := 0; i < l; i++ {
		results = append(results, <-c)
	}
	return results
}

func findSpec(objs []*testObject, name string) *testObject {
	for _, obj := range objs {
		for _, specName := range obj.c {
			if name == specName {
				return obj
			}
		}
	}
	return nil
}

type testObject struct {
	c    []string
	done bool
}

func NewTestObject() *testObject {
	return &testObject{
		c: make([]string, 0),
	}
}

func (t *testObject) Use(i string) {
	t.c = append(t.c, i)
}

func (t *testObject) Close() {
	if t.done {
		panic("close() called too many times")
	}
	t.done = true
}

{'fraction_non_alphanumeric': 0.19309611293753626, 'fraction_numerical': 0.010829626764649004, 'mean_word_length': 3.195943204868154, 'pattern_counts': {'":': 0, '<': 13, '<?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': '5673054', 'n_tokens_mistral': 4807, 'n_tokens_neox': 4260, 'n_words': 1019}