From 8f9b01eeac475ff2191ee051f2513e1221069017 Mon Sep 17 00:00:00 2001 From: Guillaume Hain <zedtux@zedroot.org> Date: Thu, 20 Oct 2022 20:04:45 +0200 Subject: [PATCH] Adds tests for mass assignment --- spec/integration/types_spec.rb | 221 ++++++++++++++++++++++++--------- 1 file changed, 164 insertions(+), 57 deletions(-) diff --git a/spec/integration/types_spec.rb b/spec/integration/types_spec.rb index 319db91ce4..8b77cb61a9 100644 --- a/spec/integration/types_spec.rb +++ b/spec/integration/types_spec.rb @@ -1,9 +1,12 @@ require 'spec_helper' -describe 'types' do - before { load_simple_document } - before { SimpleDocument.field :field1, field_options } - let(:field_options) { { :type => type } } +describe NoBrainer::Document::Types do + before do + load_simple_document + SimpleDocument.field :field1, field_options + end + + let(:field_options) { { type: type } } let(:doc) { SimpleDocument.new } context 'when using String type' do @@ -34,6 +37,16 @@ end end + context 'with mass assignment' do + let!(:document) { SimpleDocument.create! } + + it 'updates the document' do + expect do + document.update(field1: 'Hello') + end.to change(document, :field1).from(nil).to('Hello') + end + end + it 'type checks and casts on length' do doc.field1 = "x" * NoBrainer::Config.max_string_length doc.field1.should == "x" * NoBrainer::Config.max_string_length @@ -50,12 +63,12 @@ let(:type) { SimpleDocument::Text } it 'type checks and casts' do - doc.field1 = 'ohai' - doc.field1.should == 'ohai' - doc.valid?.should == true - doc.field1 = :ohai - doc.field1.should == :ohai - doc.valid?.should == false + doc.field1 = 'ohai' + doc.field1.should == 'ohai' + doc.valid?.should == true + doc.field1 = :ohai + doc.field1.should == :ohai + doc.valid?.should == false end it 'type does not checks length' do @@ -68,6 +81,22 @@ context 'when using Integer type' do let(:type) { Integer } + context 'with mass assignment' do + let!(:document) { SimpleDocument.create! } + + it 'updates the document when passing a number' do + expect do + document.update(field1: 1) + end.to change(document, :field1).from(nil).to(1) + end + + it 'updates the document when passing a number as a String' do + expect do + document.update(field1: '2') + end.to change(document, :field1).from(nil).to(2) + end + end + it 'type checks and casts' do doc.field1 = 1 doc.field1.should == 1 @@ -165,6 +194,22 @@ context 'when using Boolean type' do let(:type) { SimpleDocument::Boolean } + context 'with mass assignment' do + let!(:document) { SimpleDocument.create! } + + it 'updates the document when passing a boolean' do + expect do + document.update(field1: true) + end.to change(document, :field1).from(nil).to(true) + end + + it 'updates the document when passing a boolean as a String' do + expect do + document.update(field1: 'false') + end.to change(document, :field1).from(nil).to(false) + end + end + it 'provides a ? method' do doc.field1 = true doc.field1?.should == true @@ -232,7 +277,17 @@ context 'when using Binary type' do let(:type) { SimpleDocument::Binary } - let(:data) { 255.times.map { |i| i.chr }.join } + let(:data) { 255.times.map(&:chr).join } + + context 'with mass assignment' do + let!(:document) { SimpleDocument.create! } + + it 'updates the document when passing a binary' do + expect do + document.update(field1: data) + end.to change(document, :field1).from(nil).to(data) + end + end it 'type checks and casts' do doc.field1 = 'hello' @@ -257,6 +312,16 @@ context 'when using Symbol type' do let(:type) { Symbol } + context 'with mass assignment' do + let!(:document) { SimpleDocument.create! } + + it 'updates the document when passing a Symbol' do + expect do + document.update(field1: :value) + end.to change(document, :field1).from(nil).to(:value) + end + end + it 'type checks and casts' do doc.field1 = :ohai doc.field1.should == :ohai @@ -294,10 +359,25 @@ context 'when using Time type' do let(:type) { Time } + let(:now) { Time.at(Time.now.to_i) } - it 'type checks and casts' do - now = Time.at(Time.now.to_i) + context 'with mass assignment' do + let!(:document) { SimpleDocument.create! } + + it 'updates the document when passing a Time' do + expect do + document.update(field1: now) + end.to change(document, :field1).from(nil).to(now) + end + + it 'updates the document when passing a Time as a String' do + expect do + document.update(field1: now.iso8601) + end.to change(document, :field1).from(nil).to(now) + end + end + it 'type checks and casts' do doc.field1 = now doc.field1.should == now doc.valid?.should == true @@ -426,9 +506,8 @@ let(:user_timezone) { :unchanged } let(:db_timezone) { :unchanged } - it 'db reads timezone does not change' do - NoBrainer.run { SimpleDocument.rql_table.insert(:field1 => time) } + NoBrainer.run { SimpleDocument.rql_table.insert(field1: time) } SimpleDocument.first.field1.utc_offset.should == time.utc_offset end end @@ -438,7 +517,7 @@ let(:db_timezone) { :unchanged } it 'db reads timezone changes to local' do - NoBrainer.run { SimpleDocument.rql_table.insert(:field1 => time) } + NoBrainer.run { SimpleDocument.rql_table.insert(field1: time) } SimpleDocument.first.field1.utc_offset.should == time.utc.getlocal.utc_offset end end @@ -448,7 +527,7 @@ let(:db_timezone) { :unchanged } it 'db reads timezone changes to utc' do - NoBrainer.run { SimpleDocument.rql_table.insert(:field1 => time) } + NoBrainer.run { SimpleDocument.rql_table.insert(field1: time) } SimpleDocument.first.field1.utc_offset.should == time.utc.utc_offset end end @@ -457,24 +536,46 @@ context 'when using Date type' do let(:type) { Date } + let(:today) { Date.today } - it 'type checks and casts' do - today = Date.today + context 'with mass assignment' do + let!(:document) { SimpleDocument.create! } + + it 'updates the document when passing a Date' do + expect do + document.update(field1: today) + end.to change(document, :field1).from(nil).to(today) + end + + it 'updates the document when passing a Date as a String' do + expect do + document.update(field1: today.strftime('%F')) + end.to change(document, :field1).from(nil).to(today) + end + + it 'updates the document when passing a Date as a String' do + expect do + document.update(field1: '2022-10-20') + end.to change(document, :field1).from(nil).to(Date.new(2022, 10, 20)) + end + end + it 'type checks and casts' do doc.field1 = today doc.field1.should == today doc.valid?.should == true doc.field1 = "2014-06-26T15:34:12-02:00" doc.field1.should == "2014-06-26T15:34:12-02:00" + # ERROR: Field1 should be a date doc.valid?.should == false doc.field1 = 123 doc.field1.should == 123 doc.valid?.should == false - doc.field1 = "2014-06-26" - doc.field1.should == Date.parse("2014-06-26") + doc.field1 = '2014-06-26' + doc.field1.should == Date.parse('2014-06-26') doc.valid?.should == true doc.field1 = nil @@ -482,31 +583,35 @@ doc.reload doc.field1.should == nil - doc.field1 = "2014-06-26" + doc.field1 = '2014-06-26' doc.save doc.reload - doc.field1.should == Date.parse("2014-06-26") + doc.field1.should == Date.parse('2014-06-26') - SimpleDocument.where(:field1 => Date.parse("2014-06-26")).count.should == 1 + SimpleDocument.where(field1: Date.parse('2014-06-26')).count.should == 1 end end context 'when using a non implemented type' do let(:type) { nil } - before { define_class(:CustomType) { } } - before { SimpleDocument.field :field1, :type => CustomType } + + before do + define_class(:CustomType) { } + SimpleDocument.field :field1, type: CustomType + end it 'type checks' do doc.field1 = CustomType.new doc.valid?.should == true doc.field1 = 123 doc.valid?.should == false - doc.errors.full_messages.first.should == "Field1 should be a custom type" + doc.errors.full_messages.first.should == 'Field1 should be a custom type' end end context 'when using a custom type' do let(:type) { nil } + before do define_class :Point, Struct.new(:x, :y) do def self.nobrainer_cast_user_to_model(value) @@ -522,11 +627,12 @@ def self.nobrainer_cast_db_to_model(value) end def self.nobrainer_cast_model_to_db(value) - {'x' => value.x, 'y' => value.y} + { 'x' => value.x, 'y' => value.y } end end + + SimpleDocument.field :field1, type: Point end - before { SimpleDocument.field :field1, :type => Point } it 'type checks' do doc.field1 = Point.new @@ -535,9 +641,9 @@ def self.nobrainer_cast_model_to_db(value) doc.field1 = 123 doc.field1.should == 123 doc.valid?.should == false - doc.errors.full_messages.first.should == "Field1 should be a point" + doc.errors.full_messages.first.should == 'Field1 should be a point' - doc.field1 = {:x => 123, :y => 456} + doc.field1 = { x: 123, y: 456 } doc.field1.should == Point.new(123, 456) doc.valid?.should == true @@ -548,11 +654,12 @@ def self.nobrainer_cast_model_to_db(value) context 'when coming from the database with a cast that cannot be perfomred' do let(:type) { nil } + it 'does not type check/cast' do doc.field1 = '1' doc.save SimpleDocument.first.field1.should == '1' - SimpleDocument.field :field1, :type => Integer + SimpleDocument.field :field1, type: Integer SimpleDocument.first.field1.should == '1' end end @@ -600,16 +707,16 @@ def self.nobrainer_cast_model_to_db(value) doc.field1 = [] doc.valid?.should == false - doc.field1 = [1,2] + doc.field1 = [1, 2] doc.valid?.should == true - doc.field1.should == type.new(1,2) + doc.field1.should == type.new(1, 2) - doc.field1 = [1,2,3] + doc.field1 = [1, 2, 3] doc.valid?.should == false doc.field1 = ['1.2', '-2'] doc.valid?.should == true - doc.field1.should == type.new(1.2,-2) + doc.field1.should == type.new(1.2, -2) doc.field1.inspect.should == [1.2, -2.0].inspect doc.field1 = ['1.2x', '-2'] @@ -633,32 +740,32 @@ def self.nobrainer_cast_model_to_db(value) doc.field1 = [0, -91] doc.valid?.should == false - doc.field1 = {:longitude => 1, :latitude => 2} + doc.field1 = { longitude: 1, latitude: 2 } doc.valid?.should == true doc.field1.should == type.new(1, 2) - doc.field1 = {:long => 1, :lat => 2} + doc.field1 = { long: 1, lat: 2 } doc.valid?.should == true doc.field1.should == type.new(1, 2) - doc.field1 = {:longi => 1, :lat => 2} + doc.field1 = { longi: 1, lat: 2 } doc.valid?.should == false - doc.field1 = type.new(1,2) + doc.field1 = type.new(1, 2) doc.valid?.should == true - doc.field1.should == type.new(1,2) + doc.field1.should == type.new(1, 2) end it 'reads back a set from the db' do - doc.field1 = [1,2] + doc.field1 = [1, 2] doc.save doc.reload - doc.field1.should == type.new(1,2) + doc.field1.should == type.new(1, 2) end end context 'when using Enum type' do - let(:field_options) { { :type => SimpleDocument::Enum, :in => [:a, :b] } } + let(:field_options) { { type: SimpleDocument::Enum, in: %i[a b] } } it 'type checks' do doc.field1 = :invalid @@ -689,7 +796,7 @@ def self.nobrainer_cast_model_to_db(value) context 'when using a prefix/suffix' do context 'with custom names' do - let(:field_options) { { :type => SimpleDocument::Enum, :in => [:a, :b], :prefix => :p, :suffix => :s } } + let(:field_options) { { type: SimpleDocument::Enum, in: %i[a b], prefix: :p, suffix: :s } } it 'names the methods properly' do doc.field1 = :a @@ -702,7 +809,7 @@ def self.nobrainer_cast_model_to_db(value) end context 'with default prefix' do - let(:field_options) { { :type => SimpleDocument::Enum, :in => [:a, :b], :prefix => true } } + let(:field_options) { { type: SimpleDocument::Enum, in: %i[a b], prefix: true } } it 'names the methods properly' do doc.field1 = :a @@ -715,7 +822,7 @@ def self.nobrainer_cast_model_to_db(value) end context 'with default suffix' do - let(:field_options) { { :type => SimpleDocument::Enum, :in => [:a, :b], :suffix => true } } + let(:field_options) { { type: SimpleDocument::Enum, in: %i[a b], suffix: true } } it 'names the methods properly' do doc.field1 = :a @@ -730,18 +837,18 @@ def self.nobrainer_cast_model_to_db(value) context 'when not specifying :in properly' do it 'fails' do - expect { SimpleDocument.field :field2, :type => SimpleDocument::Enum } + expect { SimpleDocument.field :field2, type: SimpleDocument::Enum } .to raise_error(/provide.*:in/) - expect { SimpleDocument.field :field2, :type => SimpleDocument::Enum, :in => [] } + expect { SimpleDocument.field :field2, type: SimpleDocument::Enum, in: [] } .to raise_error(/provide.*:in/) - expect { SimpleDocument.field :field2, :type => SimpleDocument::Enum, :in => [123] } + expect { SimpleDocument.field :field2, type: SimpleDocument::Enum, in: [123] } .to raise_error(/symbol values/) end end context 'when specifying overlapping values' do it 'fails' do - expect { SimpleDocument.field :field2, :type => SimpleDocument::Enum, :in => [:a] } + expect { SimpleDocument.field :field2, type: SimpleDocument::Enum, in: [:a] } .to raise_error(/already taken/) end end @@ -765,8 +872,8 @@ def self.nobrainer_cast_model_to_db(value) let(:type) { NoBrainer::TypedArray.of(Date) } it 'type checks and casts array elements' do - date_strs = %w(2020-09-21 2020-09-22 2020-09-23) - dates = date_strs.map { |s| Date.parse(s) } + date_strs = %w[2020-09-21 2020-09-22 2020-09-23] + dates = date_strs.map { |s| Date.parse(s) } doc.field1 = dates doc.field1.should == dates @@ -785,7 +892,7 @@ def self.nobrainer_cast_model_to_db(value) doc.reload doc.field1.should == dates - SimpleDocument.where(:field1 => dates).count.should == 1 + SimpleDocument.where(field1: dates).count.should == 1 SimpleDocument.where(:field1.any.eq => dates.first).count.should == 1 end end @@ -794,7 +901,7 @@ def self.nobrainer_cast_model_to_db(value) let(:type) { NoBrainer::TypedArray.of(Date, allow_nil: true) } it 'type checks array elmeents' do - dates = %w(2020-09-21 2020-09-22 2020-09-23).map { |s| Date.parse(s) } + dates = %w(2020-09-21 2020-09-22 2020-09-23).map { |s| Date.parse(s) } doc.field1 = dates doc.valid?.should == true @@ -809,10 +916,10 @@ def self.nobrainer_cast_model_to_db(value) before { load_simple_document } it 'raises with Geo::Circle' do - expect { SimpleDocument.field :field1, :type => NoBrainer::Geo::Circle }.to raise_error(/Cannot store circles/) + expect { SimpleDocument.field :field1, type: NoBrainer::Geo::Circle }.to raise_error(/Cannot store circles/) end it 'raises with bad types' do - expect { SimpleDocument.field :field1, :type => "asdasd" }.to raise_error(/type option/) + expect { SimpleDocument.field :field1, type: 'asdasd' }.to raise_error(/type option/) end end