github.com/mailgun/holster/v4@v4.20.0/functional/functional_test.go (about)

     1  package functional_test
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"context"
     7  	"sync"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/mailgun/holster/v4/functional"
    12  	"github.com/stretchr/testify/assert"
    13  )
    14  
    15  func TestFunctional(t *testing.T) {
    16  	ctx := context.Background()
    17  
    18  	t.Run("Run()", func(t *testing.T) {
    19  		t.Run("Happy path", func(t *testing.T) {
    20  			testFunc := func(_ *functional.T) {}
    21  			pass := functional.Run(ctx, testFunc)
    22  			assert.True(t, pass)
    23  		})
    24  
    25  		t.Run("Test fails", func(t *testing.T) {
    26  			testFunc := func(ft *functional.T) {
    27  				ft.FailNow()
    28  			}
    29  			pass := functional.Run(ctx, testFunc)
    30  			assert.False(t, pass)
    31  		})
    32  
    33  		t.Run("Nested test", func(t *testing.T) {
    34  			t.Run("Passes", func(t *testing.T) {
    35  				testFunc := func(ft *functional.T) {
    36  					ft.Run("Subtest 1", func(_ *functional.T) {
    37  					})
    38  				}
    39  				pass := functional.Run(ctx, testFunc)
    40  				assert.True(t, pass)
    41  			})
    42  
    43  			t.Run("Fails", func(t *testing.T) {
    44  				testFunc := func(ft *functional.T) {
    45  					ft.Run("Subtest 1", func(ft *functional.T) {
    46  						ft.FailNow()
    47  					})
    48  				}
    49  				pass := functional.Run(ctx, testFunc)
    50  				assert.False(t, pass)
    51  			})
    52  		})
    53  
    54  		t.Run("WithWriter()", func(t *testing.T) {
    55  			testFunc := func(ft *functional.T) {
    56  				ft.Log("Foobar")
    57  			}
    58  			var buf bytes.Buffer
    59  			twriter := bufio.NewWriter(&buf)
    60  			pass := functional.Run(ctx, testFunc, functional.WithWriter(twriter))
    61  			assert.True(t, pass)
    62  			assert.Contains(t, "Foobar", buf.String())
    63  		})
    64  
    65  		t.Run("WithArgs()", func(t *testing.T) {
    66  			args := []string{"A", "B", "C"}
    67  			testFunc := func(ft *functional.T) {
    68  				assert.Equal(t, args, ft.Args())
    69  			}
    70  			pass := functional.Run(ctx, testFunc, functional.WithArgs(args...))
    71  			assert.True(t, pass)
    72  		})
    73  
    74  		t.Run("Skip", func(t *testing.T) {
    75  			var mutex sync.Mutex
    76  			var before, after bool
    77  			testFunc := func(ft *functional.T) {
    78  				mutex.Lock()
    79  				defer mutex.Unlock()
    80  				before = true
    81  				ft.SkipNow()
    82  				after = true
    83  			}
    84  			pass := functional.Run(ctx, testFunc)
    85  			assert.True(t, pass)
    86  
    87  			mutex.Lock()
    88  			defer mutex.Unlock()
    89  			assert.True(t, before)
    90  			assert.False(t, after)
    91  		})
    92  	})
    93  
    94  	t.Run("RunSuite()", func(t *testing.T) {
    95  		t.Run("Happy path", func(t *testing.T) {
    96  			var counter int
    97  			testFunc1 := func(_ *functional.T) {
    98  				counter++
    99  			}
   100  			testFunc2 := func(_ *functional.T) {
   101  				counter++
   102  			}
   103  			tests := []functional.TestFunc{testFunc1, testFunc2}
   104  			pass := functional.RunSuite(ctx, "Foobar suite", tests)
   105  			assert.True(t, pass)
   106  			assert.Equal(t, 2, counter)
   107  		})
   108  
   109  		t.Run("Partial failure", func(t *testing.T) {
   110  			var counter int
   111  			testFunc1 := func(_ *functional.T) {
   112  				counter++
   113  			}
   114  			testFunc2 := func(ft *functional.T) {
   115  				counter++
   116  				ft.FailNow()
   117  			}
   118  			tests := []functional.TestFunc{testFunc1, testFunc2}
   119  			pass := functional.RunSuite(ctx, "Foobar suite", tests)
   120  			assert.False(t, pass)
   121  			assert.Equal(t, 2, counter)
   122  		})
   123  
   124  		t.Run("Complete failure", func(t *testing.T) {
   125  			var counter int
   126  			testFunc1 := func(ft *functional.T) {
   127  				counter++
   128  				ft.FailNow()
   129  			}
   130  			testFunc2 := func(ft *functional.T) {
   131  				counter++
   132  				ft.FailNow()
   133  			}
   134  			tests := []functional.TestFunc{testFunc1, testFunc2}
   135  			pass := functional.RunSuite(ctx, "Foobar suite", tests)
   136  			assert.False(t, pass)
   137  			assert.Equal(t, 2, counter)
   138  		})
   139  	})
   140  
   141  	t.Run("RunBenchmarkTimes()", func(t *testing.T) {
   142  		t.Run("Happy path", func(t *testing.T) {
   143  			testCases := []struct {
   144  				Name  string
   145  				N     int
   146  				Delay time.Duration
   147  			}{
   148  				{Name: "Once", N: 1, Delay: 5 * time.Millisecond},
   149  				{Name: "2x", N: 2, Delay: 5 * time.Millisecond},
   150  				{Name: "100x", N: 100, Delay: 500 * time.Microsecond},
   151  			}
   152  
   153  			for _, testCase := range testCases {
   154  				t.Run(testCase.Name, func(t *testing.T) {
   155  					var counter int
   156  					benchmarkFunc := func(fb *functional.B) {
   157  						for i := 0; i < fb.N; i++ {
   158  							counter++
   159  							time.Sleep(testCase.Delay)
   160  						}
   161  					}
   162  					result := functional.RunBenchmarkTimes(ctx, benchmarkFunc, testCase.N)
   163  					assert.True(t, result.Pass)
   164  					assert.False(t, result.StartTime.IsZero())
   165  					assert.False(t, result.EndTime.IsZero())
   166  					assert.Equal(t, testCase.N, counter)
   167  				})
   168  			}
   169  		})
   170  
   171  		t.Run("Subtest has same N value", func(t *testing.T) {
   172  			const expectedN = 100
   173  			var counterFunc1, counterFunc2a int
   174  			benchmarkFunc := func(fb *functional.B) {
   175  				fb.Run("Func1", func(fb *functional.B) {
   176  					for i := 0; i < fb.N; i++ {
   177  						counterFunc1++
   178  					}
   179  				})
   180  				fb.Run("Func2", func(fb *functional.B) {
   181  					fb.Run("Func2a", func(fb *functional.B) {
   182  						for i := 0; i < fb.N; i++ {
   183  							counterFunc2a++
   184  						}
   185  					})
   186  				})
   187  			}
   188  
   189  			result := functional.RunBenchmarkTimes(ctx, benchmarkFunc, expectedN)
   190  			assert.True(t, result.Pass)
   191  			assert.Equal(t, expectedN, counterFunc1)
   192  			assert.Equal(t, expectedN, counterFunc2a)
   193  		})
   194  
   195  		t.Run("WithWriter()", func(t *testing.T) {
   196  			testFunc := func(fb *functional.B) {
   197  				fb.Log("Foobar")
   198  			}
   199  			var buf bytes.Buffer
   200  			bwriter := bufio.NewWriter(&buf)
   201  			result := functional.RunBenchmarkTimes(ctx, testFunc, 1, functional.WithWriter(bwriter))
   202  			assert.True(t, result.Pass)
   203  			assert.Contains(t, "Foobar", buf.String())
   204  		})
   205  
   206  		t.Run("WithArgs()", func(t *testing.T) {
   207  			args := []string{"A", "B", "C"}
   208  			testFunc := func(fb *functional.B) {
   209  				assert.Equal(t, args, fb.Args())
   210  			}
   211  			result := functional.RunBenchmarkTimes(ctx, testFunc, 1, functional.WithArgs(args...))
   212  			assert.True(t, result.Pass)
   213  		})
   214  
   215  		t.Run("Benchmark fails", func(t *testing.T) {
   216  			testFunc := func(fb *functional.B) {
   217  				fb.FailNow()
   218  			}
   219  			result := functional.RunBenchmarkTimes(ctx, testFunc, 1)
   220  			assert.False(t, result.Pass)
   221  		})
   222  
   223  		t.Run("Nested benchmark", func(t *testing.T) {
   224  			t.Run("Passes", func(t *testing.T) {
   225  				benchFunc := func(fb *functional.B) {
   226  					fb.Run("Subtest 1", func(_ *functional.B) {
   227  					})
   228  				}
   229  				result := functional.RunBenchmarkTimes(ctx, benchFunc, 1)
   230  				assert.True(t, result.Pass)
   231  			})
   232  
   233  			t.Run("Fails", func(t *testing.T) {
   234  				benchFunc := func(fb *functional.B) {
   235  					fb.Run("Subtest 1", func(b *functional.B) {
   236  						b.FailNow()
   237  					})
   238  				}
   239  				result := functional.RunBenchmarkTimes(ctx, benchFunc, 1)
   240  				assert.False(t, result.Pass)
   241  			})
   242  		})
   243  
   244  		t.Run("Skip", func(t *testing.T) {
   245  			var mutex sync.Mutex
   246  			var before, after bool
   247  			testFunc := func(fb *functional.B) {
   248  				mutex.Lock()
   249  				defer mutex.Unlock()
   250  				before = true
   251  				fb.SkipNow()
   252  				after = true
   253  			}
   254  			result := functional.RunBenchmarkTimes(ctx, testFunc, 1)
   255  			assert.True(t, result.Pass)
   256  
   257  			mutex.Lock()
   258  			defer mutex.Unlock()
   259  			assert.True(t, before)
   260  			assert.False(t, after)
   261  		})
   262  	})
   263  
   264  	t.Run("RunBenchmarkSuiteTimes()", func(t *testing.T) {
   265  		const times = 5
   266  
   267  		t.Run("Happy path", func(t *testing.T) {
   268  			var counter int
   269  			testFunc1 := func(fb *functional.B) {
   270  				counter += fb.N
   271  			}
   272  			testFunc2 := func(fb *functional.B) {
   273  				counter += fb.N
   274  			}
   275  			tests := []functional.BenchmarkFunc{testFunc1, testFunc2}
   276  			pass := functional.RunBenchmarkSuiteTimes(ctx, "Foobar suite", times, tests)
   277  			assert.True(t, pass)
   278  			assert.Equal(t, 2*times, counter)
   279  		})
   280  
   281  		t.Run("Partial failure", func(t *testing.T) {
   282  			var counter int
   283  			testFunc1 := func(fb *functional.B) {
   284  				counter += fb.N
   285  			}
   286  			testFunc2 := func(fb *functional.B) {
   287  				counter += fb.N
   288  				fb.FailNow()
   289  			}
   290  			tests := []functional.BenchmarkFunc{testFunc1, testFunc2}
   291  			pass := functional.RunBenchmarkSuiteTimes(ctx, "Foobar suite", times, tests)
   292  			assert.False(t, pass)
   293  			assert.Equal(t, 2*times, counter)
   294  		})
   295  
   296  		t.Run("Complete failure", func(t *testing.T) {
   297  			var counter int
   298  			testFunc1 := func(fb *functional.B) {
   299  				counter += fb.N
   300  				fb.FailNow()
   301  			}
   302  			testFunc2 := func(fb *functional.B) {
   303  				counter += fb.N
   304  				fb.FailNow()
   305  			}
   306  			tests := []functional.BenchmarkFunc{testFunc1, testFunc2}
   307  			pass := functional.RunBenchmarkSuiteTimes(ctx, "Foobar suite", times, tests)
   308  			assert.False(t, pass)
   309  			assert.Equal(t, 2*times, counter)
   310  		})
   311  	})
   312  }