# # ActiveFacts tests: Value instances in the Runtime API # Copyright (c) 2008 Clifford Heath. Read the LICENSE file. # #require 'ruby-debug'; Debugger.start #trap "INT" do # puts caller*"\n\t" # debugger #end describe "An instance of every type of ObjectType" do before :all do Object.send :remove_const, :Mod if Object.const_defined?("Mod") module Mod # These are the base value types we're going to test: @base_types = [ Int, Real, AutoCounter, String, Date, DateTime, Decimal, Guid ] # Construct the names of the roles they play: @base_type_roles = @base_types.map do |t| t.name.snakecase end @role_names = @base_type_roles.inject([]) {|a, t| a << :"#{t}_val" } + @base_type_roles.inject([]) {|a, t| a << :"#{t}_sub_val" } # Create a value type and a subtype of that value type for each base type: @base_types.each do |base_type| Mod.module_eval <<-END class #{base_type.name}Val < #{base_type.name} value_type end class #{base_type.name}SubVal < #{base_type.name}Val # Note no new "value_type" is required here, it comes through inheritance end END end # Create a TestByX, TestByXSub, and TestSubByX class for all base types X # Each class has a has_one and a one_to_one for all roles. # and is identified by the has_one :x role @base_types.each do |base_type| code = <<-END class TestBy#{base_type.name} identified_by :#{base_type.name.snakecase}_val#{ @role_names.map do |role_name| %Q{ #{ (role_name == (base_type.name.snakecase+'_val').to_sym ? "one_to_one :#{role_name}, :mandatory => true" : "has_one :#{role_name}") } one_to_one :one_#{role_name}, :class => #{role_name.to_s.camelcase}} end*"" } end class TestBy#{base_type.name}Sub identified_by :#{base_type.name.snakecase}_sub_val#{ @role_names.map do |role_name| %Q{ #{ (role_name == (base_type.name.snakecase+'_sub_val').to_sym ? "one_to_one :#{role_name}" : "has_one :#{role_name}") } one_to_one :one_#{role_name}, :class => #{role_name.to_s.camelcase}} end*"" } end class TestSubBy#{base_type.name} < TestBy#{base_type.name} # Entity subtypes, inherit identification and all roles end class TestBy#{base_type.name}Entity identified_by :test_by_#{base_type.name.snakecase} one_to_one :test_by_#{base_type.name.snakecase} end END begin Mod.module_eval code rescue Exception => e puts "Failure: #{e}" puts "Failed on: < e puts "FAILED on #{object.class} at #{i}" raise end end end it "if a value, should verbalise" do @value_instances.each do |value| #puts value.verbalise value.respond_to?(:verbalise).should be_true verbalisation = value.verbalise verbalisation.should =~ %r{\b#{value.class.basename}\b} end end it "if an entity, should respond to verbalise" do (@entities+@entities_by_entity).each do |entity| entity.respond_to?(:verbalise).should be_true verbalisation = entity.verbalise verbalisation.should =~ %r{\b#{entity.class.basename}\b} entity.class.identifying_role_names.each do |ir| role = entity.class.roles(ir) role.should_not be_nil counterpart_object_type = role.counterpart.object_type verbalisation.should =~ %r{\b#{counterpart_object_type.basename}\b} end end end end it "should respond to constellation" do (@value_instances+@entities+@entities_by_entity).each do |instance| next if instance == nil instance.respond_to?(:constellation).should be_true end end it "should return the module in response to .vocabulary()" do (@value_types+@entity_types).zip((@value_instances+@entities+@entities_by_entity)).each do |object_type, instance| next if instance == nil instance.class.vocabulary.should == Mod end end it "should disallow treating an unresolved AutoCounter as an integer" do c = ActiveFacts::API::Constellation.new(Mod) a = c.AutoCounterVal(:new) lambda { b = 2 + a }.should raise_error a.assign(3) lambda { b = 2 + a a.to_i }.should_not raise_error end it "should complain when not enough identifying values are provided for an entity" do c = ActiveFacts::API::Constellation.new(Mod) lambda { c.TestByInt(:int_val => nil) }.should raise_error end it "should complain when too many identifying values are provided for an entity" do c = ActiveFacts::API::Constellation.new(Mod) lambda { c.TestByInt(2, 3) }.should raise_error end it "should complain when wrong type is used for an entity" do c = ActiveFacts::API::Constellation.new(Mod) lambda { c.TestByInt("Not an Int") }.should raise_error end it "should handle a non-mandatory missing identifying role" do module Mod2 class Word identified_by :singular, :plural has_one :singular, :class => "Spelling", :mandatory => true has_one :plural, :class => "Spelling" end class Spelling < String value_type end end c = ActiveFacts::API::Constellation.new(Mod2) s = c.Word('sheep') f = c.Word('fish', :plural => nil) a = c.Word('aircraft', nil) s.plural.should be_nil f.plural.should be_nil a.plural.should be_nil end it "should handle a unary as an identifying role" do module Mod2 class Status identified_by :is_ok maybe :is_ok end end c = ActiveFacts::API::Constellation.new(Mod2) n = c.Status(:is_ok => nil) t = c.Status(:is_ok => true) f = c.Status(:is_ok => false) s = c.Status(:is_ok => 'foo') n.is_ok.should == nil t.is_ok.should == true f.is_ok.should == false s.is_ok.should == true n.is_ok = nil t.is_ok = true f.is_ok = false s.is_ok = true n.is_ok.should == nil t.is_ok.should == true f.is_ok.should == false s.is_ok.should == true end end