// TODO handle-bound tests

package test

import (
	
	
	
	

	arpc 
	
	

	sst 
	
	amhelpt 
	am 
	ampipe 
)

type S = am.S

type (
	Schema = am.Schema
)

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	 := utils.NewNoRelsNetSrc(, nil, "")
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	.Add1("A", nil)

	// assert
	amhelpt.AssertIs(, .NetMach, S{"A"})

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	 := utils.NewNoRelsNetSrc(, nil, "")
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	.Add(S{"A"}, nil)
	.Add(S{"B"}, nil)

	// assert
	amhelpt.AssertIs(, .NetMach, S{"A", "B"})

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	 := utils.NewNoRelsNetSrc(, S{"A"}, "")
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// assert
	assert.Subset(, .StateNames(), S{"A", "B", "C", "D"})

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}
	// amhelp.EnableDebugging(true)

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	 := utils.NewNoRelsNetSrc(, S{"A"}, "")
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	.Set(S{"B"}, nil)

	// assert
	amhelpt.AssertIs(, , S{"B"})

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	 := utils.NewNoRelsNetSrc(, S{"A"}, "")
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	.Add(S{"B"}, nil)

	// assert
	amhelpt.AssertIs(, , S{"A", "B"})

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	 := utils.NewNoRelsNetSrc(, S{"B", "C"}, "")
	, , ,  := (, , , nil, 0, false, nil, nil)

	// test
	.NetMach.Remove(S{"C"}, nil)
	 := .NetMach

	// assert
	amhelpt.AssertIs(, , S{"B"})

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// relations
	 := utils.NewCustomNetSrc(, am.Schema{
		sst.A: {},
		sst.B: {},
		sst.C: {Remove: S{sst.D}},
		sst.D: {},
	})
	.Add1(sst.D, nil)
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// C deactivates D
	.Add(S{"C"}, nil)
	amhelpt.AssertIs(, , S{"C"})

	disposeTest(, , , true)
}

func (
	 *testing.T,  NewTestFactory,
) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	 := utils.NewCustomNetSrc(, am.Schema{
		sst.A: {},
		sst.B: {},
		sst.C: {Remove: S{sst.D}},
		sst.D: {},
	})
	.Add1(sst.D, nil)
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	 := .Set(S{"C", "D"}, nil)

	// assert
	assert.Equal(, am.Canceled, )
	amhelpt.AssertIs(, , S{"D"})

	disposeTest(, , , true)
}

