spec/grape/validations_spec.rb in grape-1.5.0 vs spec/grape/validations_spec.rb in grape-1.5.1
- old
+ new
@@ -881,9 +881,277 @@
requires(:required_subitems, type: Array) { requires :value }
end
end
expect(declared_params).to eq([items: [:key, { optional_subitems: [:value] }, { required_subitems: [:value] }]])
end
+
+ context <<~DESC do
+ Issue occurs whenever:
+ * param structure with at least three levels
+ * 1st level item is a required Array that has >1 entry with an optional item present and >1 entry with an optional item missing
+ * 2nd level is an optional Array or Hash
+ * 3rd level is a required item (can be any type)
+ * additional levels do not effect the issue from occuring
+ DESC
+
+ it "example based off actual real world use case" do
+ subject.params do
+ requires :orders, type: Array do
+ requires :id, type: Integer
+ optional :drugs, type: Array do
+ requires :batches, type: Array do
+ requires :batch_no, type: String
+ end
+ end
+ end
+ end
+
+ subject.get '/validate_required_arrays_under_optional_arrays' do
+ 'validate_required_arrays_under_optional_arrays works!'
+ end
+
+ data = {
+ orders: [
+ { id: 77, drugs: [{batches: [{batch_no: "A1234567"}]}]},
+ { id: 70 }
+ ]
+ }
+
+ get '/validate_required_arrays_under_optional_arrays', data
+ expect(last_response.body).to eq("validate_required_arrays_under_optional_arrays works!")
+ expect(last_response.status).to eq(200)
+ end
+
+ it "simplest example using Arry -> Array -> Hash -> String" do
+ subject.params do
+ requires :orders, type: Array do
+ requires :id, type: Integer
+ optional :drugs, type: Array do
+ requires :batch_no, type: String
+ end
+ end
+ end
+
+ subject.get '/validate_required_arrays_under_optional_arrays' do
+ 'validate_required_arrays_under_optional_arrays works!'
+ end
+
+ data = {
+ orders: [
+ { id: 77, drugs: [{batch_no: "A1234567"}]},
+ { id: 70 }
+ ]
+ }
+
+ get '/validate_required_arrays_under_optional_arrays', data
+ expect(last_response.body).to eq("validate_required_arrays_under_optional_arrays works!")
+ expect(last_response.status).to eq(200)
+ end
+
+ it "simplest example using Arry -> Hash -> String" do
+ subject.params do
+ requires :orders, type: Array do
+ requires :id, type: Integer
+ optional :drugs, type: Hash do
+ requires :batch_no, type: String
+ end
+ end
+ end
+
+ subject.get '/validate_required_arrays_under_optional_arrays' do
+ 'validate_required_arrays_under_optional_arrays works!'
+ end
+
+ data = {
+ orders: [
+ { id: 77, drugs: {batch_no: "A1234567"}},
+ { id: 70 }
+ ]
+ }
+
+ get '/validate_required_arrays_under_optional_arrays', data
+ expect(last_response.body).to eq("validate_required_arrays_under_optional_arrays works!")
+ expect(last_response.status).to eq(200)
+ end
+
+ it "correctly indexes invalida data" do
+ subject.params do
+ requires :orders, type: Array do
+ requires :id, type: Integer
+ optional :drugs, type: Array do
+ requires :batch_no, type: String
+ requires :quantity, type: Integer
+ end
+ end
+ end
+
+ subject.get '/correctly_indexes' do
+ 'correctly_indexes works!'
+ end
+
+ data = {
+ orders: [
+ { id: 70 },
+ { id: 77, drugs: [{batch_no: "A1234567", quantity: 12}, {batch_no: "B222222"}]}
+ ]
+ }
+
+ get '/correctly_indexes', data
+ expect(last_response.body).to eq("orders[1][drugs][1][quantity] is missing")
+ expect(last_response.status).to eq(400)
+ end
+
+ context "multiple levels of optional and requires settings" do
+ before do
+ subject.params do
+ requires :top, type: Array do
+ requires :top_id, type: Integer, allow_blank: false
+ optional :middle_1, type: Array do
+ requires :middle_1_id, type: Integer, allow_blank: false
+ optional :middle_2, type: Array do
+ requires :middle_2_id, type: String, allow_blank: false
+ optional :bottom, type: Array do
+ requires :bottom_id, type: Integer, allow_blank: false
+ end
+ end
+ end
+ end
+ end
+
+ subject.get '/multi_level' do
+ 'multi_level works!'
+ end
+ end
+
+ it "with valid data" do
+ data = {
+ top: [
+ { top_id: 1, middle_1: [
+ {middle_1_id: 11}, {middle_1_id: 12, middle_2: [
+ {middle_2_id: 121}, {middle_2_id: 122, bottom: [{bottom_id: 1221}]}]}]},
+ { top_id: 2, middle_1: [
+ {middle_1_id: 21}, {middle_1_id: 22, middle_2: [
+ {middle_2_id: 221}]}]},
+ { top_id: 3, middle_1: [
+ {middle_1_id: 31}, {middle_1_id: 32}]},
+ { top_id: 4 }
+ ]
+ }
+
+ get '/multi_level', data
+ expect(last_response.body).to eq("multi_level works!")
+ expect(last_response.status).to eq(200)
+ end
+
+ it "with invalid data" do
+ data = {
+ top: [
+ { top_id: 1, middle_1: [
+ {middle_1_id: 11}, {middle_1_id: 12, middle_2: [
+ {middle_2_id: 121}, {middle_2_id: 122, bottom: [{bottom_id: nil}]}]}]},
+ { top_id: 2, middle_1: [
+ {middle_1_id: 21}, {middle_1_id: 22, middle_2: [{middle_2_id: nil}]}]},
+ { top_id: 3, middle_1: [
+ {middle_1_id: nil}, {middle_1_id: 32}]},
+ { top_id: nil, missing_top_id: 4 }
+ ]
+ }
+ # debugger
+ get '/multi_level', data
+ expect(last_response.body.split(", ")).to match_array([
+ "top[3][top_id] is empty",
+ "top[2][middle_1][0][middle_1_id] is empty",
+ "top[1][middle_1][1][middle_2][0][middle_2_id] is empty",
+ "top[0][middle_1][1][middle_2][1][bottom][0][bottom_id] is empty"
+ ])
+ expect(last_response.status).to eq(400)
+ end
+ end
+ end
+
+ it "exactly_one_of" do
+ subject.params do
+ requires :orders, type: Array do
+ requires :id, type: Integer
+ optional :drugs, type: Hash do
+ optional :batch_no, type: String
+ optional :batch_id, type: String
+ exactly_one_of :batch_no, :batch_id
+ end
+ end
+ end
+
+ subject.get '/exactly_one_of' do
+ 'exactly_one_of works!'
+ end
+
+ data = {
+ orders: [
+ { id: 77, drugs: {batch_no: "A1234567"}},
+ { id: 70 }
+ ]
+ }
+
+ get '/exactly_one_of', data
+ expect(last_response.body).to eq("exactly_one_of works!")
+ expect(last_response.status).to eq(200)
+ end
+
+ it "at_least_one_of" do
+ subject.params do
+ requires :orders, type: Array do
+ requires :id, type: Integer
+ optional :drugs, type: Hash do
+ optional :batch_no, type: String
+ optional :batch_id, type: String
+ at_least_one_of :batch_no, :batch_id
+ end
+ end
+ end
+
+ subject.get '/at_least_one_of' do
+ 'at_least_one_of works!'
+ end
+
+ data = {
+ orders: [
+ { id: 77, drugs: {batch_no: "A1234567"}},
+ { id: 70 }
+ ]
+ }
+
+ get '/at_least_one_of', data
+ expect(last_response.body).to eq("at_least_one_of works!")
+ expect(last_response.status).to eq(200)
+ end
+
+ it "all_or_none_of" do
+ subject.params do
+ requires :orders, type: Array do
+ requires :id, type: Integer
+ optional :drugs, type: Hash do
+ optional :batch_no, type: String
+ optional :batch_id, type: String
+ all_or_none_of :batch_no, :batch_id
+ end
+ end
+ end
+
+ subject.get '/all_or_none_of' do
+ 'all_or_none_of works!'
+ end
+
+ data = {
+ orders: [
+ { id: 77, drugs: {batch_no: "A1234567", batch_id: "12"}},
+ { id: 70 }
+ ]
+ }
+
+ get '/all_or_none_of', data
+ expect(last_response.body).to eq("all_or_none_of works!")
+ expect(last_response.status).to eq(200)
+ end
end
context 'multiple validation errors' do
before do
subject.params do