Add abstract OptionalAwareValidator class

This improves validation of optional fields and respects the `optional`
option of properties
This commit is contained in:
Benjamin Neff 2017-08-28 01:49:31 +02:00
parent 9081328d51
commit 6f936caddf
No known key found for this signature in database
GPG key ID: 971464C3F1A90194
27 changed files with 114 additions and 25 deletions

View file

@ -37,6 +37,7 @@ end
require "diaspora_federation/validators/related_entity_validator" require "diaspora_federation/validators/related_entity_validator"
# abstract types # abstract types
require "diaspora_federation/validators/optional_aware_validator"
require "diaspora_federation/validators/relayable_validator" require "diaspora_federation/validators/relayable_validator"
# types # types

View file

@ -1,7 +1,7 @@
module DiasporaFederation module DiasporaFederation
module Validators module Validators
# This validates a {Entities::AccountDeletion}. # This validates a {Entities::AccountDeletion}.
class AccountDeletionValidator < Validation::Validator class AccountDeletionValidator < OptionalAwareValidator
include Validation include Validation
rule :author, %i[not_empty diaspora_id] rule :author, %i[not_empty diaspora_id]

View file

@ -1,7 +1,7 @@
module DiasporaFederation module DiasporaFederation
module Validators module Validators
# This validates a {Entities::AccountMigration}. # This validates a {Entities::AccountMigration}.
class AccountMigrationValidator < Validation::Validator class AccountMigrationValidator < OptionalAwareValidator
include Validation include Validation
rule :author, %i[not_empty diaspora_id] rule :author, %i[not_empty diaspora_id]

View file

@ -1,7 +1,7 @@
module DiasporaFederation module DiasporaFederation
module Validators module Validators
# This validates a {Entities::Comment}. # This validates a {Entities::Comment}.
class CommentValidator < Validation::Validator class CommentValidator < OptionalAwareValidator
include Validation include Validation
include RelayableValidator include RelayableValidator

View file

@ -1,7 +1,7 @@
module DiasporaFederation module DiasporaFederation
module Validators module Validators
# This validates a {Entities::Contact}. # This validates a {Entities::Contact}.
class ContactValidator < Validation::Validator class ContactValidator < OptionalAwareValidator
include Validation include Validation
rule :author, %i[not_empty diaspora_id] rule :author, %i[not_empty diaspora_id]

View file

@ -1,7 +1,7 @@
module DiasporaFederation module DiasporaFederation
module Validators module Validators
# This validates a {Entities::Conversation}. # This validates a {Entities::Conversation}.
class ConversationValidator < Validation::Validator class ConversationValidator < OptionalAwareValidator
include Validation include Validation
rule :author, %i[not_empty diaspora_id] rule :author, %i[not_empty diaspora_id]

View file

@ -1,7 +1,7 @@
module DiasporaFederation module DiasporaFederation
module Validators module Validators
# This validates a {Entities::EventParticipation}. # This validates a {Entities::EventParticipation}.
class EventParticipationValidator < Validation::Validator class EventParticipationValidator < OptionalAwareValidator
include Validation include Validation
include RelayableValidator include RelayableValidator

View file

@ -1,7 +1,7 @@
module DiasporaFederation module DiasporaFederation
module Validators module Validators
# This validates a {Entities::Event}. # This validates a {Entities::Event}.
class EventValidator < Validation::Validator class EventValidator < OptionalAwareValidator
include Validation include Validation
rule :author, %i[not_empty diaspora_id] rule :author, %i[not_empty diaspora_id]

View file

@ -3,7 +3,7 @@ module DiasporaFederation
# This validates a {Discovery::HCard}. # This validates a {Discovery::HCard}.
# #
# @note # @note
class HCardValidator < Validation::Validator class HCardValidator < OptionalAwareValidator
include Validation include Validation
rule :guid, :guid rule :guid, :guid

View file

@ -1,7 +1,7 @@
module DiasporaFederation module DiasporaFederation
module Validators module Validators
# This validates a {Entities::Like}. # This validates a {Entities::Like}.
class LikeValidator < Validation::Validator class LikeValidator < OptionalAwareValidator
include Validation include Validation
include RelayableValidator include RelayableValidator

View file

@ -1,7 +1,7 @@
module DiasporaFederation module DiasporaFederation
module Validators module Validators
# This validates a {Entities::Location}. # This validates a {Entities::Location}.
class LocationValidator < Validation::Validator class LocationValidator < OptionalAwareValidator
include Validation include Validation
rule :lat, :not_empty rule :lat, :not_empty