func (
	 *testing.T,  NewTestFactory,
) {
	 := []struct {
		 string
		   func( *testing.T,  *arpc.NetworkMachine)
	}{
		{
			"using Set should de-activate the old one",
			func( *testing.T,  *arpc.NetworkMachine) {
				// (D:1)[A:0 B:0 C:0]
				.Set(S{"C"}, nil)
				amhelpt.AssertIs(, , S{"C"})
			},
		},
		{
			"using Set should work both ways",
			func( *testing.T,  *arpc.NetworkMachine) {
				// (D:1)[A:0 B:0 C:0]
				.Set(S{"C"}, nil)
				amhelpt.AssertIs(, , S{"C"})
				.Set(S{"D"}, nil)
				amhelpt.AssertIs(, , S{"D"})
			},
		},
		{
			"using Add should de-activate the old one",
			func( *testing.T,  *arpc.NetworkMachine) {
				// (D:1)[A:0 B:0 C:0]
				.Add(S{"C"}, nil)
				amhelpt.AssertIs(, , S{"C"})
			},
		},
		{
			"using Add should work both ways",
			func( *testing.T,  *arpc.NetworkMachine) {
				// (D:1)[A:0 B:0 C:0]
				.Add(S{"C"}, nil)
				amhelpt.AssertIs(, , S{"C"})
				.Add(S{"D"}, nil)
				amhelpt.AssertIs(, , S{"D"})
			},
		},
	}

	for  := range  {
		 := []

		.Run(., func( *testing.T) {
			if os.Getenv(am.EnvAmTestDbgAddr) == "" {
				.Parallel()
			}

			// init
			,  := context.WithCancel(context.Background())
			defer ()

			 := utils.NewCustomNetSrc(, am.Schema{
				sst.A: {},
				sst.B: {},
				sst.C: {Remove: S{sst.D}},
				sst.D: {Remove: S{sst.C}},
			})
			.Add1(sst.D, nil)
			, , ,  := (, , , nil, 0, false, nil, nil)
			 := .NetMach

			// test
			.(, )

			// dispose
			disposeTest(, , , true)
		})
	}
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewCustomNetSrc(, am.Schema{
		sst.A: {Remove: S{sst.D}},
		sst.B: {},
		sst.C: {Add: S{sst.D}},
		sst.D: {},
	})

	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	.Set(S{"C"}, nil)

	// assert
	amhelpt.AssertIs(, , S{"C", "D"}, "state should be activated")
	.Set(S{"A", "C"}, nil)
	amhelpt.AssertIs(, , S{"A", "C"}, "state D should be skipped if "+
		"blocked at the same time")

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewCustomNetSrc(, am.Schema{
		sst.A: {Require: S{sst.D}},
		sst.B: {},
		sst.C: {},
		sst.D: {},
	})

	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	.Set(S{"C", "D"}, nil)

	// assert
	amhelpt.AssertIs(, , S{"C", "D"})

	disposeTest(, , , true)
}

func (
	 *testing.T,  NewTestFactory,
) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewCustomNetSrc(, am.Schema{
		sst.A: {},
		sst.B: {},
		sst.C: {Require: S{sst.D}},
		sst.D: {},
	})
	.Add1(sst.A, nil)

	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	.Set(S{"C", "A"}, nil)

	// assert
	amhelpt.AssertIs(, , S{"A"}, "target state shouldnt be activated")

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewCustomNetSrc(, am.Schema{
		sst.A: {},
		sst.B: {
			Auto:    true,
			Require: S{sst.A},
		},
		sst.C: {Require: S{sst.D}},
		sst.D: {},
	})

	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	 := .Add(S{"A"}, nil)

	// assert
	assert.Equal(, am.Executed, , "transition should be executed")
	amhelpt.AssertIs(, , S{"A", "B"}, "dependant auto state should be set")

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewCustomNetSrc(, am.Schema{
		sst.A: {},
		sst.B: {},
		sst.C: {Require: S{sst.D}},
		sst.D: {},
	})
	.Add1(sst.A, nil)

	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	 := false
	switch .Switch(S{"A", "B"}) {
	case "A":
		 = true
	case "B":
	}
	assert.Equal(, true, )

	 := false
	switch .Switch(S{"C", "B"}) {
	case "B":
	default:
		 = true
	}
	assert.Equal(, true, )

	disposeTest(, , , true)
}

func (
	 *testing.T,  NewTestFactory,
) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewCustomNetSrc(, Schema{
		"A": {Remove: S{"B"}},
		"B": {Remove: S{"A"}},
		"Z": {Add: S{"B"}},
	})

	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	.Set(S{"Z"}, nil)

	// assert
	amhelpt.AssertIs(, , S{"Z", "B"})

	disposeTest(, , , true)
}

