From 9fc7ee2857839243f2c8a7ddf291a430dcc39e86 Mon Sep 17 00:00:00 2001 From: Jesse Coretta <{ID}+{username}@users.noreply.github.com> Date: Tue, 12 Nov 2024 03:40:05 -0800 Subject: [PATCH] Improved error handler (experimental), interface Identifier convenience method --- at.go | 52 ++++++++++++++++++++++++++++++++++++++- at_test.go | 38 ++++++++++++++++++++++++++++ dc.go | 64 ++++++++++++++++++++++++++++++++++++++++++++++-- dc_test.go | 38 ++++++++++++++++++++++++++++ ds.go | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++--- ds_test.go | 39 +++++++++++++++++++++++++++++ err.go | 5 ++++ ls.go | 48 +++++++++++++++++++++++++++++++++++- ls_test.go | 38 ++++++++++++++++++++++++++++ mr.go | 49 ++++++++++++++++++++++++++++++++++++- mr_test.go | 39 +++++++++++++++++++++++++++++ mu.go | 48 ++++++++++++++++++++++++++++++++++-- nf.go | 58 +++++++++++++++++++++++++++++++++++++++++-- nf_test.go | 40 ++++++++++++++++++++++++++++++ oc.go | 58 +++++++++++++++++++++++++++++++++++++++++-- oc_test.go | 38 ++++++++++++++++++++++++++++ type.go | 18 ++++++++++++++ 17 files changed, 727 insertions(+), 15 deletions(-) diff --git a/at.go b/at.go index e90e6fd..51c372d 100644 --- a/at.go +++ b/at.go @@ -131,6 +131,19 @@ func (r AttributeType) Marshal(def any) error { return nil } +/* +E returns the underlying error instance. +*/ +func (r AttributeType) E() (err error) { + if !r.IsZero() { + err = r.attributeType.err + } else { + err = ErrNilReceiver + } + + return +} + func (r AttributeType) marshalExt(key string, v any) { if hasPfx(key, `X-`) { switch tv := v.(type) { @@ -234,8 +247,10 @@ func (r AttributeType) Replace(x AttributeType) AttributeType { func (r *attributeType) replace(x AttributeType) { if r.OID == `` { + r.err = ErrMissingNumericOID return } else if r.OID != x.NumericOID() { + r.err = ErrInvalidOID return } @@ -713,6 +728,13 @@ func (r AttributeType) IsZero() bool { return r.attributeType == nil } +/* +Identifier returns the output of [AttributeType.OID] and is merely used +for an interface-friendly means of obtaining the principal identifier +of the receiver instance. +*/ +func (r AttributeType) Identifier() (ident string) { return r.OID() } + /* IsIdentifiedAs returns a Boolean value indicative of whether id matches either the numericOID or descriptor of the receiver instance. Case is @@ -864,6 +886,8 @@ func (r *attributeType) setNumericOID(id string) { if len(r.OID) == 0 { r.OID = id } + } else { + r.err = ErrInvalidOID } return @@ -916,9 +940,14 @@ func (r AttributeType) SetName(x ...string) AttributeType { } func (r *attributeType) setName(x ...string) { + b4 := r.Name.Len() for i := 0; i < len(x); i++ { r.Name.Push(x[i]) } + + if r.Name.Len()-len(x) != b4 { + r.err = ErrInvalidNames + } } /* @@ -1039,6 +1068,8 @@ func (r *attributeType) setStringer(function ...Stringer) { // Return a static value. return str } + } else { + r.err = err } return } @@ -1100,6 +1131,10 @@ func (r *attributeType) prepareString() (str string, err error) { } } + if err != nil { + r.err = err + } + return } @@ -1221,6 +1256,8 @@ func (r *attributeType) setSyntax(x any) { if def.Compliant() { r.Syntax = def + } else { + r.err = ErrInvalidSyntax } } @@ -1295,6 +1332,8 @@ func (r *attributeType) setEquality(x any) { if def.Compliant() { r.Equality = def + } else { + r.err = ErrEqualityRuleNotFound } } @@ -1369,6 +1408,8 @@ func (r *attributeType) setSubstring(x any) { if def.Compliant() { r.Substring = def + } else { + r.err = ErrSubstringRuleNotFound } } @@ -1443,6 +1484,8 @@ func (r *attributeType) setOrdering(x any) { if def.Compliant() { r.Ordering = def + } else { + r.err = ErrOrderingRuleNotFound } } @@ -1538,6 +1581,8 @@ func (r *attributeType) setSuperType(x any) { if def.Compliant() { r.SuperType = def + } else { + r.err = ErrSuperTypeNotFound } } @@ -1808,7 +1853,12 @@ func (r AttributeType) Compliant() bool { // Any combination of SV/C is permitted // EXCEPT for BOTH. See RFC 3671. - return !(r.SingleValue() && collective) + ok := !(r.SingleValue() && collective) + if ok { + r.attributeType.err = nil + } + + return ok } /* diff --git a/at_test.go b/at_test.go index 5047a68..780f3ae 100644 --- a/at_test.go +++ b/at_test.go @@ -82,6 +82,44 @@ func ExampleAttributeType_SubTypes() { // Output: 15 subordinate types found } +/* +This example demonstrates the means for checking to see if the receiver +is in an error condition. +*/ +func ExampleAttributeType_E() { + def := mySchema.NewAttributeType() + def.SetNumericOID(`23jklm5.1`) // bogus + if err := def.E(); err != nil { + fmt.Println(err) + } + // Output: Numeric OID is invalid +} + +/* +This example demonstrates the means for resolving an error condition. +*/ +func ExampleAttributeType_E_clearError() { + def := mySchema.NewAttributeType() + def.SetNumericOID(`23jklm5.1`) // bogus + + // We realized our mistake. + def.SetNumericOID(`1.3.6.1.4.1.56521.999.8.4.1.1`) // valid + + // But when we check again, the error is still there. + if def.E() != nil { + //fmt.Println(... the error ...) + } + + // We must clear the error with a + // passing compliance check. + if def.Compliant(); def.E() == nil { + fmt.Println("Error has been resolved") + } + // Output: Error has been resolved + + return +} + /* This example demonstrates a compliancy check of the "name" [AttributeType]. diff --git a/dc.go b/dc.go index 1694d7b..1699112 100644 --- a/dc.go +++ b/dc.go @@ -22,6 +22,19 @@ func (r DITContentRule) Description() (desc string) { return } +/* +E returns the underlying error instance. +*/ +func (r DITContentRule) E() (err error) { + if !r.IsZero() { + err = r.dITContentRule.err + } else { + err = ErrNilReceiver + } + + return +} + /* DITContentRules returns the [DITContentRules] instance from within the receiver instance. @@ -343,6 +356,13 @@ func (r DITContentRules) oIDsStringer(_ ...any) (present string) { return } +/* +Identifier returns the output of [DITContentRule.OID] and is merely used +for an interface-friendly means of obtaining the principal identifier +of the receiver instance. +*/ +func (r DITContentRule) Identifier() (ident string) { return r.OID() } + /* IsIdentifiedAs returns a Boolean value indicative of whether id matches either the numericOID or descriptor of the receiver instance. Case is @@ -425,6 +445,10 @@ func (r *dITContentRule) setAux(m ...any) { r.Aux.Push(oc) } } + + if err != nil { + r.err = err + } } /* @@ -522,7 +546,12 @@ func (r DITContentRule) Compliant() bool { // if any dITStructureRule definitions exist, // make sure they don't produce a MUST/NOT // conflict. - return r.dsrComply(structural) + ok := r.dsrComply(structural) + if ok { + r.dITContentRule.err = nil + } + + return ok } func (r DITContentRule) dsrComply(structural ObjectClass) bool { @@ -782,9 +811,14 @@ func (r DITContentRule) SetName(x ...string) DITContentRule { } func (r *dITContentRule) setName(x ...string) { + b4 := r.Name.Len() for i := 0; i < len(x); i++ { r.Name.Push(x[i]) } + + if r.Name.Len()-len(x) != b4 { + r.err = ErrInvalidNames + } } /* @@ -882,8 +916,12 @@ func (r *dITContentRule) setNumericOID(id string) { oc := r.schema.ObjectClasses().Get(id) if oc.Kind() == StructuralKind { r.OID = oc + } else { + r.err = ErrIncompatStructuralClass } } + } else { + r.err = ErrInvalidOID } return @@ -932,6 +970,10 @@ func (r *dITContentRule) setMust(m ...any) { r.Must.Push(at) } } + + if err != nil { + r.err = err + } } /* @@ -977,6 +1019,10 @@ func (r *dITContentRule) setMay(m ...any) { r.May.Push(at) } } + + if err != nil { + r.err = err + } } /* @@ -1022,6 +1068,10 @@ func (r *dITContentRule) setNot(m ...any) { r.Not.Push(at) } } + + if err != nil { + r.err = err + } } /* @@ -1083,6 +1133,8 @@ func (r *dITContentRule) setStringer(function ...Stringer) { // Return a preserved value. return str } + } else { + r.err = err } } else { r.stringer = stringer @@ -1173,6 +1225,10 @@ func (r *dITContentRule) prepareString() (str string, err error) { } } + if err != nil { + r.err = err + } + return } @@ -1344,7 +1400,11 @@ func (r DITContentRule) Replace(x DITContentRule) DITContentRule { } func (r *dITContentRule) replace(x DITContentRule) { - if r.OID.NumericOID() != x.NumericOID() { + if r.OID.NumericOID() == `` { + r.err = ErrMissingNumericOID + return + } else if r.OID.NumericOID() != x.NumericOID() { + r.err = ErrInvalidOID return } diff --git a/dc_test.go b/dc_test.go index 5223d98..4e9d249 100644 --- a/dc_test.go +++ b/dc_test.go @@ -40,6 +40,44 @@ func ExampleDITContentRule_Marshal() { // X-ORIGIN 'RFCXXXX' ) } +/* +This example demonstrates the means for checking to see if the receiver +is in an error condition. +*/ +func ExampleDITContentRule_E() { + def := mySchema.NewDITContentRule() + def.SetNumericOID(`23jklm5.1`) // bogus + if err := def.E(); err != nil { + fmt.Println(err) + } + // Output: Numeric OID is invalid +} + +/* +This example demonstrates the means for resolving an error condition. +*/ +func ExampleDITContentRule_E_clearError() { + def := mySchema.NewDITContentRule() + def.SetNumericOID(`23jklm5.1`) // bogus + + // We realized our mistake. + def.SetNumericOID(mySchema.ObjectClasses().Get(`person`).NumericOID()) // valid + + // But when we check again, the error is still there. + if def.E() != nil { + //fmt.Println(... the error ...) + } + + // We must clear the error with a + // passing compliance check. + if def.Compliant(); def.E() == nil { + fmt.Println("Error has been resolved") + } + // Output: Error has been resolved + + return +} + /* This example demonstrates a compliancy check of the "account" [ObjectClass]. */ diff --git a/ds.go b/ds.go index cda65c4..2a1ad99 100644 --- a/ds.go +++ b/ds.go @@ -1,7 +1,5 @@ package schemax -//import "fmt" - /* ds.go contains all DIT structure rule related methods and functions. */ @@ -50,6 +48,19 @@ func (r DITStructureRule) schema() (s Schema) { return } +/* +E returns the underlying error instance. +*/ +func (r DITStructureRule) E() (err error) { + if !r.IsZero() { + err = r.dITStructureRule.err + } else { + err = ErrNilReceiver + } + + return +} + /* Replace overrides the receiver with x. Both must bear an identical numeric rule ID and x MUST be compliant. @@ -81,6 +92,7 @@ func (r *dITStructureRule) replace(x DITStructureRule) { if r == nil { r = newDITStructureRule() } else if r.ID != x.RuleID() { + r.err = ErrInvalidRuleID return } @@ -248,6 +260,7 @@ func (r DITStructureRule) Compliant() bool { // not apply. dc := r.schema().DITContentRules().Get(form.OC().OID()) if dc.IsZero() { + r.dITStructureRule.err = nil return true } @@ -262,6 +275,8 @@ func (r DITStructureRule) Compliant() bool { } } + r.dITStructureRule.err = nil + return true } @@ -339,6 +354,21 @@ func (r DITStructureRule) ID() (id string) { return } +/* +Identifier returns the first available instance identifier, which will +either be the DESC clause (output of [DITStructureRule.Name]) or the +rule identifier (output of [DITStructureRule.ID]). This method is merely +present to offer a convenient interface-friendly means of obtaining +the principal identifier of the receiver instance. +*/ +func (r DITStructureRule) Identifier() (ident string) { + if ident = r.Name(); len(ident) == 0 { + ident = r.ID() + } + + return +} + /* IsIdentifiedAs returns a Boolean value indicative of whether id matches either the numericOID or descriptor of the receiver instance. Case is @@ -475,8 +505,10 @@ func (r *dITStructureRule) setStringer(function ...Stringer) { stringer = function[0] } + var err error if stringer == nil { - str, err := r.prepareString() // perform one-time text/template op + var str string + str, err = r.prepareString() // perform one-time text/template op if err == nil { // Save the stringer r.stringer = func() string { @@ -487,6 +519,10 @@ func (r *dITStructureRule) setStringer(function ...Stringer) { } else { r.stringer = stringer } + + if err != nil { + r.err = err + } } /* @@ -525,9 +561,14 @@ func (r DITStructureRule) SetName(x ...string) DITStructureRule { } func (r *dITStructureRule) setName(x ...string) { + b4 := r.Name.Len() for i := 0; i < len(x); i++ { r.Name.Push(x[i]) } + + if r.Name.Len()-len(x) != b4 { + r.err = ErrInvalidNames + } } /* @@ -618,6 +659,7 @@ func (r DITStructureRule) SetRuleID(id any) DITStructureRule { } func (r *dITStructureRule) setRuleID(x any) { + var err error switch tv := x.(type) { case uint64: r.ID = uint(tv) @@ -626,11 +668,21 @@ func (r *dITStructureRule) setRuleID(x any) { case int: if tv >= 0 { r.ID = uint(tv) + } else { + err = ErrInvalidRuleID } case string: if z, ok := atoui(tv); ok { r.ID = z + } else { + err = ErrInvalidRuleID } + default: + err = ErrInvalidRuleID + } + + if err != nil { + r.err = err } return @@ -655,7 +707,8 @@ func (r DITStructureRule) SetSuperRule(m ...any) DITStructureRule { } func (r *dITStructureRule) setSuperRule(m ...any) { - for i := 0; i < len(m); i++ { + var err error + for i := 0; i < len(m) && err == nil; i++ { var def DITStructureRule switch tv := m[i].(type) { case uint64, uint, int: @@ -670,11 +723,16 @@ func (r *dITStructureRule) setSuperRule(m ...any) { case DITStructureRule: def = tv default: + err = ErrInvalidRuleID continue } r.SuperRules.Push(def) } + + if err != nil { + r.err = err + } } /* @@ -864,6 +922,8 @@ func (r *dITStructureRule) setForm(x any) { if !def.IsZero() { r.Form = def + } else { + r.err = ErrNameFormNotFound } } @@ -1426,6 +1486,10 @@ func (r *dITStructureRule) prepareString() (str string, err error) { } } + if err != nil { + r.err = err + } + return } diff --git a/ds_test.go b/ds_test.go index f51a034..3f21aa8 100644 --- a/ds_test.go +++ b/ds_test.go @@ -106,6 +106,45 @@ func ExampleDITStructureRule_NamedObjectClass() { // Output: uddiBusinessEntity } +/* +This example demonstrates the means for checking to see if the receiver +is in an error condition. +*/ +func ExampleDITStructureRule_E() { + def := mySchema.NewDITStructureRule() + def.SetRuleID("Z") // bogus + if err := def.E(); err != nil { + fmt.Println(err) + } + // Output: Invalid integer identifier for structure rule +} + +/* +This example demonstrates the means for resolving an error condition. +*/ +func ExampleDITStructureRule_E_clearError() { + def := mySchema.NewDITStructureRule() + def.SetRuleID(`X`) // bogus + + // We realized our mistake. + def.SetRuleID(30) // valid + def.SetForm(`domainNameForm`) + + // But when we check again, the error is still there. + if err := def.E(); err != nil { + // handle error + } + + // We must clear the error with a + // passing compliance check. + if def.Compliant(); def.E() == nil { + fmt.Println("Error has been resolved") + } + // Output: Error has been resolved + + return +} + /* This example demonstrates a compliancy check of a [DITStructureRule] instance. diff --git a/err.go b/err.go index ce8578d..b348675 100644 --- a/err.go +++ b/err.go @@ -22,6 +22,9 @@ var ( ErrNilSchemaRef error = errors.New("Receiver instance lacks a Schema reference") ErrDefNonCompliant error = errors.New("Definition failed compliance checks") ErrInvalidInput error = errors.New("Input instance not compatible") + ErrInvalidNames error = errors.New("One or more names (descr) are invalid") + ErrInvalidOID error = errors.New("Numeric OID is invalid") + ErrInvalidRuleID error = errors.New("Invalid integer identifier for structure rule") ErrInvalidSyntax error = errors.New("Value does not meet the prescribed syntax qualifications") ErrInvalidValue error = errors.New("Value does not meet the prescribed value qualifications") ErrNoMatch error = errors.New("Values do not match according to prescribed assertion match") @@ -31,7 +34,9 @@ var ( ErrNotEqual error = errors.New("Values are not equal") ErrMissingNumericOID error = errors.New("Missing or invalid numeric OID for definition") ErrInvalidDNOrFlatInt error = errors.New("Invalid DN or flattened integer") + ErrIncompatStructuralClass error = errors.New("Incompatible structural class for target") + ErrSuperTypeNotFound error = errors.New("SUP AttributeType not found") ErrOrderingRuleNotFound error = errors.New("ORDERING MatchingRule not found") ErrSubstringRuleNotFound error = errors.New("SUBSTR MatchingRule not found") ErrEqualityRuleNotFound error = errors.New("EQUALITY MatchingRule not found") diff --git a/ls.go b/ls.go index 9a68d57..ca6c972 100644 --- a/ls.go +++ b/ls.go @@ -10,6 +10,32 @@ func NewLDAPSyntaxes() LDAPSyntaxes { return r } +/* +E returns the underlying error instance. +*/ +func (r LDAPSyntax) E() (err error) { + if !r.IsZero() { + err = r.lDAPSyntax.err + } else { + err = ErrNilReceiver + } + + return +} + +/* +Identifier returns the first available instance identifier, which will +either be the DESC clause (output of [LDAPSyntax.Description]) or the +numeric OID (output of [LDAPSyntax.NumericOID]). +*/ +func (r LDAPSyntax) Identifier() (ident string) { + if ident = r.Description(); len(ident) == 0 { + ident = r.NumericOID() + } + + return +} + /* IsIdentifiedAs returns a Boolean value indicative of whether id matches either the numericOID or description of the receiver instance. Case is @@ -207,8 +233,12 @@ func (r LDAPSyntaxes) Compliant() bool { Compliant returns a Boolean value indicative of the receiver being fully compliant per the required clauses of [§ 4.1.5 of RFC 4512]: + - Instance must not be nil - Numeric OID must be present and valid +Successful returns result in the annihilation of the underlying error +instance. + [§ 4.1.5 of RFC 4512]: https://rfc-editor.org/rfc/rfc4512.html#section-4.1.5 */ func (r LDAPSyntax) Compliant() bool { @@ -216,7 +246,13 @@ func (r LDAPSyntax) Compliant() bool { return false } - return isNumericOID(r.lDAPSyntax.OID) + ok := isNumericOID(r.lDAPSyntax.OID) + if ok { + r.lDAPSyntax.err = nil + } + + return ok + } /* @@ -280,6 +316,8 @@ func (r *lDAPSyntax) setStringer(function ...Stringer) { // Return a preserved value. return str } + } else { + r.err = err } return } @@ -444,6 +482,8 @@ func (r *lDAPSyntax) setNumericOID(id string) { if len(r.OID) == 0 { r.OID = id } + } else { + r.err = ErrInvalidOID } return @@ -800,8 +840,10 @@ func (r LDAPSyntax) Replace(x LDAPSyntax) LDAPSyntax { func (r *lDAPSyntax) replace(x LDAPSyntax) { if r.OID == `` { + r.err = ErrMissingNumericOID return } else if r.OID != x.NumericOID() { + r.err = ErrInvalidOID return } @@ -838,6 +880,10 @@ func (r *lDAPSyntax) prepareString() (str string, err error) { } } + if err != nil { + r.err = err + } + return } diff --git a/ls_test.go b/ls_test.go index aafb977..b738f25 100644 --- a/ls_test.go +++ b/ls_test.go @@ -28,6 +28,44 @@ func ExampleLDAPSyntax_Marshal() { // X-NOT-HUMAN-READABLE 'TRUE' ) } +/* +This example demonstrates the means for checking to see if the receiver +is in an error condition. +*/ +func ExampleLDAPSyntax_E() { + def := mySchema.NewLDAPSyntax() + def.SetNumericOID(`23jklm5.1`) // bogus + if err := def.E(); err != nil { + fmt.Println(err) + } + // Output: Numeric OID is invalid +} + +/* +This example demonstrates the means for resolving an error condition. +*/ +func ExampleLDAPSyntax_E_clearError() { + def := mySchema.NewLDAPSyntax() + def.SetNumericOID(`23jklm5.1`) // bogus + + // We realized our mistake. + def.SetNumericOID(`1.3.6.1.4.1.56521.999.8.4.1.1`) // valid + + // But when we check again, the error is still there. + if def.E() != nil { + //fmt.Println(... the error ...) + } + + // We must clear the error with a + // passing compliance check. + if def.Compliant(); def.E() == nil { + fmt.Println("Error has been resolved") + } + // Output: Error has been resolved + + return +} + /* This example demonstrates the creation of a new [LDAPSyntax] instance which will be replaced in memory by another. This change diff --git a/mr.go b/mr.go index 2a6d644..46cba29 100644 --- a/mr.go +++ b/mr.go @@ -64,6 +64,19 @@ func newMatchingRule() *matchingRule { } } +/* +E returns the underlying error instance. +*/ +func (r MatchingRule) E() (err error) { + if !r.IsZero() { + err = r.matchingRule.err + } else { + err = ErrNilReceiver + } + + return +} + /* Replace overrides the receiver with x. Both must bear an identical numeric OID and x MUST be compliant. @@ -93,8 +106,10 @@ func (r MatchingRule) Replace(x MatchingRule) MatchingRule { func (r *matchingRule) replace(x MatchingRule) { if r.OID == `` { + r.err = ErrMissingNumericOID return } else if r.OID != x.NumericOID() { + r.err = ErrInvalidOID return } @@ -309,6 +324,8 @@ func (r *matchingRule) setNumericOID(id string) { if len(r.OID) == 0 { r.OID = id } + } else { + r.err = ErrInvalidOID } return @@ -415,6 +432,8 @@ func (r *matchingRule) setSyntax(x any) { if !def.IsZero() { r.Syntax = def + } else { + r.err = ErrInvalidSyntax } } @@ -504,6 +523,13 @@ func (r MatchingRule) Description() (desc string) { return } +/* +Identifier returns the output of [MatchingRule.OID] and is merely used +for an interface-friendly means of obtaining the principal identifier +of the receiver instance. +*/ +func (r MatchingRule) Identifier() (ident string) { return r.OID() } + /* IsIdentifiedAs returns a Boolean value indicative of whether id matches either the numericOID or descriptor of the receiver instance. Case is @@ -621,9 +647,14 @@ func (r MatchingRule) SetName(x ...string) MatchingRule { } func (r *matchingRule) setName(x ...string) { + b4 := r.Name.Len() for i := 0; i < len(x); i++ { r.Name.Push(x[i]) } + + if r.Name.Len()-len(x) != b4 { + r.err = ErrInvalidNames + } } /* @@ -850,6 +881,10 @@ func (r *matchingRule) prepareString() (str string, err error) { } } + if err != nil { + r.err = err + } + return } @@ -908,7 +943,12 @@ func (r MatchingRules) Compliant() bool { Compliant returns a Boolean value indicative of the receiver being fully compliant per the required clauses of [§ 4.1.3 of RFC 4512]: + - Instance must not be nil - Numeric OID must be present and valid + - Underlying [LDAPSyntax] instance must be valid + +Successful returns result in the annihilation of the underlying error +instance. [§ 4.1.3 of RFC 4512]: https://rfc-editor.org/rfc/rfc4512.html#section-4.1.3 */ @@ -921,7 +961,12 @@ func (r MatchingRule) Compliant() bool { return false } - return r.Syntax().Compliant() + ok := r.Syntax().Compliant() + if ok { + r.matchingRule.err = nil + } + + return ok } /* @@ -985,6 +1030,8 @@ func (r *matchingRule) setStringer(function ...Stringer) { // Return a preserved value. return str } + } else { + r.err = err } return } diff --git a/mr_test.go b/mr_test.go index 3ae2527..37df960 100644 --- a/mr_test.go +++ b/mr_test.go @@ -61,6 +61,45 @@ func ExampleMatchingRule_Parse() { // X-ORIGIN 'NOWHERE' ) } +/* +This example demonstrates the means for checking to see if the receiver +is in an error condition. +*/ +func ExampleMatchingRule_E() { + def := mySchema.NewMatchingRule() + def.SetNumericOID(`23jklm5.1`) // bogus + if err := def.E(); err != nil { + fmt.Println(err) + } + // Output: Numeric OID is invalid +} + +/* +This example demonstrates the means for resolving an error condition. +*/ +func ExampleMatchingRule_E_clearError() { + def := mySchema.NewMatchingRule() + def.SetNumericOID(`23jklm5.1`) // bogus + def.SetSyntax(`integer`) + + // We realized our mistake. + def.SetNumericOID(`1.3.6.1.4.1.56521.999.8.4.1.1`) // valid + + // But when we check again, the error is still there. + if def.E() != nil { + // handle error + } + + // We must clear the error with a + // passing compliance check. + if def.Compliant(); def.E() == nil { + fmt.Println("Error has been resolved") + } + // Output: Error has been resolved + + return +} + /* This example demonstrates the creation of a new [MatchingRule] instance for manual assembly in a fluent manner. diff --git a/mu.go b/mu.go index e02e7c1..f1a31f2 100644 --- a/mu.go +++ b/mu.go @@ -195,8 +195,10 @@ func (r MatchingRuleUse) Replace(x MatchingRuleUse) MatchingRuleUse { func (r *matchingRuleUse) replace(x MatchingRuleUse) { if r.OID.IsZero() { + r.err = ErrMissingNumericOID return } else if r.OID.NumericOID() != x.NumericOID() { + r.err = ErrInvalidOID return } @@ -212,6 +214,19 @@ func (r *matchingRuleUse) replace(x MatchingRuleUse) { r.data = x.matchingRuleUse.data } +/* +E returns the underlying error instance. +*/ +func (r MatchingRuleUse) E() (err error) { + if !r.IsZero() { + err = r.matchingRuleUse.err + } else { + err = ErrNilReceiver + } + + return +} + /* Compliant returns a Boolean value indicative of every [MatchingRuleUse] returning a compliant response from the [MatchingRuleUse.Compliant] method. @@ -256,7 +271,12 @@ func (r MatchingRuleUse) Compliant() bool { return false } - return act == r.Applies().Len() + ok := act == r.Applies().Len() + if ok { + r.matchingRuleUse.err = nil + } + + return ok } /* @@ -341,10 +361,12 @@ func (r *matchingRuleUse) setStringer(function ...Stringer) { stringer = function[0] } + var err error if stringer == nil { // no user provided closure means we // defer to a general use stringer. - str, err := r.prepareString() // perform one-time text/template op + var str string + str, err = r.prepareString() // perform one-time text/template op if err == nil { // Save the stringer r.stringer = func() string { @@ -355,6 +377,10 @@ func (r *matchingRuleUse) setStringer(function ...Stringer) { return } + if err != nil { + r.err = err + } + // assign user-provided closure r.stringer = stringer } @@ -469,6 +495,10 @@ func (r *matchingRuleUse) setApplies(m ...any) { r.Applies.Push(at) } } + + if err != nil { + r.err = err + } } /* @@ -513,6 +543,13 @@ func (r *matchingRuleUse) getSchema() (s Schema) { return } +/* +Identifier returns the output of [MatchingRuleUse.OID] and is merely used +for an interface-friendly means of obtaining the principal identifier +of the receiver instance. +*/ +func (r MatchingRuleUse) Identifier() (ident string) { return r.OID() } + /* IsIdentifiedAs returns a Boolean value indicative of whether id matches either the numericOID or descriptor of the receiver instance. Case is @@ -744,6 +781,8 @@ func (r *matchingRuleUse) setNumericOID(id string) { // and when the MR has been found. if !mr.IsZero() && r.OID.IsZero() { r.OID = mr + } else { + r.err = ErrInvalidOID } return @@ -789,9 +828,14 @@ func (r MatchingRuleUse) SetName(x ...string) MatchingRuleUse { } func (r *matchingRuleUse) setName(x ...string) { + b4 := r.Name.Len() for i := 0; i < len(x); i++ { r.Name.Push(x[i]) } + + if r.Name.Len()-len(x) != b4 { + r.err = ErrInvalidNames + } } /* diff --git a/nf.go b/nf.go index a742a3c..ea52a38 100644 --- a/nf.go +++ b/nf.go @@ -82,6 +82,19 @@ func (r NameForm) Map() (def DefinitionMap) { return } +/* +E returns the underlying error instance. +*/ +func (r NameForm) E() (err error) { + if !r.IsZero() { + err = r.nameForm.err + } else { + err = ErrNilReceiver + } + + return +} + /* NewNameForm initializes and returns a new instance of [NameForm], ready for manual assembly. This method need not be used when creating @@ -169,8 +182,10 @@ func (r NameForm) Replace(x NameForm) NameForm { func (r *nameForm) replace(x NameForm) { if r.OID == `` { + r.err = ErrMissingNumericOID return } else if r.OID != x.NumericOID() { + r.err = ErrInvalidOID return } @@ -210,6 +225,13 @@ func (r NameForm) EnforcedBy() (dsr DITStructureRules) { return } +/* +Identifier returns the output of [NameForm.OID] and is merely used for +an interface-friendly means of obtaining the principal identifier of +the receiver instance. +*/ +func (r NameForm) Identifier() (ident string) { return r.OID() } + /* IsIdentifiedAs returns a Boolean value indicative of whether id matches either the numericOID or descriptor of the receiver instance. Case is @@ -281,7 +303,12 @@ func (r NameForm) Compliant() bool { } } - return mct > 0 + ok := mct > 0 + if ok { + r.nameForm.err = nil + } + + return ok } /* @@ -373,9 +400,14 @@ func (r NameForm) SetName(name ...string) NameForm { } func (r *nameForm) setName(x ...string) { + b4 := r.Name.Len() for i := 0; i < len(x); i++ { r.Name.Push(x[i]) } + + if r.Name.Len()-len(x) != b4 { + r.err = ErrInvalidNames + } } /* @@ -402,6 +434,8 @@ func (r *nameForm) setNumericOID(id string) { if len(r.OID) == 0 { r.OID = id } + } else { + r.err = ErrInvalidOID } return @@ -518,6 +552,10 @@ func (r *nameForm) setMay(m ...any) { r.May.Push(at) } } + + if err != nil { + r.err = err + } } /* @@ -585,6 +623,10 @@ func (r *nameForm) setMust(m ...any) { r.Must.Push(at) } } + + if err != nil { + r.err = err + } } /* @@ -673,8 +715,10 @@ func (r *nameForm) setStringer(function ...Stringer) { stringer = function[0] } + var err error if stringer == nil { - str, err := r.prepareString() // perform one-time text/template op + var str string + str, err = r.prepareString() // perform one-time text/template op if err == nil { // Save the stringer r.stringer = func() string { @@ -685,6 +729,10 @@ func (r *nameForm) setStringer(function ...Stringer) { } else { r.stringer = stringer } + + if err != nil { + r.err = err + } } /* @@ -759,6 +807,10 @@ func (r *nameForm) prepareString() (str string, err error) { } } + if err != nil { + r.err = err + } + return } @@ -1150,6 +1202,8 @@ func (r *nameForm) setOC(x any) { if !oc.IsZero() && oc.Kind() == StructuralKind { r.Structural = oc + } else { + r.err = ErrIncompatStructuralClass } } diff --git a/nf_test.go b/nf_test.go index 7a3c179..3967b50 100644 --- a/nf_test.go +++ b/nf_test.go @@ -61,6 +61,46 @@ func ExampleSchema_NewNameForm() { // MUST cn ) } +/* +This example demonstrates the means for checking to see if the receiver +is in an error condition. +*/ +func ExampleNameForm_E() { + def := mySchema.NewNameForm() + def.SetNumericOID(`23jklm5.1`) // bogus + if err := def.E(); err != nil { + fmt.Println(err) + } + // Output: Numeric OID is invalid +} + +/* +This example demonstrates the means for resolving an error condition. +*/ +func ExampleNameForm_E_clearError() { + def := mySchema.NewNameForm() + def.SetNumericOID(`23jklm5.1`) // bogus + + // We realized our mistake. + def.SetNumericOID(`1.3.6.1.4.1.56521.999.8.4.1.1`) // valid + def.SetOC(`person`) + def.SetMust(`cn`) + + // But when we check again, the error is still there. + if def.E() != nil { + //fmt.Println(... the error ...) + } + + // We must clear the error with a + // passing compliance check. + if def.Compliant(); def.E() == nil { + fmt.Println("Error has been resolved") + } + // Output: Error has been resolved + + return +} + /* This example demonstrates a compliancy check of the "account" [ObjectClass]. diff --git a/oc.go b/oc.go index 77a8963..cbb0d05 100644 --- a/oc.go +++ b/oc.go @@ -290,9 +290,14 @@ func (r ObjectClass) SetName(x ...string) ObjectClass { } func (r *objectClass) setName(x ...string) { + b4 := r.Name.Len() for i := 0; i < len(x); i++ { r.Name.Push(x[i]) } + + if r.Name.Len()-len(x) != b4 { + r.err = ErrInvalidNames + } } /* @@ -421,6 +426,9 @@ func (r *objectClass) setMust(m ...any) { } } + if err != nil { + r.err = err + } } /* @@ -454,6 +462,10 @@ func (r *objectClass) setMay(m ...any) { r.May.Push(at) } } + + if err != nil { + r.err = err + } } /* @@ -491,6 +503,10 @@ func (r *objectClass) setSuperClass(x ...any) { r.SuperClasses.push(sup) } } + + if err != nil { + r.err = err + } } /* @@ -521,7 +537,11 @@ func (r ObjectClass) Replace(x ObjectClass) ObjectClass { } func (r *objectClass) replace(x ObjectClass) { - if r.OID != x.NumericOID() { + if r.OID == `` { + r.err = ErrMissingNumericOID + return + } else if r.OID != x.NumericOID() { + r.err = ErrInvalidOID return } @@ -657,7 +677,26 @@ func (r ObjectClass) Compliant() bool { } } - return isNumericOID(r.NumericOID()) + ok := isNumericOID(r.NumericOID()) + if ok { + r.objectClass.err = nil + } + + return ok + +} + +/* +E returns the underlying error instance. +*/ +func (r ObjectClass) E() (err error) { + if !r.IsZero() { + err = r.objectClass.err + } else { + err = ErrNilReceiver + } + + return } /* @@ -1008,6 +1047,13 @@ func (r ObjectClass) OID() (oid string) { return } +/* +Identifier returns the output of [ObjectClass.OID] and is merely used +for an interface-friendly means of obtaining the principal identifier +of the receiver instance. +*/ +func (r ObjectClass) Identifier() (ident string) { return r.OID() } + /* IsIdentifiedAs returns a Boolean value indicative of whether id matches either the numericOID or descriptor of the receiver instance. Case is @@ -1132,6 +1178,8 @@ func (r *objectClass) setNumericOID(id string) { if len(r.OID) == 0 { r.OID = id } + } else { + r.err = ErrInvalidOID } } @@ -1206,6 +1254,8 @@ func (r *objectClass) setStringer(function ...Stringer) { // Return a preserved value. return str } + } else { + r.err = err } } else { r.stringer = stringer @@ -1293,6 +1343,10 @@ func (r *objectClass) prepareString() (str string, err error) { } } + if err != nil { + r.err = err + } + return } diff --git a/oc_test.go b/oc_test.go index dd73d92..b438ca3 100644 --- a/oc_test.go +++ b/oc_test.go @@ -41,6 +41,44 @@ func ExampleObjectClass_Marshal() { // X-ORIGIN 'RFCXXXX' ) } +/* +This example demonstrates the means for checking to see if the receiver +is in an error condition. +*/ +func ExampleObjectClass_E() { + def := mySchema.NewObjectClass() + def.SetNumericOID(`23jklm5.1`) // bogus + if err := def.E(); err != nil { + fmt.Println(err) + } + // Output: Numeric OID is invalid +} + +/* +This example demonstrates the means for resolving an error condition. +*/ +func ExampleObjectClass_E_clearError() { + def := mySchema.NewObjectClass() + def.SetNumericOID(`23jklm5.1`) // bogus + + // We realized our mistake. + def.SetNumericOID(`1.3.6.1.4.1.56521.999.8.4.1.1`) // valid + + // But when we check again, the error is still there. + if def.E() != nil { + //fmt.Println(... the error ...) + } + + // We must clear the error with a + // passing compliance check. + if def.Compliant(); def.E() == nil { + fmt.Println("Error has been resolved") + } + // Output: Error has been resolved + + return +} + /* This example demonstrates a compliancy check of the "account" [ObjectClass]. */ diff --git a/type.go b/type.go index 42bc279..44a48e3 100644 --- a/type.go +++ b/type.go @@ -399,6 +399,7 @@ type attributeType struct { Usage uint Extensions Extensions + err error schema Schema stringer Stringer valQual ValueQualifier @@ -454,6 +455,7 @@ type dITContentRule struct { Not AttributeTypes Extensions Extensions + err error schema Schema stringer Stringer data any @@ -512,6 +514,7 @@ type dITStructureRule struct { SuperRules DITStructureRules Extensions Extensions + err error schema Schema stringer Stringer data any @@ -552,6 +555,7 @@ type lDAPSyntax struct { Desc string Extensions Extensions + err error schema Schema stringer Stringer synQual SyntaxQualifier @@ -605,6 +609,7 @@ type matchingRule struct { Syntax LDAPSyntax Extensions Extensions + err error schema Schema stringer Stringer assMatch AssertionMatcher @@ -662,6 +667,7 @@ type matchingRuleUse struct { Applies AttributeTypes Extensions Extensions + err error schema Schema stringer Stringer data any @@ -716,6 +722,7 @@ type nameForm struct { May AttributeTypes Extensions Extensions + err error schema Schema stringer Stringer data any @@ -776,6 +783,7 @@ type objectClass struct { May AttributeTypes Extensions Extensions + err error schema Schema stringer Stringer data any @@ -847,6 +855,16 @@ type Definition interface { // within the receiver instance. Data() any + // Identifier returns the principal identifier of the receiver + // instance as a string. Value sources vary greatly depending + // on the underlying type of instance. + Identifier() string + + // E returns the underlying error instance present within the + // receiver instance. Errors are cleared following a successful + // run of the associated Compliant method. + E() error + // Parse returns an error following an attempt read the string // input value into the receiver instance. //