github.com/arnodel/golua@v0.0.0-20230215163904-e0b5347eaaa1/runtime/thread_test.go (about)

     1  package runtime
     2  
     3  import (
     4  	"reflect"
     5  	"testing"
     6  )
     7  
     8  func TestThread_Resume(t *testing.T) {
     9  	type args struct {
    10  		caller *Thread
    11  		args   []Value
    12  	}
    13  	tests := []struct {
    14  		name      string
    15  		thread    *Thread
    16  		args      args
    17  		wantPanic interface{}
    18  	}{
    19  		{
    20  			name: "caller must be running",
    21  			thread: &Thread{
    22  				status: ThreadSuspended,
    23  			},
    24  			args: args{
    25  				caller: &Thread{
    26  					status: ThreadDead,
    27  				},
    28  			},
    29  			wantPanic: "Caller of thread to resume is not running",
    30  		},
    31  	}
    32  	for _, tt := range tests {
    33  		t.Run(tt.name, func(t *testing.T) {
    34  			th := tt.thread
    35  			gotPanic := func() (res interface{}) {
    36  				defer func() { res = recover() }()
    37  				_, _ = th.Resume(tt.args.caller, tt.args.args)
    38  				return
    39  			}()
    40  			if !reflect.DeepEqual(gotPanic, tt.wantPanic) {
    41  				t.Errorf("Thread.Resume() panic got %v, want %v", gotPanic, tt.wantPanic)
    42  			}
    43  		})
    44  	}
    45  }
    46  
    47  func TestThread_Yield(t *testing.T) {
    48  	type args struct {
    49  		args []Value
    50  	}
    51  	tests := []struct {
    52  		name      string
    53  		thread    *Thread
    54  		args      args
    55  		wantPanic interface{}
    56  	}{
    57  		{
    58  			name: "Thread to yield must be running",
    59  			thread: &Thread{
    60  				status: ThreadDead,
    61  			},
    62  			wantPanic: "Thread to yield is not running",
    63  		},
    64  		{
    65  			name: "Caller of thread to yield must be OK",
    66  			thread: &Thread{
    67  				status: ThreadOK,
    68  				caller: &Thread{
    69  					status: ThreadDead,
    70  				},
    71  			},
    72  			wantPanic: "Caller of thread to yield is not OK",
    73  		},
    74  	}
    75  	for _, tt := range tests {
    76  		t.Run(tt.name, func(t *testing.T) {
    77  			th := tt.thread
    78  			gotPanic := func() (res interface{}) {
    79  				defer func() { res = recover() }()
    80  				_, _ = th.Yield(tt.args.args)
    81  				return
    82  			}()
    83  			if !reflect.DeepEqual(gotPanic, tt.wantPanic) {
    84  				t.Errorf("Thread.Yield() panic got %v, want %v", gotPanic, tt.wantPanic)
    85  			}
    86  		})
    87  	}
    88  }
    89  
    90  func TestThread_end(t *testing.T) {
    91  	type args struct {
    92  		args  []Value
    93  		err   error
    94  		extra interface{}
    95  	}
    96  	quotaErr := ContextTerminationError{message: "boo!"}
    97  	tests := []struct {
    98  		name      string
    99  		thread    *Thread
   100  		args      args
   101  		wantPanic interface{}
   102  	}{
   103  		{
   104  			name: "Thread to end must be running",
   105  			thread: &Thread{
   106  				status:   ThreadDead,
   107  				caller:   &Thread{},
   108  				resumeCh: make(chan valuesError),
   109  			},
   110  			wantPanic: "Called Thread.end on a non-running thread",
   111  		},
   112  		{
   113  			name: "Caller of thread to end must be OK",
   114  			thread: &Thread{
   115  				status: ThreadOK,
   116  				caller: &Thread{
   117  					status: ThreadDead,
   118  				},
   119  				resumeCh: make(chan valuesError),
   120  			},
   121  			wantPanic: "Caller thread of ending thread is not OK",
   122  		},
   123  		{
   124  			name: "Thread must not run out of resources",
   125  			thread: &Thread{
   126  				status: ThreadOK,
   127  				caller: &Thread{
   128  					resumeCh: make(chan valuesError, 1),
   129  				},
   130  				resumeCh: make(chan valuesError),
   131  			},
   132  			args: args{
   133  				extra: quotaErr,
   134  			},
   135  			wantPanic: quotaErr,
   136  		},
   137  	}
   138  	for _, tt := range tests {
   139  		t.Run(tt.name, func(t *testing.T) {
   140  			th := tt.thread
   141  			th.Runtime = &Runtime{} // So releasing resources works.
   142  			gotPanic := func() (res interface{}) {
   143  				defer func() { res = recover() }()
   144  				caller := th.caller // The caller is removed when th is killed
   145  				th.end(tt.args.args, tt.args.err, tt.args.extra)
   146  				_, _ = caller.getResumeValues()
   147  				return
   148  			}()
   149  			if gotPanic != tt.wantPanic {
   150  				t.Errorf("Thread.end() panic got %#v, want %#v", gotPanic, tt.wantPanic)
   151  			}
   152  		})
   153  	}
   154  }