func (
	 *testing.T,  NewTestFactory,
) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewCustomNetSrc(, Schema{
		"Wet":   {Require: S{"Water"}},
		"Dry":   {Remove: S{"Wet"}},
		"Water": {Add: S{"Wet"}, Remove: S{"Dry"}},
	})

	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	.Set(S{"Dry"}, nil)
	.Set(S{"Water"}, nil)

	// assert
	amhelpt.AssertIs(, , S{"Water", "Wet"})

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewNoRelsNetSrc(, nil, "")

	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test

	 := make(chan struct{})
	 := make(chan struct{})
	go func() {
		close()
		<-.When(S{"A", "B"}, nil)
		close()
	}()

	 := make(chan struct{})
	 := make(chan struct{})
	go func() {
		close()
		<-.When(S{"A", "B"}, nil)
		close()
	}()

	<-
	<-

	.Add(S{"A", "B"}, nil)

	<-
	<-

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewNoRelsNetSrc(, S{"A"}, "")
	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	<-.When(S{"A"}, nil)

	// assert
	amhelpt.AssertIs(, , S{"A"})

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewNoRelsNetSrc(, S{"A", "B"}, "")
	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test

	 := make(chan struct{})
	 := make(chan struct{})
	go func() {
		close()
		<-.WhenNot(S{"A", "B"}, nil)
		close()
	}()

	 := make(chan struct{})
	 := make(chan struct{})
	go func() {
		close()
		<-.WhenNot(S{"A", "B"}, nil)
		close()
	}()

	<-
	<-

	.Remove(S{"A", "B"}, nil)

	<-
	<-

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewNoRelsNetSrc(, S{"A"}, "")
	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	<-.WhenNot(S{"B"}, nil)

	// assert
	amhelpt.AssertIs(, , S{"A"})

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewCustomNetSrc(, am.Schema{
		sst.A: {},
		sst.B: {},
		sst.C: {
			Auto:    true,
			Require: S{sst.B},
		},
		sst.D: {
			Auto:    true,
			Require: S{sst.B},
		},
	})
	.Add1(sst.A, nil)

	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	.Add(S{"A"}, nil)

	// assert
	amhelpt.AssertIs(, , S{"A"})

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewCustomNetSrc(, am.Schema{
		sst.A: {},
		sst.B: {Multi: true},
		sst.C: {},
		sst.D: {},
	})

	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test 1
	// ()[]
	.Add(S{"A", "B"}, nil)
	amhelpt.AssertIs(, , S{"A", "B"})
	amhelpt.AssertTime(, , S{"A", "B", "C", "D"}, am.Time{1, 1, 0, 0})

	.Add(S{"A", "B"}, nil)
	amhelpt.AssertIs(, , S{"A", "B"})
	amhelpt.AssertTime(, , S{"A", "B", "C", "D"}, am.Time{1, 3, 0, 0})

	.Add(S{"A", "B", "C"}, nil)
	amhelpt.AssertIs(, , S{"A", "B", "C"})
	amhelpt.AssertTime(, , S{"A", "B", "C", "D"}, am.Time{1, 5, 1, 0})

	.Set(S{"D"}, nil)
	amhelpt.AssertIs(, , S{"D"})
	amhelpt.AssertTime(, , S{"A", "B", "C", "D"}, am.Time{2, 6, 2, 1})

	.Add(S{"D", "C"}, nil)
	amhelpt.AssertIs(, , S{"D", "C"})
	amhelpt.AssertTime(, , S{"A", "B", "C", "D"}, am.Time{2, 6, 3, 1})

	.Remove(S{"B", "C"}, nil)
	amhelpt.AssertIs(, , S{"D"})
	amhelpt.AssertTime(, , S{"A", "B", "C", "D"}, am.Time{2, 6, 4, 1})

	.Add(S{"A", "B"}, nil)
	amhelpt.AssertIs(, , S{"D", "A", "B"})
	amhelpt.AssertTime(, , S{"A", "B", "C", "D"}, am.Time{3, 7, 4, 1})

	// test 2
	 := S{"A", "B", "C", "D"}
	 := .Time()
	.Add(S{"C"}, nil)
	 := .Time()

	// assert
	amhelpt.AssertIs(, , S{"A", "B", "D", "C"})
	amhelpt.AssertTime(, , S{"A", "B", "C", "D"}, am.Time{3, 7, 5, 1})
	assert.True(, .After(true, ))
	assert.False(, .After(true, ))

	disposeTest(, , , true)
}

