github.com/moov-io/imagecashletter@v0.10.1/writer_test.go (about)

     1  // Copyright 2020 The Moov Authors
     2  // Use of this source code is governed by an Apache License
     3  // license that can be found in the LICENSE file.
     4  
     5  package imagecashletter
     6  
     7  import (
     8  	"bytes"
     9  	"os"
    10  	"path/filepath"
    11  	"strings"
    12  	"testing"
    13  
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  // TestICLWrite writes an ICL File
    18  func TestICLWrite(t *testing.T) {
    19  	file := NewFile().SetHeader(mockFileHeader())
    20  
    21  	// Create CheckDetail
    22  	cd := mockCheckDetail()
    23  	cd.AddCheckDetailAddendumA(mockCheckDetailAddendumA())
    24  	cd.AddCheckDetailAddendumB(mockCheckDetailAddendumB())
    25  	cd.AddCheckDetailAddendumC(mockCheckDetailAddendumC())
    26  	cd.AddImageViewDetail(mockImageViewDetail())
    27  	cd.AddImageViewData(mockImageViewData())
    28  	cd.AddImageViewAnalysis(mockImageViewAnalysis())
    29  	bundle := NewBundle(mockBundleHeader())
    30  	bundle.AddCheckDetail(cd)
    31  
    32  	// CheckDetail 2
    33  	cdTwo := mockCheckDetail()
    34  	cdTwo.AddCheckDetailAddendumA(mockCheckDetailAddendumA())
    35  	cdTwo.AddCheckDetailAddendumB(mockCheckDetailAddendumB())
    36  	cdTwo.AddCheckDetailAddendumC(mockCheckDetailAddendumC())
    37  	cdTwo.AddImageViewDetail(mockImageViewDetail())
    38  	cdTwo.AddImageViewData(mockImageViewData())
    39  	cdTwo.AddImageViewAnalysis(mockImageViewAnalysis())
    40  	bundle.AddCheckDetail(cdTwo)
    41  
    42  	// Create ReturnDetail
    43  	rd := mockReturnDetail()
    44  	rd.AddReturnDetailAddendumA(mockReturnDetailAddendumA())
    45  	rd.AddReturnDetailAddendumB(mockReturnDetailAddendumB())
    46  	rd.AddReturnDetailAddendumC(mockReturnDetailAddendumC())
    47  	rd.AddReturnDetailAddendumD(mockReturnDetailAddendumD())
    48  	rd.AddImageViewDetail(mockImageViewDetail())
    49  	rd.AddImageViewData(mockImageViewData())
    50  	rd.AddImageViewAnalysis(mockImageViewAnalysis())
    51  	returnBundle := NewBundle(mockBundleHeader())
    52  	returnBundle.BundleHeader.BundleSequenceNumber = "2"
    53  	returnBundle.AddReturnDetail(rd)
    54  
    55  	rdTwo := mockReturnDetail()
    56  	rdTwo.AddReturnDetailAddendumA(mockReturnDetailAddendumA())
    57  	rdTwo.AddReturnDetailAddendumB(mockReturnDetailAddendumB())
    58  	rdTwo.AddReturnDetailAddendumC(mockReturnDetailAddendumC())
    59  	rdTwo.AddReturnDetailAddendumD(mockReturnDetailAddendumD())
    60  	rdTwo.AddImageViewDetail(mockImageViewDetail())
    61  	rdTwo.AddImageViewData(mockImageViewData())
    62  	rdTwo.AddImageViewAnalysis(mockImageViewAnalysis())
    63  	returnBundle.AddReturnDetail(rdTwo)
    64  
    65  	// Create CashLetter
    66  	cl := NewCashLetter(mockCashLetterHeader())
    67  	cl.AddBundle(bundle)
    68  	cl.AddBundle(returnBundle)
    69  	require.NoError(t, cl.Create())
    70  	file.AddCashLetter(cl)
    71  
    72  	clTwo := NewCashLetter(mockCashLetterHeader())
    73  	clTwo.CashLetterHeader.CashLetterID = "A2"
    74  	clTwo.AddBundle(bundle)
    75  	clTwo.AddBundle(returnBundle)
    76  	require.NoError(t, clTwo.Create())
    77  	file.AddCashLetter(clTwo)
    78  
    79  	// Create file
    80  	require.NoError(t, file.Create())
    81  	require.NoError(t, file.Validate())
    82  
    83  	b := &bytes.Buffer{}
    84  	f := NewWriter(b)
    85  	require.NoError(t, f.Write(file))
    86  
    87  	r := NewReader(strings.NewReader(b.String()))
    88  	_, err := r.Read()
    89  	require.NoError(t, err)
    90  	require.NoError(t, r.File.Validate())
    91  }
    92  
    93  // TestICLWriteCreditItem writes an ICL file with a CreditItem
    94  func TestICLWriteCreditItem(t *testing.T) {
    95  	file := NewFile().SetHeader(mockFileHeader())
    96  
    97  	// CreditItem
    98  	ci := mockCreditItem()
    99  
   100  	// Create CheckDetail
   101  	cd := mockCheckDetail()
   102  	cd.AddCheckDetailAddendumA(mockCheckDetailAddendumA())
   103  	cd.AddCheckDetailAddendumB(mockCheckDetailAddendumB())
   104  	cd.AddCheckDetailAddendumC(mockCheckDetailAddendumC())
   105  	cd.AddImageViewDetail(mockImageViewDetail())
   106  	cd.AddImageViewData(mockImageViewData())
   107  	cd.AddImageViewAnalysis(mockImageViewAnalysis())
   108  	bundle := NewBundle(mockBundleHeader())
   109  	bundle.AddCheckDetail(cd)
   110  
   111  	// CheckDetail 2
   112  	cdTwo := mockCheckDetail()
   113  	cdTwo.AddCheckDetailAddendumA(mockCheckDetailAddendumA())
   114  	cdTwo.AddCheckDetailAddendumB(mockCheckDetailAddendumB())
   115  	cdTwo.AddCheckDetailAddendumC(mockCheckDetailAddendumC())
   116  	cdTwo.AddImageViewDetail(mockImageViewDetail())
   117  	cdTwo.AddImageViewData(mockImageViewData())
   118  	cdTwo.AddImageViewAnalysis(mockImageViewAnalysis())
   119  	bundle.AddCheckDetail(cdTwo)
   120  
   121  	// Create CashLetter
   122  	cl := NewCashLetter(mockCashLetterHeader())
   123  	cl.AddCreditItem(ci)
   124  	cl.AddBundle(bundle)
   125  	require.NoError(t, cl.Create())
   126  	file.AddCashLetter(cl)
   127  
   128  	clTwo := NewCashLetter(mockCashLetterHeader())
   129  	clTwo.CashLetterHeader.CashLetterID = "A2"
   130  	clTwo.AddBundle(bundle)
   131  
   132  	require.NoError(t, clTwo.Create())
   133  	file.AddCashLetter(clTwo)
   134  
   135  	// Create file
   136  	require.NoError(t, file.Create())
   137  	require.NoError(t, file.Validate())
   138  
   139  	b := &bytes.Buffer{}
   140  	f := NewWriter(b)
   141  	require.NoError(t, f.Write(file))
   142  
   143  	r := NewReader(strings.NewReader(b.String()))
   144  	_, err := r.Read()
   145  	require.NoError(t, err)
   146  	require.NoError(t, r.File.Validate())
   147  }
   148  
   149  // TestICLWriteCreditRecord writes an ICL file with a Credit record
   150  func TestICLWriteCreditRecord(t *testing.T) {
   151  	file := NewFile().SetHeader(mockFileHeader())
   152  
   153  	// CreditItem
   154  	ci := mockCredit()
   155  
   156  	// Create CheckDetail
   157  	cd := mockCheckDetail()
   158  	cd.AddCheckDetailAddendumA(mockCheckDetailAddendumA())
   159  	cd.AddCheckDetailAddendumB(mockCheckDetailAddendumB())
   160  	cd.AddCheckDetailAddendumC(mockCheckDetailAddendumC())
   161  	cd.AddImageViewDetail(mockImageViewDetail())
   162  	cd.AddImageViewData(mockImageViewData())
   163  	cd.AddImageViewAnalysis(mockImageViewAnalysis())
   164  	bundle := NewBundle(mockBundleHeader())
   165  	bundle.AddCheckDetail(cd)
   166  
   167  	// CheckDetail 2
   168  	cdTwo := mockCheckDetail()
   169  	cdTwo.AddCheckDetailAddendumA(mockCheckDetailAddendumA())
   170  	cdTwo.AddCheckDetailAddendumB(mockCheckDetailAddendumB())
   171  	cdTwo.AddCheckDetailAddendumC(mockCheckDetailAddendumC())
   172  	cdTwo.AddImageViewDetail(mockImageViewDetail())
   173  	cdTwo.AddImageViewData(mockImageViewData())
   174  	cdTwo.AddImageViewAnalysis(mockImageViewAnalysis())
   175  	bundle.AddCheckDetail(cdTwo)
   176  
   177  	// Create CashLetter
   178  	cl := NewCashLetter(mockCashLetterHeader())
   179  	cl.AddCredit(ci)
   180  	cl.AddBundle(bundle)
   181  	require.NoError(t, cl.Create())
   182  	file.AddCashLetter(cl)
   183  
   184  	clTwo := NewCashLetter(mockCashLetterHeader())
   185  	clTwo.CashLetterHeader.CashLetterID = "A2"
   186  	clTwo.AddBundle(bundle)
   187  
   188  	require.NoError(t, clTwo.Create())
   189  	file.AddCashLetter(clTwo)
   190  
   191  	// Create file
   192  	require.NoError(t, file.Create())
   193  	require.NoError(t, file.Validate())
   194  
   195  	b := &bytes.Buffer{}
   196  	f := NewWriter(b)
   197  	require.NoError(t, f.Write(file))
   198  
   199  	r := NewReader(strings.NewReader(b.String()))
   200  	_, err := r.Read()
   201  	require.NoError(t, err)
   202  	require.NoError(t, r.File.Validate())
   203  }
   204  
   205  // TestICLWriteRoutingNumberSummary writes an ICL file with a RoutingNumberSummary
   206  func TestICLWriteRoutingNumber(t *testing.T) {
   207  	file := NewFile().SetHeader(mockFileHeader())
   208  
   209  	// RoutingNumberSummary
   210  	rns := mockRoutingNumberSummary()
   211  
   212  	// Create CheckDetail
   213  	cd := mockCheckDetail()
   214  	cd.AddCheckDetailAddendumA(mockCheckDetailAddendumA())
   215  	cd.AddCheckDetailAddendumB(mockCheckDetailAddendumB())
   216  	cd.AddCheckDetailAddendumC(mockCheckDetailAddendumC())
   217  	cd.AddImageViewDetail(mockImageViewDetail())
   218  	cd.AddImageViewData(mockImageViewData())
   219  	cd.AddImageViewAnalysis(mockImageViewAnalysis())
   220  	bundle := NewBundle(mockBundleHeader())
   221  	bundle.AddCheckDetail(cd)
   222  
   223  	// Create CashLetter
   224  	cl := NewCashLetter(mockCashLetterHeader())
   225  	cl.AddBundle(bundle)
   226  	cl.AddRoutingNumberSummary(rns)
   227  	require.NoError(t, cl.Create())
   228  	file.AddCashLetter(cl)
   229  
   230  	// Create file
   231  	require.NoError(t, file.Create())
   232  	require.NoError(t, file.Validate())
   233  
   234  	b := &bytes.Buffer{}
   235  	f := NewWriter(b)
   236  	require.NoError(t, f.Write(file))
   237  
   238  	r := NewReader(strings.NewReader(b.String()))
   239  	_, err := r.Read()
   240  	require.NoError(t, err)
   241  	require.NoError(t, r.File.Validate())
   242  }
   243  
   244  func TestICLWrite_VariableLengthOption(t *testing.T) {
   245  	fileBytes, err := os.ReadFile(filepath.Join("test", "testdata", "valid-ascii.x937"))
   246  	require.NoError(t, err)
   247  
   248  	fd := bytes.NewReader(fileBytes)
   249  	r := NewReader(fd, ReadVariableLineLengthOption())
   250  	file, err := r.Read()
   251  	require.NoError(t, err)
   252  
   253  	b := &bytes.Buffer{}
   254  	w := NewWriter(b, WriteVariableLineLengthOption())
   255  	require.NoError(t, w.Write(&file))
   256  	require.Equal(t, fileBytes, b.Bytes())
   257  }
   258  
   259  func TestICLWrite_EbcdicEncodingOption(t *testing.T) {
   260  	fileBytes, err := os.ReadFile(filepath.Join("test", "testdata", "valid-ebcdic.x937"))
   261  	require.NoError(t, err)
   262  
   263  	fd := bytes.NewReader(fileBytes)
   264  	r := NewReader(fd, ReadVariableLineLengthOption(), ReadEbcdicEncodingOption())
   265  	file, err := r.Read()
   266  	require.NoError(t, err)
   267  
   268  	b := &bytes.Buffer{}
   269  	w := NewWriter(b, WriteVariableLineLengthOption(), WriteEbcdicEncodingOption())
   270  	require.NoError(t, w.Write(&file))
   271  	require.Equal(t, fileBytes, b.Bytes())
   272  }
   273  
   274  func TestWriter_CollateErr(t *testing.T) {
   275  	cd := &CheckDetail{
   276  		// Create a CheckDetail without a corresponding ImageData or ImageViewAnalysis
   277  		// so when we attempt to collate them it doesn't crash.
   278  		ImageViewDetail: []ImageViewDetail{
   279  			mockImageViewDetail(),
   280  			mockImageViewDetail(),
   281  		},
   282  		// To trigger the crash this issue fixes we need two ImageViewDetails, and one ImageData.
   283  		// Having one ImageViewAnalysis would work as well
   284  		ImageViewData: []ImageViewData{
   285  			mockImageViewData(),
   286  		},
   287  		ImageViewAnalysis: []ImageViewAnalysis{
   288  			mockImageViewAnalysis(),
   289  		},
   290  	}
   291  
   292  	var buf bytes.Buffer
   293  	w := NewWriter(&buf)
   294  	require.ErrorContains(t, w.writeCheckImageView(cd), "ImageViewData does not match Image View Detail count of 1")
   295  }