From 4d8c2ef19b3967cccdba2fc4af39b80787099b26 Mon Sep 17 00:00:00 2001 From: Jared O'Connell Date: Thu, 18 Apr 2024 13:04:58 -0400 Subject: [PATCH 1/4] Add proper method to access root object --- schema/scope.go | 51 ++++++++++++++++++++++++++++++++++++-------- schema/scope_test.go | 39 +++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 9 deletions(-) diff --git a/schema/scope.go b/schema/scope.go index 53eda03..6a1508b 100644 --- a/schema/scope.go +++ b/schema/scope.go @@ -13,6 +13,7 @@ type Scope interface { Object Objects() map[string]*ObjectSchema Root() string + RootObject() *ObjectSchema SelfSerialize() (any, error) } @@ -56,40 +57,40 @@ func (s *ScopeSchema) SelfSerialize() (any, error) { } func (s *ScopeSchema) ID() string { - return s.ObjectsValue[s.RootValue].ID() + return s.RootObject().ID() } func (s *ScopeSchema) Properties() map[string]*PropertySchema { - return s.ObjectsValue[s.RootValue].PropertiesValue + return s.RootObject().PropertiesValue } func (s *ScopeSchema) GetDefaults() map[string]any { - return s.ObjectsValue[s.RootValue].GetDefaults() + return s.RootObject().GetDefaults() } func (s *ScopeSchema) ReflectedType() reflect.Type { - return s.ObjectsValue[s.RootValue].ReflectedType() + return s.RootObject().ReflectedType() } func (s *ScopeSchema) Unserialize(data any) (any, error) { - return s.ObjectsValue[s.RootValue].Unserialize(data) + return s.RootObject().Unserialize(data) } func (s *ScopeSchema) ValidateCompatibility(typeOrData any) error { schemaType, ok := typeOrData.(*ScopeSchema) if ok { - return s.ObjectsValue[s.RootValue].ValidateCompatibility(schemaType.ObjectsValue[schemaType.RootValue]) + return s.RootObject().ValidateCompatibility(schemaType.ObjectsValue[schemaType.RootValue]) } - return s.ObjectsValue[s.RootValue].ValidateCompatibility(typeOrData) + return s.RootObject().ValidateCompatibility(typeOrData) } func (s *ScopeSchema) Validate(data any) error { - return s.ObjectsValue[s.RootValue].Validate(data) + return s.RootObject().Validate(data) } func (s *ScopeSchema) Serialize(data any) (any, error) { - return s.ObjectsValue[s.RootValue].Serialize(data) + return s.RootObject().Serialize(data) } func (s *ScopeSchema) ApplyScope(externalScope Scope, namespace string) { @@ -123,6 +124,38 @@ func (s *ScopeSchema) Objects() map[string]*ObjectSchema { return s.ObjectsValue } +func (s *ScopeSchema) objectIDList() string { + output := "" + for id := range s.ObjectsValue { + output += "\n" + id + } + return output +} + +func (s *ScopeSchema) RootObject() *ObjectSchema { + rootObject, rootObjectFound := s.ObjectsValue[s.RootValue] + if !rootObjectFound { + panic(fmt.Sprintf( + "root object with ID %q not found; available objects:%s", + s.RootValue, + s.objectIDList(), + )) + } + if rootObject == nil { + panic(fmt.Sprintf( + "root object with ID %q is nil; this is a bug", + s.RootValue, + )) + } + if rootObject.ID() != s.RootValue { + panic(fmt.Sprintf( + "root object's ID %q doesn't match its map key %q; please fix the input", + rootObject.ID(), s.RootValue, + )) + } + return rootObject +} + func (s *ScopeSchema) Root() string { return s.RootValue } diff --git a/schema/scope_test.go b/schema/scope_test.go index 7f8eebe..e7e3d9b 100644 --- a/schema/scope_test.go +++ b/schema/scope_test.go @@ -498,3 +498,42 @@ func TestApplyingExternalNamespaceToNonRefTypes(t *testing.T) { }) } } + +func TestMismatchedRoot(t *testing.T) { + // This is a common user mistake: invalid root key + brokenSchema := schema.ScopeSchema{ + ObjectsValue: map[string]*schema.ObjectSchema{ + "a": schema.NewObjectSchema("a", map[string]*schema.PropertySchema{}), + }, + RootValue: "wrong", + } + assert.PanicsContains(t, func() { + brokenSchema.RootObject() + }, "root object with ID \"wrong\" not found; available objects:\na") +} + +func TestNilRoot(t *testing.T) { + // This is just a bug case + brokenSchema := schema.ScopeSchema{ + ObjectsValue: map[string]*schema.ObjectSchema{ + "a": nil, + }, + RootValue: "a", + } + assert.PanicsContains(t, func() { + brokenSchema.RootObject() + }, "root object with ID \"a\" is nil") +} + +func TestMismatchedRootID(t *testing.T) { + // This is a common user mistake: valid key doesn't match object ID + brokenSchema := schema.ScopeSchema{ + ObjectsValue: map[string]*schema.ObjectSchema{ + "a": schema.NewObjectSchema("wrong", map[string]*schema.PropertySchema{}), + }, + RootValue: "a", + } + assert.PanicsContains(t, func() { + brokenSchema.RootObject() + }, "root object's ID \"wrong\" doesn't match its map key \"a\"") +} From e18664244744cc319cf5cd1d6214468258300b9f Mon Sep 17 00:00:00 2001 From: Jared O'Connell Date: Thu, 18 Apr 2024 19:07:11 -0400 Subject: [PATCH 2/4] Improved documeentation and added success case test --- schema/scope.go | 8 ++++---- schema/scope_test.go | 26 +++++++++++++++++++------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/schema/scope.go b/schema/scope.go index 6a1508b..ba2ccf8 100644 --- a/schema/scope.go +++ b/schema/scope.go @@ -124,10 +124,10 @@ func (s *ScopeSchema) Objects() map[string]*ObjectSchema { return s.ObjectsValue } -func (s *ScopeSchema) objectIDList() string { +func (s *ScopeSchema) objectIDList(separator string) string { output := "" for id := range s.ObjectsValue { - output += "\n" + id + output += separator + id } return output } @@ -138,12 +138,12 @@ func (s *ScopeSchema) RootObject() *ObjectSchema { panic(fmt.Sprintf( "root object with ID %q not found; available objects:%s", s.RootValue, - s.objectIDList(), + s.objectIDList("\n\t"), )) } if rootObject == nil { panic(fmt.Sprintf( - "root object with ID %q is nil; this is a bug", + "root object with ID %q is nil", s.RootValue, )) } diff --git a/schema/scope_test.go b/schema/scope_test.go index e7e3d9b..38eaeed 100644 --- a/schema/scope_test.go +++ b/schema/scope_test.go @@ -499,8 +499,20 @@ func TestApplyingExternalNamespaceToNonRefTypes(t *testing.T) { } } +func TestGetRootObject(t *testing.T) { + rootObject := schema.NewObjectSchema("a", map[string]*schema.PropertySchema{}) + correctSchema := schema.ScopeSchema{ + ObjectsValue: map[string]*schema.ObjectSchema{ + "a": rootObject, + }, + RootValue: "a", + } + assert.Equals(t, correctSchema.RootObject(), rootObject) +} + func TestMismatchedRoot(t *testing.T) { - // This is a common user mistake: invalid root key + // This is a common user mistake: invalid RootValue in the scope. + // Panic when a Scope's RootValue is not a key in its ObjectsValue brokenSchema := schema.ScopeSchema{ ObjectsValue: map[string]*schema.ObjectSchema{ "a": schema.NewObjectSchema("a", map[string]*schema.PropertySchema{}), @@ -509,11 +521,11 @@ func TestMismatchedRoot(t *testing.T) { } assert.PanicsContains(t, func() { brokenSchema.RootObject() - }, "root object with ID \"wrong\" not found; available objects:\na") + }, "root object with ID \"wrong\" not found; available objects:\n\ta") } func TestNilRoot(t *testing.T) { - // This is just a bug case + // This is just a bug case; nil object in the objects map. brokenSchema := schema.ScopeSchema{ ObjectsValue: map[string]*schema.ObjectSchema{ "a": nil, @@ -526,14 +538,14 @@ func TestNilRoot(t *testing.T) { } func TestMismatchedRootID(t *testing.T) { - // This is a common user mistake: valid key doesn't match object ID + // This is a common user mistake: valid scope map key doesn't match the object's ID brokenSchema := schema.ScopeSchema{ ObjectsValue: map[string]*schema.ObjectSchema{ - "a": schema.NewObjectSchema("wrong", map[string]*schema.PropertySchema{}), + "wrong": schema.NewObjectSchema("a", map[string]*schema.PropertySchema{}), }, - RootValue: "a", + RootValue: "wrong", } assert.PanicsContains(t, func() { brokenSchema.RootObject() - }, "root object's ID \"wrong\" doesn't match its map key \"a\"") + }, "root object's ID \"a\" doesn't match its map key \"wrong\"") } From 5c9a3621e873282296b03871fe68cf7adb401259 Mon Sep 17 00:00:00 2001 From: Jared O'Connell Date: Fri, 19 Apr 2024 12:52:24 -0400 Subject: [PATCH 3/4] Added extra test case for root object access function --- schema/scope_test.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/schema/scope_test.go b/schema/scope_test.go index 38eaeed..2c4bcc6 100644 --- a/schema/scope_test.go +++ b/schema/scope_test.go @@ -524,6 +524,19 @@ func TestMismatchedRoot(t *testing.T) { }, "root object with ID \"wrong\" not found; available objects:\n\ta") } +func TestMismatchedRootKey(t *testing.T) { + // Tests when the Root value and ID value are correct, but the key of the object map is wrong. + brokenSchema := schema.ScopeSchema{ + ObjectsValue: map[string]*schema.ObjectSchema{ + "wrong": schema.NewObjectSchema("a", map[string]*schema.PropertySchema{}), + }, + RootValue: "a", + } + assert.PanicsContains(t, func() { + brokenSchema.RootObject() + }, "root object with ID \"a\" not found; available objects:\n\twrong") +} + func TestNilRoot(t *testing.T) { // This is just a bug case; nil object in the objects map. brokenSchema := schema.ScopeSchema{ From 2079a43298d633f42f6af0c2a4d9a723bd85c5e8 Mon Sep 17 00:00:00 2001 From: Jared O'Connell Date: Fri, 19 Apr 2024 12:56:31 -0400 Subject: [PATCH 4/4] Improved error message --- schema/scope.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schema/scope.go b/schema/scope.go index ba2ccf8..729d3f3 100644 --- a/schema/scope.go +++ b/schema/scope.go @@ -149,7 +149,7 @@ func (s *ScopeSchema) RootObject() *ObjectSchema { } if rootObject.ID() != s.RootValue { panic(fmt.Sprintf( - "root object's ID %q doesn't match its map key %q; please fix the input", + "root object's ID %q doesn't match its map key %q; please fix the schema definition", rootObject.ID(), s.RootValue, )) }