View file

@ -1,7 +1,7 @@
module DiasporaFederation module DiasporaFederation
module Validators module Validators
# This validates a {Entities::Message}. # This validates a {Entities::Message}.
class MessageValidator < Validation::Validator class MessageValidator < OptionalAwareValidator
include Validation include Validation
rule :author, %i[not_empty diaspora_id] rule :author, %i[not_empty diaspora_id]

View file

@ -0,0 +1,23 @@
module DiasporaFederation
module Validators
# Abstract validator which only validates optional fields when they are not nil.
class OptionalAwareValidator < Validation::Validator
def rules
super.reject do |field, rules|
@obj.public_send(field).nil? &&
!rules.map(&:class).include?(Validation::Rule::NotNil) &&
optional_props.include?(field)
end
end
private
def optional_props
entity_name = self.class.name.split("::").last.sub("Validator", "")
return [] unless Entities.const_defined?(entity_name)
Entities.const_get(entity_name).optional_props
end
end
end
end

View file

@ -1,7 +1,7 @@
module DiasporaFederation module DiasporaFederation
module Validators module Validators
# This validates a {Entities::Participation}. # This validates a {Entities::Participation}.
class ParticipationValidator < Validation::Validator class ParticipationValidator < OptionalAwareValidator
include Validation include Validation
rule :author, %i[not_empty diaspora_id] rule :author, %i[not_empty diaspora_id]

View file

@ -1,7 +1,7 @@
module DiasporaFederation module DiasporaFederation
module Validators module Validators
# This validates a {Entities::Person}. # This validates a {Entities::Person}.
class PersonValidator < Validation::Validator class PersonValidator < OptionalAwareValidator
include Validation include Validation
rule :guid, :guid rule :guid, :guid

View file

@ -1,7 +1,7 @@
module DiasporaFederation module DiasporaFederation
module Validators module Validators
# This validates a {Entities::Photo}. # This validates a {Entities::Photo}.
class PhotoValidator < Validation::Validator class PhotoValidator < OptionalAwareValidator
include Validation include Validation
rule :guid, :guid rule :guid, :guid

View file

@ -1,7 +1,7 @@
module DiasporaFederation module DiasporaFederation
module Validators module Validators
# This validates a {Entities::PollAnswer}. # This validates a {Entities::PollAnswer}.
class PollAnswerValidator < Validation::Validator class PollAnswerValidator < OptionalAwareValidator
include Validation include Validation
rule :guid, :guid rule :guid, :guid

View file

@ -1,7 +1,7 @@
module DiasporaFederation module DiasporaFederation
module Validators module Validators
# This validates a {Entities::PollParticipation}. # This validates a {Entities::PollParticipation}.
class PollParticipationValidator < Validation::Validator class PollParticipationValidator < OptionalAwareValidator
include Validation include Validation
include RelayableValidator include RelayableValidator

View file

@ -1,7 +1,7 @@
module DiasporaFederation module DiasporaFederation
module Validators module Validators
# This validates a {Entities::Poll}. # This validates a {Entities::Poll}.
class PollValidator < Validation::Validator class PollValidator < OptionalAwareValidator
include Validation include Validation
rule :guid, :guid rule :guid, :guid

View file

@ -1,7 +1,7 @@
module DiasporaFederation module DiasporaFederation
module Validators module Validators
# This validates a {Entities::Profile}. # This validates a {Entities::Profile}.
class ProfileValidator < Validation::Validator class ProfileValidator < OptionalAwareValidator
include Validation include Validation
rule :author, :diaspora_id rule :author, :diaspora_id

View file

@ -1,7 +1,7 @@
module DiasporaFederation module DiasporaFederation
module Validators module Validators
# This validates a {Entities::Reshare}. # This validates a {Entities::Reshare}.
class ReshareValidator < Validation::Validator class ReshareValidator < OptionalAwareValidator
include Validation include Validation
rule :root_author, :diaspora_id rule :root_author, :diaspora_id

View file

@ -1,7 +1,7 @@
module DiasporaFederation module DiasporaFederation
module Validators module Validators
# This validates a {Entities::Retraction}. # This validates a {Entities::Retraction}.
class RetractionValidator < Validation::Validator class RetractionValidator < OptionalAwareValidator
include Validation include Validation
rule :author, %i[not_empty diaspora_id] rule :author, %i[not_empty diaspora_id]

View file

