spec/attribute_spec.rb in attributor-2.6.1 vs spec/attribute_spec.rb in attributor-3.0

- old
+ new

@@ -91,10 +91,52 @@ it 'includes sub-attributes' do description[:type][:attributes].should have_key(:id) end end + + context 'with an example' do + + let(:attribute_options){ {} } + let(:example){ attribute.example } + subject(:described){ attribute.describe(false, example: example) } + + context 'using a simple terminal type' do + let(:type) { String } + its(:keys){ should include(:example) } + it 'should have the passed example value' do + described.should have_key(:example) + described[:example].should eq(example) + end + it 'should have removed the example from the :type' do + described[:type].should_not have_key(:example) + end + + end + + context 'using a complex type' do + let(:type) { Cormorant } + its(:keys){ should_not include(:example) } + + it 'Should see examples in the right places, depending on leaf/no-leaf types' do + # String, a leaf attribute type: should have example + name_attr = described[:type][:attributes][:name] + name_attr.should include(:example) + name_attr[:type].should_not include(:example) + + # Struct, a non-leaf attribute type: shouldn't have example + ts_attr = described[:type][:attributes][:timestamps] + ts_attr.should_not include(:example) + ts_attr[:type].should_not include(:example) + + # DateTime inside a Struct, a nested leaf attribute type: should have example + born_attr = ts_attr[:type][:attributes][:born_at] + born_attr.should include(:example) + born_attr[:type].should_not include(:example) + end + end + end end context 'parse' do let(:loaded_object){ double("I'm loaded") } @@ -133,14 +175,12 @@ }.not_to raise_error end end end - context 'example' do let(:example) { nil } - let(:attribute_options) { {:example => example} } context 'with nothing specified' do let(:attribute_options) { {} } before do type.should_receive(:example).and_return(example) @@ -149,112 +189,145 @@ it 'defers to the type' do attribute.example.should be example end end + context 'with an attribute that has the values option set' do + let(:values) { ["one", "two"] } + let(:attribute_options) { {:values => values} } + it 'picks a random value' do + values.should include subject.example + end + end + + context 'deterministic examples' do + let(:example) { /\w+/ } + let(:attribute_options) { {:example => example} } + + it 'can take a context to pre-seed the random number generator' do + example_1 = subject.example(['context']) + example_2 = subject.example(['context']) + + example_1.should eq example_2 + end + + it 'can take a context to pre-seed the random number generator' do + example_1 = subject.example(['context']) + example_2 = subject.example(['different context']) + + example_1.should_not eq example_2 + end + end + + context 'with an example option' do + let(:example){ "Bob" } + let(:attribute_options) { {example: example , regexp: /Bob/ } } + + its(:example){ should == example } + + context 'that is not valid' do + let(:example){ "Frank" } + it 'raises a validation error' do + expect{ + subject.example + }.to raise_error(Attributor::AttributorException, /Error generating example/) + end + end + end + end + + context 'example_from_options' do + let(:example) { nil } + let(:generated_example) { example } + let(:attribute_options) { {:example => example} } + let(:parent){ nil } + let(:context){ Attributor::DEFAULT_ROOT_CONTEXT} + + subject(:example_result) { attribute.example_from_options( parent, context ) } + before do + attribute.should_receive(:load).with( generated_example , an_instance_of(Array) ).and_call_original + end + context 'with a string' do let(:example) { "example" } - its(:example) { should be example } + it { should be example } end + context 'with an integer' do + let(:type) { Attributor::Integer } + let(:example) { 5 } + it { should be example } + end + context 'with a regexp' do let(:example) { /\w+/ } + let(:generated_example) { /\w+/.gen } - it 'calls #gen on the regexp' do - example.should_receive(:gen).and_call_original - subject.example.should =~ example + example.should_receive(:gen).and_return(generated_example) + + example_result.should =~ example end context 'for a type with a non-String native_type' do let(:type) { Attributor::Integer } - context 'using a regexp' do - let(:example) { /\d{5}/ } - it 'coerces the example value properly' do - example.should_receive(:gen).and_call_original - type.should_receive(:load).and_call_original - - subject.example.should be_kind_of(type.native_type) - end + let(:example) { /\d{5}/ } + let(:generated_example) { /\d{5}/.gen } + + it 'coerces the example value properly' do + example.should_receive(:gen).and_return(generated_example) + type.should_receive(:load).and_call_original + + example_result.should be_kind_of(type.native_type) end - context 'usign a native Integer type' do - let(:example) { 5 } - it 'coerces the example value properly' do - type.should_receive(:load).and_call_original - subject.example.should be_kind_of(type.native_type) - end - end end + end - context 'with a proc' do + let(:parent){ Object.new } + context 'with one argument' do let(:example) { lambda { |obj| 'ok' } } - let(:some_object) { Object.new } + let(:generated_example) { 'ok' } before do - example.should_receive(:call).with(some_object).and_call_original + example.should_receive(:call).with(parent).and_return(generated_example) end it 'passes any given parent through to the example proc' do - subject.example(nil, parent: some_object).should == 'ok' + example_result.should == 'ok' end end context 'with two arguments' do let(:example) { lambda { |obj, context| "#{context} ok" } } - let(:some_object) { Object.new } - let(:some_context) { ['some_context'] } - + let(:generated_example) { "#{context} ok" } + let(:context){ ['some_context'] } before do - example.should_receive(:call).with(some_object, some_context).and_call_original + example.should_receive(:call).with(parent, context).and_return(generated_example) end it 'passes any given parent through to the example proc' do - subject.example(some_context, parent: some_object).should == "#{some_context} ok" + example_result.should == "#{context} ok" end end end context 'with an array' do - let(:example) { ["one", "two"] } + let(:example) { ["one"] } + let(:generated_example) { "one" } it 'picks a random value' do - example.should include subject.example + example.should_receive(:pick).and_call_original + example.should include example_result end - end - context 'with an attribute that has the values option set' do - let(:values) { ["one", "two"] } - let(:attribute_options) { {:values => values} } - it 'picks a random value' do - values.should include subject.example - end - end - context 'deterministic examples' do - let(:example) { /\w+/ } - it 'can take a context to pre-seed the random number generator' do - example_1 = subject.example(['context']) - example_2 = subject.example(['context']) - - example_1.should eq example_2 - end - - it 'can take a context to pre-seed the random number generator' do - example_1 = subject.example(['context']) - example_2 = subject.example(['different context']) - - example_1.should_not eq example_2 - end - - - end end context 'load' do let(:context){ ['context'] } let(:value) { '1' } @@ -284,35 +357,35 @@ let(:type) { Attributor::Boolean } let(:default_value) { false } it { should == default_value} end - + context 'for a Proc-based default value' do let(:context){ ["$"] } subject(:result){ attribute.load(value,context) } context 'with no arguments arguments' do let(:default_value) { proc { "no_params" } } it { should == default_value.call } end - + context 'with 1 argument (the parent)' do let(:default_value) { proc {|parent| "parent is fake: #{parent.class}" } } it { should == "parent is fake: Attributor::FakeParent" } end - + context 'with 2 argument (the parent and the contents)' do let(:default_value) { proc {|parent,context| "parent is fake: #{parent.class} and context is: #{context}" } } it { should == "parent is fake: Attributor::FakeParent and context is: [\"$\"]"} end - + context 'which attempts to use the parent (which is not supported for the moment)' do let(:default_value) { proc {|parent| "any parent method should spit out warning: [#{parent.something}]" } } it "should output a warning" do - begin + begin old_verbose, $VERBOSE = $VERBOSE, nil Kernel.should_receive(:warn).and_call_original attribute.load(value,context).should == "any parent method should spit out warning: []" ensure $VERBOSE = old_verbose @@ -635,10 +708,9 @@ let(:attribute_block) { Proc.new{ attribute :angry , required: true } } let(:attribute_options) { {reference: Chicken, member_options: member_options} } let(:member_type) { Attributor::Struct } let(:type) { Attributor::Collection.of(member_type) } let(:member_options) { {} } - context 'the member_attribute of that type' do subject(:member_attribute) { attribute.type.member_attribute } it { should be_kind_of(Attributor::Attribute)} its(:options) { should eq(member_options.merge(reference: Chicken, identity: :email)) }