github.com/KEINOS/go-countline@v1.1.0/cl/_alt/alt_test.go (about)

     1  // ============================================================================
     2  //
     3  //	Alternate implementations of CountLines function
     4  //
     5  // ============================================================================
     6  //
     7  //	This file contains the alternate implementations of CountLines().
     8  //	We benchmark them to see which one is the fastest.
     9  //
    10  //	Note that all implementations MUST pass the test for specifications.
    11  //	See the "Spec Tests" section below.
    12  //
    13  //nolint:revive,stylecheck
    14  package _alt
    15  
    16  import (
    17  	"bytes"
    18  	"io"
    19  	"testing"
    20  
    21  	"github.com/KEINOS/go-countline/cl/spec"
    22  	"github.com/pkg/errors"
    23  	"github.com/stretchr/testify/require"
    24  )
    25  
    26  // ============================================================================
    27  //  Tests
    28  // ============================================================================
    29  //  Specification tests for alternate implementations of CountLines().
    30  
    31  //nolint:paralleltest
    32  func TestCountLines_specs(t *testing.T) {
    33  	for _, targetFunc := range []struct {
    34  		name string
    35  		fn   func(io.Reader) (int, error)
    36  	}{
    37  		// Add the alternate implementations here.
    38  		{"CountLinesAlt1", CountLinesAlt1},
    39  		{"CountLinesAlt2", CountLinesAlt2},
    40  		{"CountLinesAlt3", CountLinesAlt3},
    41  		{"CountLinesAlt4", CountLinesAlt4},
    42  		{"CountLinesAlt5", CountLinesAlt5},
    43  	} {
    44  		t.Run(targetFunc.name, func(t *testing.T) {
    45  			spec.RunSpecTest(t, targetFunc.name, targetFunc.fn)
    46  		})
    47  
    48  		t.Run(targetFunc.name+"_nil_input", func(t *testing.T) {
    49  			numLines, err := targetFunc.fn(nil)
    50  
    51  			require.Error(t, err, "should return an error on nil input")
    52  			require.Equal(t, 0, numLines, "returned number of lines should be 0 on error")
    53  		})
    54  
    55  		t.Run(targetFunc.name+"_io_read_fail", func(t *testing.T) {
    56  			dummyReader := &DummyReader{msg: "forced error"}
    57  
    58  			numLines, err := targetFunc.fn(dummyReader)
    59  
    60  			require.Error(t, err, "it should return an error on io.Reader read failure")
    61  			require.Equal(t, 0, numLines, "returned number of lines should be 0 on error")
    62  			require.Contains(t, err.Error(), "forced error", "the returned error should contain the reason of the error")
    63  		})
    64  
    65  		t.Run(targetFunc.name+"_zero_padded", func(t *testing.T) {
    66  			// Create a dummy reader with zero-padded/capped bytes
    67  			dummyReader := bytes.NewReader(make([]byte, 1024))
    68  
    69  			_, err := targetFunc.fn(dummyReader)
    70  
    71  			require.NoError(t, err, "it should not return an error on zero padded/empty capped byte slice input")
    72  		})
    73  	}
    74  }
    75  
    76  // DummyReader is a dummy io.Reader that returns an error on Read().
    77  type DummyReader struct {
    78  	msg string
    79  }
    80  
    81  // Read implements io.Reader interface. This method always returns an error with the msg field.
    82  func (r *DummyReader) Read(p []byte) (int, error) {
    83  	return 0, errors.New(r.msg)
    84  }