@ -1,7 +1,7 @@
module DiasporaFederation module DiasporaFederation
module Validators module Validators
# This validates a {Entities::StatusMessage}. # This validates a {Entities::StatusMessage}.
class StatusMessageValidator < Validation::Validator class StatusMessageValidator < OptionalAwareValidator
include Validation include Validation
rule :author, %i[not_empty diaspora_id] rule :author, %i[not_empty diaspora_id]

View file

@ -4,7 +4,7 @@ module DiasporaFederation
# #
# @note It does not validate the guid and public key, because it will be # @note It does not validate the guid and public key, because it will be
# removed in the webfinger. # removed in the webfinger.
class WebFingerValidator < Validation::Validator class WebFingerValidator < OptionalAwareValidator
include Validation include Validation
rule :acct_uri, :not_empty rule :acct_uri, :not_empty

View file

@ -60,7 +60,7 @@ module DiasporaFederation
property :test5, :timestamp property :test5, :timestamp
entity :test6, TestEntity entity :test6, TestEntity
property :test7, :string, optional: true property :test7, :string, optional: true
entity :multi, [OtherEntity] entity :multi, [OtherEntity], optional: true
end end
class TestEntityWithAuthorAndGuid < DiasporaFederation::Entity class TestEntityWithAuthorAndGuid < DiasporaFederation::Entity
@ -94,5 +94,20 @@ module DiasporaFederation
rule :author, %i[not_empty diaspora_id] rule :author, %i[not_empty diaspora_id]
rule :guid, :guid rule :guid, :guid
end end
class TestComplexEntityValidator < OptionalAwareValidator
include Validation
rule :test1, length: {minimum: 3}
rule :test2, :boolean
rule :test7, length: {minimum: 3}
rule :multi, :not_nil
end
class TestUnknownEntityValidator < OptionalAwareValidator
include Validation
rule :test1, length: {minimum: 3}
end
end end
end end

View file

@ -0,0 +1,50 @@
module DiasporaFederation
describe Validators::OptionalAwareValidator do
let(:entity_data) {
{test1: "abc", test2: true, test7: "abc", multi: []}
}
it "validates a valid object" do
validator = Validators::TestComplexEntityValidator.new(OpenStruct.new(entity_data))
expect(validator).to be_valid
expect(validator.errors).to be_empty
end
it "fails when a mandatory property is invalid" do
["ab", nil].each do |val|
entity = OpenStruct.new(entity_data.merge(test1: val))
validator = Validators::TestComplexEntityValidator.new(entity)
expect(validator).not_to be_valid
expect(validator.errors).to include(:test1)
end
end
it "fails when an optional property is invalid" do
entity = OpenStruct.new(entity_data.merge(test7: "ab"))
validator = Validators::TestComplexEntityValidator.new(entity)
expect(validator).not_to be_valid
expect(validator.errors).to include(:test7)
end
it "allows an optional property to be nil" do
entity = OpenStruct.new(entity_data.merge(test7: nil))
validator = Validators::TestComplexEntityValidator.new(entity)
expect(validator).to be_valid
expect(validator.errors).to be_empty
end
it "doesn't ignore 'not_nil' rules for an optional property" do
entity = OpenStruct.new(entity_data.merge(multi: nil))
validator = Validators::TestComplexEntityValidator.new(entity)
expect(validator).not_to be_valid
expect(validator.errors).to include(:multi)
end
it "doesn't fail when there is no entity for this validator" do
entity = OpenStruct.new(entity_data.merge(test1: nil))
validator = Validators::TestUnknownEntityValidator.new(entity)
expect(validator).not_to be_valid
expect(validator.errors).to include(:test1)
end
end
end

View file

@ -11,7 +11,7 @@ describe Validation::Rule::NotNil do
end end
context "validation" do context "validation" do
it "validates a string " do it "validates a string" do
validator = Validation::Validator.new(OpenStruct.new(not_nil: "abcd")) validator = Validation::Validator.new(OpenStruct.new(not_nil: "abcd"))
validator.rule(:not_nil, :not_nil) validator.rule(:not_nil, :not_nil)
@ -19,7 +19,7 @@ describe Validation::Rule::NotNil do
expect(validator.errors).to be_empty expect(validator.errors).to be_empty
end end
it "validates a object " do it "validates a object" do
validator = Validation::Validator.new(OpenStruct.new(not_nil: Object.new)) validator = Validation::Validator.new(OpenStruct.new(not_nil: Object.new))
validator.rule(:not_nil, :not_nil) validator.rule(:not_nil, :not_nil)