require 'test/unit' require File.join(File.dirname(__FILE__), '../lib/permalink_fu') begin require 'rubygems' require 'ruby-debug' Debugger.start rescue LoadError puts "no ruby debugger" end class FauxColumn < Struct.new(:limit) end class BaseModel def self.columns_hash @columns_hash ||= {'permalink' => FauxColumn.new(100)} end def self.inherited(base) subclasses << base end extend PermalinkFu::PluginMethods attr_accessor :id attr_accessor :title attr_accessor :extra attr_reader :permalink attr_accessor :foo class << self attr_accessor :validation, :subclasses end self.subclasses = [] def self.generated_methods @generated_methods ||= [] end def self.primary_key :id end def self.logger nil end def self.define_attribute_methods return unless generated_methods.empty? true end # ripped from AR def self.evaluate_attribute_method(attr_name, method_definition, method_name=attr_name) unless method_name.to_s == primary_key.to_s generated_methods << method_name end begin class_eval(method_definition, __FILE__, __LINE__) rescue SyntaxError => err generated_methods.delete(attr_name) if logger logger.warn "Exception occurred during reader method compilation." logger.warn "Maybe #{attr_name} is not a valid Ruby identifier?" logger.warn "#{err.message}" end end end def self.exists?(*args) false end def self.before_validation(method) self.validation = method end def validate send self.class.validation if self.class.validation permalink end def new_record? @id.nil? end def write_attribute(key, value) instance_variable_set "@#{key}", value end def read_attribute(key) instance_variable_get "@#{key}" end end class MockModel < BaseModel def self.exists?(conditions) if conditions[1] == 'foo' || conditions[1] == 'bar' || (conditions[1] == 'bar-2' && conditions[2] != 2) true else false end end has_permalink :title end class CommonMockModel < BaseModel def self.exists?(conditions) false # oh noes end has_permalink :title, :unique => false end class ScopedModel < BaseModel def self.exists?(conditions) if conditions[1] == 'foo' && conditions[2] != 5 true else false end end has_permalink :title, :scope => :foo end class ScopedModelForNilScope < BaseModel def self.exists?(conditions) (conditions[0] == 'permalink = ? and foo IS NULL') ? (conditions[1] == 'ack') : false end has_permalink :title, :scope => :foo end class OverrideModel < BaseModel has_permalink :title def permalink 'not the permalink' end end class ChangedModel < BaseModel has_permalink :title def title_changed?; true; end end class NoChangeModel < BaseModel has_permalink :title def title_changed?; false; end end class IfProcConditionModel < BaseModel has_permalink :title, :if => Proc.new { |obj| false } end class IfMethodConditionModel < BaseModel has_permalink :title, :if => :false_method def false_method; false; end end class IfStringConditionModel < BaseModel has_permalink :title, :if => 'false' end class UnlessProcConditionModel < BaseModel has_permalink :title, :unless => Proc.new { |obj| false } end class UnlessMethodConditionModel < BaseModel has_permalink :title, :unless => :false_method def false_method; false; end end class UnlessStringConditionModel < BaseModel has_permalink :title, :unless => 'false' end class MockModelExtra < BaseModel has_permalink [:title, :extra] end # trying to be like ActiveRecord, define the attribute methods manually BaseModel.subclasses.each { |c| c.send :define_attribute_methods } class PermalinkFuTest < Test::Unit::TestCase @@samples = { 'This IS a Tripped out title!!.!1 (well/ not really)' => 'this-is-a-tripped-out-title1-well-not-really', '////// meph1sto r0x ! \\\\\\' => 'meph1sto-r0x', 'āčēģīķļņū' => 'acegiklnu', '中文測試 chinese text' => 'chinese-text', 'fööbär' => 'foobar' } @@extra = { 'some-)()()-ExtRa!/// .data==?> to \/\/test' => 'some-extra-data-to-test' } def test_should_escape_permalinks @@samples.each do |from, to| assert_equal to, PermalinkFu.escape(from) end end def test_should_escape_activerecord_model @m = MockModel.new @@samples.each do |from, to| @m.title = from; @m.permalink = nil assert_equal to, @m.validate end end def test_should_escape_activerecord_model_with_existing_permalink @m = MockModel.new @@samples.each do |from, to| @m.title = 'whatever'; @m.permalink = from assert_equal to, @m.validate end end def test_multiple_attribute_permalink @m = MockModelExtra.new @@samples.each do |from, to| @@extra.each do |from_extra, to_extra| @m.title = from; @m.extra = from_extra; @m.permalink = nil assert_equal "#{to}-#{to_extra}", @m.validate end end end def test_should_create_unique_permalink @m = MockModel.new @m.permalink = 'foo' @m.validate assert_equal 'foo-2', @m.permalink @m.permalink = 'bar' @m.validate assert_equal 'bar-3', @m.permalink end def test_should_common_permalink_if_unique_is_false @m = CommonMockModel.new @m.permalink = 'foo' @m.validate assert_equal 'foo', @m.permalink end def test_should_not_check_itself_for_unique_permalink @m = MockModel.new @m.id = 2 @m.permalink = 'bar-2' @m.validate assert_equal 'bar-2', @m.permalink end def test_should_create_unique_scoped_permalink @m = ScopedModel.new @m.permalink = 'foo' @m.validate assert_equal 'foo-2', @m.permalink @m.foo = 5 @m.permalink = 'foo' @m.validate assert_equal 'foo', @m.permalink end def test_should_limit_permalink @old = MockModel.columns_hash['permalink'].limit MockModel.columns_hash['permalink'].limit = 2 @m = MockModel.new @m.title = 'BOO' assert_equal 'bo', @m.validate ensure MockModel.columns_hash['permalink'].limit = @old end def test_should_limit_unique_permalink @old = MockModel.columns_hash['permalink'].limit MockModel.columns_hash['permalink'].limit = 3 @m = MockModel.new @m.title = 'foo' assert_equal 'f-2', @m.validate ensure MockModel.columns_hash['permalink'].limit = @old end def test_should_abide_by_if_proc_condition @m = IfProcConditionModel.new @m.title = 'dont make me a permalink' @m.validate assert_nil @m.permalink end def test_should_abide_by_if_method_condition @m = IfMethodConditionModel.new @m.title = 'dont make me a permalink' @m.validate assert_nil @m.permalink end def test_should_abide_by_if_string_condition @m = IfStringConditionModel.new @m.title = 'dont make me a permalink' @m.validate assert_nil @m.permalink end def test_should_abide_by_unless_proc_condition @m = UnlessProcConditionModel.new @m.title = 'make me a permalink' @m.validate assert_not_nil @m.permalink end def test_should_abide_by_unless_method_condition @m = UnlessMethodConditionModel.new @m.title = 'make me a permalink' @m.validate assert_not_nil @m.permalink end def test_should_abide_by_unless_string_condition @m = UnlessStringConditionModel.new @m.title = 'make me a permalink' @m.validate assert_not_nil @m.permalink end def test_should_allow_override_of_permalink_method @m = OverrideModel.new @m.write_attribute(:permalink, 'the permalink') assert_not_equal @m.permalink, @m.read_attribute(:permalink) end def test_should_create_permalink_from_attribute_not_attribute_accessor @m = OverrideModel.new @m.title = 'the permalink' @m.validate assert_equal 'the-permalink', @m.read_attribute(:permalink) end def test_should_not_update_permalink_unless_field_changed @m = NoChangeModel.new @m.title = 'the permalink' @m.validate assert_nil @m.read_attribute(:permalink) end def test_should_update_permalink_if_field_changed @m = OverrideModel.new @m.title = 'the permalink' @m.validate assert_equal 'the-permalink', @m.read_attribute(:permalink) end def test_should_update_permalink_if_changed_method_does_not_exist @m = OverrideModel.new @m.title = 'the permalink' @m.validate assert_equal 'the-permalink', @m.read_attribute(:permalink) end def test_should_work_correctly_for_scoped_fields_with_nil_value s1 = ScopedModelForNilScope.new s1.title = 'ack' s1.foo = 3 s1.validate assert_equal 'ack', s1.permalink s2 = ScopedModelForNilScope.new s2.title = 'ack' s2.foo = nil s2.validate assert_equal 'ack-2', s2.permalink end end