Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding ValidateOpts #295

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions checkDetail.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,12 @@ func (cd *CheckDetail) String() string {
// Validate performs imagecashletter format rule checks on the record and returns an error if not Validated
// The first error encountered is returned and stops the parsing.
func (cd *CheckDetail) Validate() error {
return cd.ValidateWithOpts(ValidateOpts{}) // all options should be defined so the default value (false) results in the default (current) behavior
}

// ValidateWithOpts performs imagecashletter format rule checks with validate opts
func (cd *CheckDetail) ValidateWithOpts(opts ValidateOpts) error {
mfdeveloper508 marked this conversation as resolved.
Show resolved Hide resolved

if err := cd.fieldInclusion(); err != nil {
return err
}
Expand Down Expand Up @@ -283,12 +289,16 @@ func (cd *CheckDetail) Validate() error {
return &FieldError{FieldName: "CorrectionIndicator", Value: cd.CorrectionIndicatorField(), Msg: err.Error()}
}
}
// Conditional
if cd.ArchiveTypeIndicator != "" {
if err := cd.isArchiveTypeIndicator(cd.ArchiveTypeIndicator); err != nil {
return &FieldError{FieldName: "ArchiveTypeIndicator", Value: cd.ArchiveTypeIndicator, Msg: err.Error()}

if !opts.SkipAll {
// Conditional
if cd.ArchiveTypeIndicator != "" && !opts.AllowInvalidArchiveTypeIndicator {
if err := cd.isArchiveTypeIndicator(cd.ArchiveTypeIndicator); err != nil {
return &FieldError{FieldName: "ArchiveTypeIndicator", Value: cd.ArchiveTypeIndicator, Msg: err.Error()}
}
}
}

return nil
}

Expand Down
9 changes: 9 additions & 0 deletions checkDetail_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,15 @@ func TestCDArchiveTypeIndicator(t *testing.T) {
}
}

// TestCDArchiveTypeIndicatorWithValidationOption validation
func TestCDArchiveTypeIndicatorWithValidationOption(t *testing.T) {
cd := mockCheckDetail()
cd.ArchiveTypeIndicator = "W"
if err := cd.ValidateWithOpts(ValidateOpts{AllowInvalidArchiveTypeIndicator: true}); err != nil {
t.Errorf("%T: %s", err, err)
}
}

// Field Inclusion

// TestCDFIRecordType validation
Expand Down
38 changes: 38 additions & 0 deletions cmd/writeImageCashLetter/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ var (

// output formats
flagJson = flag.Bool("json", false, "Output file in json")

flagSkipValidation = flag.Bool("skip-validation", false, "Skip all validation checks")
flagValidateOpts = flag.String("validate", "", "Path to config file in json format to enable validation opts")
)

// main creates an ICL File with 2 CashLetters
Expand Down Expand Up @@ -72,6 +75,12 @@ func write(path string) {
file := imagecashletter.NewFile()
file.SetHeader(fh)

// Read validation options from the command
validateOpts := readValidationOpts(*flagValidateOpts)
if validateOpts != nil {
file.SetValidation(validateOpts)
}

// Create 4 CashLetters
for i := 0; i < 4; i++ {

Expand Down Expand Up @@ -284,3 +293,32 @@ func write(path string) {
fmt.Printf("Wrote %s\n", path)

}

func readValidationOpts(path string) *imagecashletter.ValidateOpts {
if path != "" {
// read config file
bs, readErr := os.ReadFile(path)
if readErr != nil {
fmt.Printf("ERROR: reading validate opts failed: %v\n", readErr)
os.Exit(1)
}

var opts imagecashletter.ValidateOpts
if err := json.Unmarshal(bs, &opts); err != nil {
fmt.Printf("ERROR: unmarshal of validate opts failed: %v\n", err)
os.Exit(1)
}
if *flagSkipValidation {
opts.SkipAll = true
}
return &opts
}

if *flagSkipValidation {
var opts imagecashletter.ValidateOpts
opts.SkipAll = true
return &opts
}

return nil
}
35 changes: 35 additions & 0 deletions cmd/writeImageCashLetter/main_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package main

import (
"encoding/json"
"os"
"testing"

"github.com/moov-io/imagecashletter"
)

// TestFileCreate tests creating an ICL File
Expand Down Expand Up @@ -36,3 +39,35 @@ func testFileWrite(t testing.TB) {
t.Fatal("expected non-empty file")
}
}

// TestReadValidationOpts
func TestReadValidationOpts(t *testing.T) {
tmp, err := os.CreateTemp("", "config")
if err != nil {
t.Fatal(err.Error())
}
defer os.Remove(tmp.Name())

f, err := os.Create(tmp.Name())
if err != nil {
t.Fatal(err.Error())
}

buf, _ := json.Marshal(&imagecashletter.ValidateOpts{})
f.Write(buf)
f.Close()

if opt := readValidationOpts(tmp.Name()); opt == nil {
t.Fatal("unable to create config")
}

if opt := readValidationOpts(""); opt != nil {
t.Fatal("does not to create any config")
}

*flagSkipValidation = true
if opt := readValidationOpts(""); opt == nil {
t.Fatal("unable to create config")
}

}
28 changes: 28 additions & 0 deletions file.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,15 @@ var (
msgFileCredit = "Credit outside of cash letter"
)

// ValidateOpts contains specific overrides from the default set of validations
type ValidateOpts struct {
// SkipAll will disable all validation checks of a File. It has no effect when set on records.
SkipAll bool `json:"skipAll"`
Comment on lines +96 to +97
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SkipAll can be checked inside File.Validate() to bypass all checks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exact validation function of record will hit within reader function only
it seems that we should use skipall flag in validation function of record


// AllowInvalidArchiveTypeIndicator can be set to disable archiveTypeIndicator validation
AllowInvalidArchiveTypeIndicator bool `json:"allowInvalidArchiveType"`
}

// FileError is an error describing issues validating a file
type FileError struct {
FieldName string
Expand Down Expand Up @@ -119,6 +128,8 @@ type File struct {
Bundles []Bundle `json:"bundle,omitempty"`
// FileControl is an imagecashletter FileControl
Control FileControl `json:"fileControl"`

validateOpts *ValidateOpts
}

// NewFile constructs a file template with a FileHeader and FileControl.
Expand Down Expand Up @@ -322,3 +333,20 @@ func (f *File) setRecordTypes() {
}
f.Control.setRecordType()
}

// SetValidation stores ValidateOpts
func (f *File) SetValidation(opts *ValidateOpts) {
if f == nil || opts == nil {
return
}

f.validateOpts = opts
}

// ValidateOpts returns Validation option
func (f *File) ValidateOpts() *ValidateOpts {
if f.validateOpts == nil {
return &ValidateOpts{}
}
return f.validateOpts
}
2 changes: 1 addition & 1 deletion reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ func (r *Reader) parseCheckDetail() error {
cd := new(CheckDetail)
cd.Parse(r.decodeLine(r.line))
// Ensure valid CheckDetail
if err := cd.Validate(); err != nil {
if err := cd.ValidateWithOpts(*r.File.ValidateOpts()); err != nil {
return r.error(err)
}
// Add CheckDetail
Expand Down
16 changes: 13 additions & 3 deletions returnDetail.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,12 @@ func (rd *ReturnDetail) String() string {
// Validate performs image cash letter format rule checks on the record and returns an error if not Validated
// The first error encountered is returned and stops the parsing.
func (rd *ReturnDetail) Validate() error {
return rd.ValidateWithOpts(ValidateOpts{}) // all options should be defined so the default value (false) results in the default (current) behavior
}

// ValidateWithOpts performs imagecashletter format rule checks with validate opts
func (rd *ReturnDetail) ValidateWithOpts(opts ValidateOpts) error {

if err := rd.fieldInclusion(); err != nil {
return err
}
Expand All @@ -288,11 +294,15 @@ func (rd *ReturnDetail) Validate() error {
return &FieldError{FieldName: "ReturnNotificationIndicator", Value: rd.ReturnNotificationIndicatorField(), Msg: err.Error()}
}
}
if rd.ArchiveTypeIndicator != "" {
if err := rd.isArchiveTypeIndicator(rd.ArchiveTypeIndicator); err != nil {
return &FieldError{FieldName: "ArchiveTypeIndicator", Value: rd.ArchiveTypeIndicatorField(), Msg: err.Error()}

if !opts.SkipAll {
if rd.ArchiveTypeIndicator != "" && !opts.AllowInvalidArchiveTypeIndicator {
if err := rd.isArchiveTypeIndicator(rd.ArchiveTypeIndicator); err != nil {
return &FieldError{FieldName: "ArchiveTypeIndicator", Value: rd.ArchiveTypeIndicatorField(), Msg: err.Error()}
}
}
}

if rd.TimesReturnedField() != " " && rd.TimesReturnedField() != "" {
if err := rd.isTimesReturned(rd.TimesReturned); err != nil {
return &FieldError{FieldName: "TimesReturned", Value: rd.TimesReturnedField(), Msg: err.Error()}
Expand Down
9 changes: 9 additions & 0 deletions returnDetail_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,15 @@ func TestRDArchiveTypeIndicator(t *testing.T) {
}
}

// TestRDArchiveTypeIndicatorWithValidationOption validation
func TestRDArchiveTypeIndicatorWithValidationOption(t *testing.T) {
rd := mockReturnDetail()
rd.ArchiveTypeIndicator = "W"
if err := rd.ValidateWithOpts(ValidateOpts{AllowInvalidArchiveTypeIndicator: true}); err != nil {
t.Errorf("%T: %s", err, err)
}
}

// TestRDTimesReturned validation
func TestRDTimesReturned(t *testing.T) {
rd := mockReturnDetail()
Expand Down