// TODO WhenArgs
// func TestWhenCtx(t *testing.T) {
//
// 	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
// 		t.Parallel()
// 	}

// init
//	ctx, cancel := context.WithCancel(context.Background())
//	defer cancel()
//	//
//	// machine
//	mach := amtest.NewNoRels(t, S{"A", "B"})
//	// worker
//	_, _, s, c := NewTest(t, ctx, mach, nil, nil, nil, false)
//	w := c.NetworkMachine
//	disposeTest(t, c, s, true)
//
//	// wait on 2 Whens with a step context
//	ctxWhen, cancelWhen := context.WithCancel(context.Background())
//	whenTimeCh := w.WhenTime(S{"A", "B"}, am.Time{3, 3}, ctxWhen)
//	whenArgsCh := w.WhenArgs("B", am.A{"foo": "bar"}, ctxWhen)
//	whenCh := w.When1("C", ctxWhen)
//
//	// assert
//	assert.Greater(t, len(w.indexWhenTime), 0)
//	assert.Greater(t, len(w.indexWhen), 0)
//	assert.Greater(t, len(w.indexWhenArgs), 0)
//
//	go func() {
//		time.Sleep(10 * time.Millisecond)
//		cancelWhen()
//	}()
//
//	select {
//	case <-whenCh:
//	case <-whenArgsCh:
//	case <-whenTimeCh:
//	case <-ctxWhen.Done():
//	}
//
//	// wait for the context to be canceled and cleanups happen
//	time.Sleep(time.Millisecond)
//
//	// assert
//	assert.Equal(t, len(w.indexWhenTime), 0)
//	assert.Equal(t, len(w.indexWhen), 0)
//	assert.Equal(t, len(w.indexWhenArgs), 0)
//
//	// dispose
//	disposeTest(t, c, s, true)
// }
//
// func TestWhenArgs(t *testing.T) {
//
// 	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
// 		t.Parallel()
// 	}

// init
//	m := NewRels(t, nil)
//	defer w.Dispose()
//
//	// bind
//	whenCh := m.WhenArgs("B", am.A{"foo": "bar"}, nil)
//
//	// incorrect args
//	w.Add1("B", am.A{"foo": "foo"})
//	select {
//	case <-whenCh:
//		t.Fatal("when shouldnt be resolved")
//	default:
//		// pass
//	}
//
//	// correct args
//	w.Add1("B", am.A{"foo": "bar"})
//	select {
//	default:
//		t.Fatal("when should be resolved")
//	case <-whenCh:
//		// pass
//	}
//
//	// dispose
//	w.Dispose()
//	<-w.WhenDisposed()
// }

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewNoRelsNetSrc(, S{"A", "B"}, "")
	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// bind
	// (A:1 B:1)
	 := .WhenTime(S{"A", "B"}, am.Time{5, 2}, nil)

	// tick some, but not enough
	.Remove(S{"A", "B"}, nil)
	.Add(S{"A", "B"}, nil)
	// (A:3 B:3) not yet
	select {
	case <-:
		.Fatal("when shouldnt be resolved")
	default:
		// pass
	}

	.Remove1("A", nil)
	.Add1("A", nil)
	// (A:5 B:3) OK

	select {
	default:
		.Fatal("when should be resolved")
	case <-:
		// pass
	}

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewCustomNetSrc(, am.Schema{
		sst.A: {},
		sst.B: {
			Auto:    true,
			Require: S{sst.A},
		},
		sst.C: {},
		sst.D: {},
	})
	.Add(S{sst.A, sst.B}, nil)

	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	assert.True(, .Is(S{"A", "B"}), "A B should be active")
	assert.False(, .Is(S{"A", "B", "C"}), "A B C shouldnt be active")

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewCustomNetSrc(, am.Schema{
		sst.A: {},
		sst.B: {
			Auto:    true,
			Require: S{sst.A},
		},
		sst.C: {},
		sst.D: {},
	})
	.Add(S{sst.A, sst.B}, nil)

	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	assert.False(, .Not(S{"A", "B"}), "A B should be active")
	assert.False(, .Not(S{"A", "B", "C"}), "A B C is partially active")
	assert.True(, .Not1("D"), "D is inactive")

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewCustomNetSrc(, am.Schema{
		sst.A: {},
		sst.B: {
			Auto:    true,
			Require: S{sst.A},
		},
		sst.C: {},
		sst.D: {},
	})
	.Add(S{sst.A, sst.B}, nil)

	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	assert.True(, .Any(S{"A", "B"}, S{"C"}), "A B should be active")
	assert.True(, .Any(S{"A", "B", "C"}, S{"A"}),
		"A B C is partially active")

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewCustomNetSrc(, am.Schema{
		sst.A: {},
		sst.B: {Multi: true},
		sst.C: {},
		sst.D: {},
	})

	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test 1
	// ()[]
	.Add(S{"A", "B"}, nil)
	amhelpt.AssertIs(, , S{"A", "B"})
	amhelpt.AssertTime(, , S{"A", "B", "C", "D"}, am.Time{1, 1, 0, 0})

	.Add(S{"A", "B"}, nil)
	amhelpt.AssertIs(, , S{"A", "B"})
	amhelpt.AssertTime(, , S{"A", "B", "C", "D"}, am.Time{1, 3, 0, 0})

	.Add(S{"A", "B", "C"}, nil)
	amhelpt.AssertIs(, , S{"A", "B", "C"})
	amhelpt.AssertTime(, , S{"A", "B", "C", "D"}, am.Time{1, 5, 1, 0})

	.Set(S{"D"}, nil)
	amhelpt.AssertIs(, , S{"D"})
	amhelpt.AssertTime(, , S{"A", "B", "C", "D"}, am.Time{2, 6, 2, 1})

	.Add(S{"D", "C"}, nil)
	amhelpt.AssertIs(, , S{"D", "C"})
	amhelpt.AssertTime(, , S{"A", "B", "C", "D"}, am.Time{2, 6, 3, 1})

	.Remove(S{"B", "C"}, nil)
	amhelpt.AssertIs(, , S{"D"})
	amhelpt.AssertTime(, , S{"A", "B", "C", "D"}, am.Time{2, 6, 4, 1})

	.Add(S{"A", "B"}, nil)
	amhelpt.AssertIs(, , S{"D", "A", "B"})
	amhelpt.AssertTime(, , S{"A", "B", "C", "D"}, am.Time{3, 7, 4, 1})

	assert.Subset(, .Clock(nil), am.Clock{
		"A": 3, "B": 7, "C": 4, "D": 1, "Exception": 0,
	})

	assert.Equal(, am.Clock{
		"A": 3, "B": 7,
	}, .Clock(S{"A", "B"}))

	assert.Equal(, uint64(3), .Tick("A"))

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewRelsNetSrc(, S{"A", "C"})

	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// (A:1 C:1)[B:0 D:0 Exception:0]
	 := S{"A", "B", "C", "D", "Exception"}
	 := `
    1 A
        |Tick     1
        |Auto     true
        |Require  C
    0 B
        |Tick     0
        |Multi    true
        |Add      C
    1 C
        |Tick     1
        |After    D
    0 D
        |Tick     0
        |Add      C B
    0 Exception
        |Tick     0
        |Multi    true
		`
	amhelpt.AssertString(, , , )
	// (A:1 C:1)[B:0 D:0 Exception:0]
	.Remove(S{"C"}, nil)
	// ()[A:2 B:0 C:2 D:0 Exception:0]
	.Add(S{"B"}, nil)
	// (A:3 B:1 C:3)[D:0 Exception:0]
	.Add(S{"D"}, nil)
	// (A:3 B:1 C:3 D:1)[Exception:0]
	 = `
		0 Exception
		    |Tick     0
		    |Multi    true
		1 A
		    |Tick     3
		    |Auto     true
		    |Require  C
		1 B
		    |Tick     1
		    |Multi    true
		    |Add      C
		1 C
		    |Tick     3
		    |After    D
		1 D
		    |Tick     1
		    |Add      C B
		0 ErrOnClient
		    |Tick     0
		    |Require  Exception
	`
	amhelpt.AssertString(, , , nil)

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewNoRelsNetSrc(, S{"A", "B"}, "")

	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	assert.Equal(, "(A:1 B:1)", .String())
	assert.Equal(, "(A:1 B:1) [Exception:0 C:0 D:0 ErrOnClient:0]",
		.StringAll())

	disposeTest(, , , true)
}

// TestNestedMutation
type TestNestedMutationHandlers struct {
	*am.ExceptionHandler
}

func ( *TestNestedMutationHandlers) ( *am.Event) {
	.Machine().Add1("B", nil)
	.Machine().Add1("B", nil)
	.Machine().Add1("B", nil)

	.Machine().Remove1("B", nil)
	.Machine().Remove1("B", nil)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewNoRelsNetSrc(, nil, "")
	// bind handlers
	,  := .HandlersBind(&TestNestedMutationHandlers{})
	assert.NoError(, )

	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	.Add1("A", nil)

	// assert
	amhelpt.AssertIs(, , S{"A"})

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	 := utils.NewNoRelsNetSrc(, nil, "")
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	 := .Clock(S{"A"})
	 := .Clock(nil)
	.Add(S{"A", "B"}, nil)

	// assert
	assert.False(, .IsClock())
	assert.False(, .IsClock())

	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	 := utils.NewNoRelsNetSrc(, nil, "")
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	 := .Time(S{"A"})
	 := .Time(nil)
	.Add(S{"A", "B"}, nil)

	// assert
	assert.False(, .IsTime(, S{"A"}))
	assert.False(, .IsTime(, nil))

	disposeTest(, , , true)
}

// TODO
// func TestExport(t *testing.T) {
//
// 	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
// 		t.Parallel()
// 	}

// init
//	m1 := NewNoRels(t, S{"A"})
//	defer m1.Dispose()
//
//	// change clocks
//	m1.Add1("A", nil)
//	m1.Add1("B", nil)
//	m1.Add1("C", nil)
//	m1Str := m1.Encode()
//
//	// export
//	jsonPath := path.Join(os.Te1mpDir(), "am-TestExportImport.json")
//	err := m1.Export()
// }

// TestWhenQueue
type TestWhenQueueTracer struct {
	*am.TracerNoOp
	done chan struct{}
	t    *testing.T
}

func ( *TestWhenQueueTracer) ( *am.Transition) {
	// dont mutate in a tracer
	go func() {
		 := .MachApi
		// only when setting A
		if .TimeBefore.Is1(.Index1("A")) {
			return
		}

		.Add1("B", nil)
		.Add1("C", nil)
		// TODO pause queue in the source machine's handler
		// res := m.Add1("D", nil)
		 := am.Result(5)
		.Add1("D", nil)

		<-.WhenQueue()
		amhelpt.AssertIs(.t, , S{"A", "B", "C", "D"})
		close(.done)
	}()
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewNoRelsNetSrc(, nil, "")

	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	 := &TestWhenQueueTracer{
		TracerNoOp: &am.TracerNoOp{
			Id: .Name(),
		},
		t:    ,
		done: make(chan struct{}),
	}
	,  := .BindTracer()
	require.NoError(, )

	.Add1("A", nil)
	// TODO weird close-doesnt-unblock bug in go1.25
	select {
	case <-.done:
	case <-time.After(time.Second):
		<-.done
	}

	// dispose
	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}

	// init
	,  := context.WithCancel(context.Background())
	defer ()

	// machine
	 := utils.NewNoRelsNetSrc(, S{"A"}, "")

	// worker
	, , ,  := (, , , nil, 0, false, nil, nil)
	 := .NetMach

	// test
	 := func( am.Clock) bool {
		return ["A"] > ["B"]*4
	}
	 := func( am.Clock) bool {
		return ["A"] < ["B"]
	}
	 := .WhenQuery(, nil)
	 := .WhenQuery(, nil)

	// 1, 0
	.Add1("B", nil)
	// 1, 1
	.Remove1("A", nil)
	// 2, 1
	.Add1("A", nil)
	// 3, 1

	.Remove1("A", nil)
	// 4, 1
	select {
	case <-:
		assert.Fail(, "should NOT match")
	case <-:
		assert.Fail(, "should NOT match")
	default:
		// ok
	}

	.Add1("A", nil)
	// 5, 1 = match
	select {
	case <-:
	// ok
	case <-:
		assert.Fail(, "should NOT match")
	default:
		assert.Fail(, "should match")
	}

	// dispose
	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}
	// amhelp.EnableDebugging(true)

	// machine
	 := context.Background()
	 := utils.NewNoRelsNetSrc(, S{"A"}, "")
	 := utils.NewNoRelsNetSrc(, nil, "-local")
	// amhelp.MachDebugEnv(local)

	// connect
	, , ,  := (, , , nil, 0, false, nil, nil)
	// amhelp.MachDebug(c.NetMach, "localhost:6831", am.LogOps, true,
	// 	amhelp.SemConfigEnv(true))

	.AddBreakpoint1("A", "", false)
	.AddBreakpoint1("B", "", false)

	// sync and pipe from network version to a full local
	// TODO pause RPC client?
	.Set(.NetMach.ActiveStates(nil), nil)
	,  := ampipe.BindAny(.NetMach, )
	require.NoError(, )

	// mutate
	.Add(S{"A", "B"}, nil)
	amhelpt.WaitForAll(, .Name(), , time.Second,
		.When(am.S{"A", "B"}, nil))

	.Log("OK")

	.Dispose()
	disposeTest(, , , true)
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}
	// init
	 := utils.NewNoRelsNetSrc(, nil, "")

	// test
	.Add1("A", nil)
	 := .NewStateCtx("A")
	assert.Nil(, .Err())
	.Remove1("A", nil)
	assert.Error(, .Err())

	// test inactive ctx
	 := .NewStateCtx("B")
	assert.Nil(, .Err())
	.Add1("B", nil)
	assert.Error(, .Err())

	// dispose
	.Dispose()
	<-.WhenDisposed()
}

func ( *testing.T,  NewTestFactory) {
	if os.Getenv(am.EnvAmTestDbgAddr) == "" {
		.Parallel()
	}
	// init
	 := utils.NewNoRelsNetSrc(, S{"A", "B"}, "")

	// initial sum: A:1 B:1 = 2
	 := .Time(nil).Sum(nil)
	require.Equal(, uint64(2), )

	// bind: wait for sum >= 8
	 := .WhenTimeSum(8, nil)

	// tick some, but not enough: Remove+Add both = A:3 B:3 sum=6
	.Remove(S{"A", "B"}, nil)
	.Add(S{"A", "B"}, nil)
	 := .Time(nil).Sum(nil)
	require.Equal(, uint64(6), )

	// channel should not fire yet
	select {
	case <-:
		.Fatal("when shouldnt be resolved")
	default:
		// pass
	}

	// tick A again: Remove1+Add1 = A:5 B:3 sum=8
	.Remove1("A", nil)
	.Add1("A", nil)
	 := .Time(nil).Sum(nil)
	require.Equal(, uint64(8), )

	// channel should fire now
	select {
	default:
		.Fatal("when should be resolved")
	case <-:
		// pass
	}

	// dispose
	.Dispose()
	<-.WhenDisposed()
}