Start major refactoring of recurring_todos. Started with creating new recurring todos.

All current and new tests pass
This commit is contained in:
Reinier Balt 2014-01-27 16:42:54 +01:00
parent 8e13059df1
commit 78c07d52b7
26 changed files with 1218 additions and 32 deletions

View file

@ -106,33 +106,9 @@ class RecurringTodosController < ApplicationController
end
def create
p = RecurringTodoCreateParamsHelper.new(params, recurring_todo_params)
p.attributes['end_date']=parse_date_per_user_prefs(p.attributes['end_date'])
p.attributes['start_from']=parse_date_per_user_prefs(p.attributes['start_from'])
# make sure we set :recurring_period first, since other setters depend on it being set
# TODO: move logic into model
@recurring_todo = current_user.recurring_todos.build(:recurring_period => params[:recurring_period])
@recurring_todo.assign_attributes(p.selector_attributes)
@recurring_todo.update_attributes(p.attributes)
if p.project_specified_by_name?
project = current_user.projects.where(:name => p.project_name).first_or_create
@new_project_created = project.new_record_before_save?
@recurring_todo.project_id = project.id
end
if p.context_specified_by_name?
context = current_user.contexts.where(:name => p.context_name).first_or_create
@new_context_created = context.new_record_before_save?
@recurring_todo.context_id = context.id
end
@saved = @recurring_todo.save
if @saved && p.tag_list.present?
@recurring_todo.tag_with(p.tag_list)
@recurring_todo.tags.reload
end
builder = RecurringTodos::RecurringTodosBuilder.new(current_user, all_recurring_todo_params)
@saved = builder.save
@recurring_todo = builder.saved_recurring_todo
if @saved
@status_message = t('todos.recurring_action_saved')
@ -278,7 +254,7 @@ class RecurringTodosController < ApplicationController
:ends_on, :end_date, :number_of_occurences, :occurences_count, :target,
:show_from_delta, :recurring_period, :recurrence_selector, :every_other1,
:every_other2, :every_other3, :every_day, :only_work_days, :every_count,
:weekday, :show_always,
:weekday, :show_always, :context_name, :project_name, :tag_list,
# form attributes
:recurring_period, :daily_selector, :monthly_selector, :yearly_selector,
:recurring_target, :daily_every_x_days, :monthly_day_of_week,
@ -293,6 +269,14 @@ class RecurringTodosController < ApplicationController
)
end
def all_recurring_todo_params
# move context_name, project_name and tag_list into :recurring_todo hash for easier processing
params[:recurring_todo][:context_name] = params[:context_name] unless params[:context_name].blank?
params[:recurring_todo][:project_name] = params[:project_name] unless params[:project_name].blank?
params[:recurring_todo][:tag_list] = params[:tag_list] unless params[:tag_list].blank?
recurring_todo_params
end
def init
@days_of_week = []
0.upto 6 do |i|

View file

@ -107,7 +107,7 @@ class RecurringTodo < ActiveRecord::Base
errors[:base] << "Please fill in the number of days to show the todo before the due date" if show_from_delta.blank?
end
else
raise Exception.new, "unexpected value of recurrence target selector '#{recurrence_target}'"
raise Exception.new, "unexpected value of recurrence target selector '#{target}'"
end
end

View file

@ -0,0 +1,72 @@
module RecurringTodos
class AbstractRecurringTodosBuilder
def initialize(user, attributes)
@user = user
@attributes = attributes
@filterred_attributes = filter_attributes(attributes)
@saved = false
end
def filter_attributes(attributes)
raise Exception.new, "filter_attributes should be overridden"
end
def filter_generic_attributes(attributes)
attributes['tag_list'] =
{
recurring_period: attributes["recurring_period"],
description: attributes['description'],
notes: attributes['notes'],
tag_list: tag_list_or_empty_string(attributes),
start_from: attributes['start_from'],
end_date: attributes['end_date'],
ends_on: attributes['ends_on'],
show_always: attributes['show_always'],
target: attributes['target'],
project: attributes[:project],
context: attributes[:context],
target: attributes['recurring_target'],
show_from_delta: attributes['recurring_show_days_before'],
show_always: attributes['recurring_show_always']
}
end
# build does not add tags. For tags, the recurring todos needs to be saved
def build
@recurring_todo = @pattern.build_recurring_todo
@recurring_todo.context = @filterred_attributes[:context]
@recurring_todo.project = @filterred_attributes[:project]
end
def save
build
@saved = @recurring_todo.save
@recurring_todo.tag_with(@filterred_attributes[:tag_list]) if @saved && @filterred_attributes[:tag_list].present?
return @saved
end
def saved_recurring_todo
if !@saved
raise Exception.new, @recurring_todo.valid? ? "Recurring todo was not saved yet" : "Recurring todos was not saved because of validation errors"
end
@recurring_todo
end
def attributes
@pattern.attributes
end
private
def tag_list_or_empty_string(attributes)
# avoid nil
attributes['tag_list'].blank? ? "" : attributes['tag_list'].strip
end
end
end

View file

@ -0,0 +1,42 @@
module RecurringTodos
class AbstractRepeatPattern
def initialize(user, attributes)
@attributes = attributes
@user = user
end
def build_recurring_todo
@recurring_todo = @user.recurring_todos.build(mapped_attributes)
end
def mapped_attributes
@attributes
end
def attributes
mapped_attributes
end
def map(mapping, key, source_key)
mapping[key] = mapping[source_key]
mapping.except(source_key)
end
def get_selector(key)
raise Exception.new, "recurrence selector pattern (#{key}) not given" unless @attributes.key?(key)
raise Exception.new, "unknown recurrence selector pattern: '#{@attributes[key]}'" unless valid_selector?(@attributes[key])
selector = @attributes[key]
@attributes = @attributes.except(key)
return selector
end
def valid_selector?(selector)
raise Exception.new, "valid_selector? should be overridden in subclass of AbstractRepeatPattern"
end
end
end

View file

@ -0,0 +1,19 @@
module RecurringTodos
class DailyRecurringTodosBuilder < AbstractRecurringTodosBuilder
attr_reader :recurring_todo, :pattern
def initialize(user, attributes)
super(user, attributes)
@pattern = DailyRepeatPattern.new(user, @filterred_attributes)
end
def filter_attributes(attributes)
@filterred_attributes = filter_generic_attributes(attributes)
%w{daily_selector daily_every_x_days}.each{|key| @filterred_attributes[key] = attributes[key] if attributes.key?(key)}
@filterred_attributes
end
end
end

View file

@ -0,0 +1,42 @@
module RecurringTodos
class DailyRepeatPattern < AbstractRepeatPattern
def initialize(user, attributes)
super user, attributes
@selector = get_selector('daily_selector')
end
def mapped_attributes
mapping = @attributes
mapping[:only_work_days] = only_work_days?(@selector)
mapping[:every_other1] = mapping['daily_every_x_days']
mapping = mapping.except('daily_every_x_days')
mapping
end
def every_x_days
@recurring_todo.every_other1
end
private
def only_work_days?(daily_selector)
case daily_selector
when 'daily_every_x_day'
return false
when 'daily_every_work_day'
return true
end
end
def valid_selector?(selector)
%w{daily_every_x_day daily_every_work_day}.include?(selector)
end
end
end

View file

@ -0,0 +1,25 @@
module RecurringTodos
class MonthlyRecurringTodosBuilder < AbstractRecurringTodosBuilder
def initialize(user, attributes)
super(user, attributes)
@pattern = MonthlyRepeatPattern.new(user, @filterred_attributes)
end
def filter_attributes(attributes)
@filterred_attributes = filter_generic_attributes(attributes)
%w{
monthly_selector monthly_every_x_day monthly_every_x_month
monthly_every_x_month2 monthly_every_xth_day monthly_day_of_week
}.each do |key|
@filterred_attributes[key] = attributes[key] if attributes.key?(key)
end
@filterred_attributes
end
end
end

View file

@ -0,0 +1,49 @@
module RecurringTodos
class MonthlyRepeatPattern < AbstractRepeatPattern
def initialize(user, attributes)
super user, attributes
@selector = get_selector('monthly_selector')
end
def mapped_attributes
mapping = @attributes
mapping = map(mapping, :every_other1, 'monthly_every_x_day')
mapping = map(mapping, :every_other3, 'monthly_every_xth_day')
mapping = map(mapping, :every_count, 'monthly_day_of_week')
mapping[:every_other2] = mapping[get_every_other2]
mapping = mapping.except('monthly_every_x_month').except('monthly_every_x_month2')
mapping[:recurrence_selector] = get_recurrence_selector
mapping
end
def every_x_day?
@recurring_todo.recurrence_selector == 0
end
def every_xth_day?
@recurring_todo.recurrence_selector == 1
end
private
def get_recurrence_selector
@selector=='monthly_every_x_day' ? 0 : 1
end
def get_every_other2
get_recurrence_selector == 0 ? 'monthly_every_x_month' : 'monthly_every_x_month2'
end
def valid_selector?(selector)
%w{monthly_every_x_day monthly_every_xth_day}.include?(selector)
end
end
end

View file

@ -0,0 +1,104 @@
module RecurringTodos
class RecurringTodosBuilder
attr_reader :builder, :project, :context, :tag_list, :user
def initialize (user, attributes)
@user = user
@attributes = attributes
parse_dates
parse_project
parse_context
@builder = create_builder(attributes['recurring_period'])
end
def create_builder(selector)
if %w{daily weekly monthly yearly}.include?(selector)
return eval("RecurringTodos::#{selector.capitalize}RecurringTodosBuilder.new(@user, @attributes)")
else
raise Exception.new("Unknown recurrence selector (#{selector})")
end
end
def build
@builder.build
end
def save
@project.save if @new_project_created
@context.save if @new_context_created
return @builder.save
end
def saved_recurring_todo
@builder.saved_recurring_todo
end
def recurring_todo
@builder.recurring_todo
end
def attributes
@builder.attributes
end
private
def parse_dates
%w{end_date start_from}.each {|date| @attributes[date] = @user.prefs.parse_date(@attributes[date])}
end
def parse_project
if project_specified_by_name?
@project = @user.projects.where(:name => project_name).first
unless @project
@project = @user.projects.build(:name => project_name)
@new_project_created = true
end
else
@project = @attributes['project_id'].present? ? @user.projects.find(@attributes['project_id']) : nil
end
@attributes[:project] = @project
end
def parse_context
if context_specified_by_name?
@context = @user.contexts.where(:name => context_name).first
unless @context
@context = @user.contexts.build(:name => context_name)
@new_context_created = true
end
else
@context = @attributes['context_id'].present? ? @user.contexts.find(@attributes['context_id']) : nil
end
@attributes[:context] = @context
end
def project_specified_by_name?
return false if @attributes['project_id'].present?
return false if project_name.blank?
return false if project_name == 'None'
true
end
def context_specified_by_name?
return false if @attributes['context_id'].present?
return false if context_name.blank?
true
end
def project_name
@attributes['project_name'].strip unless @attributes['project_name'].nil?
end
def context_name
@attributes['context_name'].strip unless @attributes['context_name'].nil?
end
end
end

View file

@ -0,0 +1,22 @@
module RecurringTodos
class WeeklyRecurringTodosBuilder < AbstractRecurringTodosBuilder
def initialize(user, attributes)
super(user, attributes)
@pattern = WeeklyRepeatPattern.new(user, @filterred_attributes)
end
def filter_attributes(attributes)
@filterred_attributes = filter_generic_attributes(attributes)
weekly_attributes = %w{weekly_selector weekly_every_x_week}
%w{monday tuesday wednesday thursday friday saturday sunday}.each{|day| weekly_attributes << "weekly_return_#{day}"}
weekly_attributes.each{|key| @filterred_attributes[key] = attributes[key] if attributes.key?(key)}
@filterred_attributes
end
end
end

View file

@ -0,0 +1,29 @@
module RecurringTodos
class WeeklyRepeatPattern < AbstractRepeatPattern
def initialize(user, attributes)
super user, attributes
end
def mapped_attributes
mapping = @attributes
mapping = map(mapping, :every_other1, 'weekly_every_x_week')
{ monday: 1, tuesday: 2, wednesday: 3, thursday: 4, friday: 5, saturday: 6, sunday: 0 }.each{|day, index| mapping = map_day(mapping, :every_day, "weekly_return_#{day}", index)}
mapping
end
def map_day(mapping, key, source_key, index)
mapping[key] ||= ' ' # avoid nil
mapping[source_key] ||= ' ' # avoid nil
mapping[key] = mapping[key][0, index] + mapping[source_key] + mapping[key][index+1, mapping[key].length]
mapping
end
end
end

View file

@ -0,0 +1,24 @@
module RecurringTodos
class YearlyRecurringTodosBuilder < AbstractRecurringTodosBuilder
def initialize(user, attributes)
super(user, attributes)
@pattern = YearlyRepeatPattern.new(user, @filterred_attributes)
end
def filter_attributes(attributes)
@filterred_attributes = filter_generic_attributes(attributes)
%w{ yearly_selector yearly_month_of_year yearly_month_of_year2
yearly_every_x_day yearly_every_xth_day yearly_day_of_week
}.each do |key|
@filterred_attributes[key] = attributes[key] if attributes.key?(key)
end
@filterred_attributes
end
end
end

View file

@ -0,0 +1,46 @@
module RecurringTodos
class YearlyRepeatPattern < AbstractRepeatPattern
def initialize(user, attributes)
super user, attributes
@selector = get_selector('yearly_selector')
end
def mapped_attributes
mapping = @attributes
mapping[:recurrence_selector] = get_recurrence_selector
mapping[:every_other2] = mapping[get_every_other2]
mapping = mapping.except('yearly_month_of_year').except('yearly_month_of_year2')
mapping = map(mapping, :every_other1, 'yearly_every_x_day')
mapping = map(mapping, :every_other3, 'yearly_every_xth_day')
mapping = map(mapping, :every_count, 'yearly_day_of_week')
mapping
end
private
def get_recurrence_selector
@selector=='yearly_every_x_day' ? 0 : 1
end
def get_every_other2
case get_recurrence_selector
when 0
'yearly_month_of_year'
when 1
'yearly_month_of_year2'
end
end
def valid_selector?(selector)
%w{yearly_every_x_day yearly_every_xth_day}.include?(selector)
end
end
end

View file

@ -1,5 +1,6 @@
class TodoFromRecurringTodo
attr_reader :user, :recurring_todo, :todo
def initialize(user, recurring_todo)
@user = user
@recurring_todo = recurring_todo

View file

@ -62,6 +62,52 @@ class RecurringTodosControllerTest < ActionController::TestCase
assert_equal orig_todo_count+1, Todo.count
end
def test_new_recurring_todo_handles_attribs_outside_rec_todo
login_as(:admin_user)
# check new rec todo is not there
assert_nil RecurringTodo.where(:description => "new recurring pattern").first
put :create,
"context_name"=>"library",
"project_name"=>"Build a working time machine",
"recurring_todo" =>
{
"daily_every_x_days"=>"1",
"daily_selector"=>"daily_every_x_day",
"description"=>"new recurring pattern",
"end_date" => "31/08/2010",
"ends_on" => "ends_on_end_date",
"monthly_day_of_week" => "1",
"monthly_every_x_day" => "18",
"monthly_every_x_month2" => "1",
"monthly_every_x_month" => "1",
"monthly_every_xth_day"=>"1",
"monthly_selector"=>"monthly_every_x_day",
"notes"=>"with some notes",
"number_of_occurences" => "",
"recurring_period"=>"yearly",
"recurring_show_days_before"=>"10",
"recurring_target"=>"due_date",
"recurring_show_always" => "1",
"start_from"=>"18/08/2008",
"weekly_every_x_week"=>"1",
"weekly_return_monday"=>"m",
"yearly_day_of_week"=>"1",
"yearly_every_x_day"=>"8",
"yearly_every_xth_day"=>"1",
"yearly_month_of_year2"=>"8",
"yearly_month_of_year"=>"6",
"yearly_selector"=>"yearly_every_x_day"
},
"tag_list"=>"one, two, three, four", :format => :js
new_rec_todo = RecurringTodo.where(:description => "new recurring pattern").first
assert_not_nil new_rec_todo
end
def test_recurring_todo_toggle_check
# the test fixtures did add recurring_todos but not the corresponding todos,
# so we check complete and uncheck to force creation of a todo from the

View file

@ -0,0 +1,122 @@
require_relative '../../test_helper'
module RecurringTodos
class AbstractRecurringTodosBuilderTest < ActiveSupport::TestCase
fixtures :users
def setup
@admin = users(:admin_user)
end
def test_filter_attributes_should_throw_exception
attributes = {
'recurring_period' => "daily",
'description' => "test",
'tag_list' => "tag, this, that",
'context_name' => "my new context",
'daily_selector' => 'daily_every_work_day',
'target' => 'due_date',
'show_always' => true,
'start_from' => '01/01/01',
'ends_on' => 'no_end_date'
}
assert_raise(Exception, "should have exception since we are using abstract builder") do
builder = AbstractRecurringTodosBuilder.new(@admin, attributes)
end
end
def test_tags_should_be_filled_or_empty_string
# given attributes with filled tag_list
attributes = {
'recurring_period' => 'daily',
'daily_selector' => 'daily_every_work_day',
'tag_list' => "tag, this, that"
}
builder = RecurringTodosBuilder.new(@admin, attributes)
assert_equal "tag, this, that", builder.attributes[:tag_list]
# given attributes without tag_list
attributes = {
'recurring_period' => 'daily',
'daily_selector' => 'daily_every_work_day',
}
builder = RecurringTodosBuilder.new(@admin, attributes)
assert_equal "", builder.attributes[:tag_list]
# given attributes with nil tag_list
attributes = {
'recurring_period' => 'daily',
'daily_selector' => 'daily_every_work_day',
'tag_list' => nil
}
builder = RecurringTodosBuilder.new(@admin, attributes)
assert_equal "", builder.attributes[:tag_list]
# given attributes with empty tag_list ==> should be stripped
attributes = {
'recurring_period' => 'daily',
'daily_selector' => 'daily_every_work_day',
'tag_list' => " "
}
builder = RecurringTodosBuilder.new(@admin, attributes)
assert_equal "", builder.attributes[:tag_list]
end
def test_tags_should_be_saved
attributes = {
'recurring_period' => "daily",
'description' => "test",
'tag_list' => "tag, this, that",
'context_name' => "my new context",
'daily_selector' => 'daily_every_work_day',
'recurring_target' => 'show_from_date',
'show_always' => true,
'start_from' => '01/01/01',
'ends_on' => 'no_end_date'
}
builder = RecurringTodosBuilder.new(@admin, attributes)
assert builder.save, "it should be saved"
assert_equal "tag, that, this", builder.saved_recurring_todo.tag_list, "tags should be saved"
attributes['tag_list'] = '' # clear tag_list
builder = RecurringTodosBuilder.new(@admin, attributes)
assert !builder.tag_list.present?, "tag list should not be present"
assert builder.save, "it should be saved"
assert_equal "", builder.saved_recurring_todo.tag_list, "tag list should be empty"
end
def test_saved_should_raise_exception_on_validation_errors
attributes = {
'recurring_period' => "daily",
'description' => "test",
'tag_list' => "tag, this, that",
'context_name' => "my new context",
'daily_selector' => 'daily_every_work_day',
'recurring_target' => 'due_date',
'show_always' => true,
'start_from' => '01/01/01',
'ends_on' => 'no_end_date_error' # invalid end_on value
}
# creating builder should not raise exception
builder = RecurringTodosBuilder.new(@admin, attributes)
builder.build
assert !builder.recurring_todo.valid?, "model should have validation errors"
assert !builder.save, "should not be able to save because of validation errors"
assert_raise(Exception, "should have exception since there is no saved recurring todo"){ builder.saved_recurring_todo }
end
end
end

View file

@ -0,0 +1,46 @@
require_relative '../../test_helper'
module RecurringTodos
class AbstractRepeatPatternTest < ActiveSupport::TestCase
fixtures :users
class TestRepeatPattern < AbstractRepeatPattern
def valid_selector?(selector)
true
end
end
def setup
@admin = users(:admin_user)
end
def test_map_removes_mapped_key
attributes = { :source => "value"}
arp = AbstractRepeatPattern.new(@admin, attributes)
attributes = arp.map(attributes, :target, :source)
assert_equal "value", attributes[:target]
assert_nil attributes[:source]
assert !attributes.key?(:source)
end
def test_get_selector_removes_selector_from_hash
attributes = { :selector => "weekly" }
arp = TestRepeatPattern.new(@admin, attributes)
assert "weekly", arp.get_selector(:selector)
assert !arp.attributes.key?(:selector)
end
def test_get_selector_raises_exception_when_missing_selector
attributes = { }
arp = TestRepeatPattern.new(@admin, attributes)
assert_raise(Exception, "should raise exception when recurrence selector is missing"){ arp.get_selector(:selector) }
end
end
end

View file

@ -0,0 +1,35 @@
require_relative '../../test_helper'
module RecurringTodos
class DailyRecurringTodosBuilderTest < ActiveSupport::TestCase
fixtures :users
def setup
@admin = users(:admin_user)
end
def test_pattern_is_daily
object = RecurringTodosBuilder.new(@admin, { 'recurring_period' => 'daily', 'daily_selector' => 'daily_every_x_day' })
assert object.builder.is_a? DailyRecurringTodosBuilder
end
def test_filter_non_daily_attributes
attributes = {
'recurring_period' => 'daily',
'description' => 'a repeating todo', # generic
'daily_selector' => 'daily_every_x_day', # daily specific
'bla_bla' => 'go away' # irrelevant for daily
}
result = RecurringTodosBuilder.new(@admin, attributes).attributes
assert_nil result['bla_bla'], "bla_bla should be filtered"
assert_nil result[:bla_bla], "bla_bla should be filtered"
assert_equal false, result[:only_work_days], "daily attributes should be preserved"
assert_equal "a repeating todo", result[:description], "description should be preserved"
end
end
end

View file

@ -0,0 +1,58 @@
require_relative '../../test_helper'
module RecurringTodos
class DailyRepeatPatternTest < ActiveSupport::TestCase
fixtures :users
def setup
@admin = users(:admin_user)
end
def test_valid_selector
attributes = {
'recurring_period' => 'daily'
}
# should not raise
%w{daily_every_x_day daily_every_work_day}.each do |selector|
attributes['daily_selector'] = selector
DailyRepeatPattern.new(@admin, attributes)
end
# should raise
attributes = {
'recurring_period' => 'daily',
'daily_selector' => 'wrong value'
}
# should raise
assert_raise(Exception, "should have exception since daily_selector has wrong value"){ DailyRepeatPattern.new(@admin, attributes) }
end
def test_mapping_of_attributes
attributes = {
'recurring_period' => 'daily',
'description' => 'a repeating todo', # generic
'daily_selector' => 'daily_every_x_day', # daily specific --> mapped to only_work_days=false
'daily_every_x_days' => '5' # mapped to every_other1
}
pattern = DailyRepeatPattern.new(@admin, attributes)
assert_equal '5', pattern.mapped_attributes[:every_other1], "every_other1 should be set to daily_every_x_days"
assert_equal false, pattern.mapped_attributes[:only_work_days], "only_work_days should be set to false for daily_every_x_day"
attributes = {
'recurring_period' => 'daily',
'description' => 'a repeating todo', # generic
'daily_selector' => 'daily_every_work_day', # daily specific --> mapped to only_work_days=true
}
pattern = DailyRepeatPattern.new(@admin, attributes)
assert_equal true, pattern.mapped_attributes[:only_work_days]
end
end
end

View file

@ -0,0 +1,35 @@
require_relative '../../test_helper'
module RecurringTodos
class MonthlyRecurringTodosBuilderTest < ActiveSupport::TestCase
fixtures :users
def setup
@admin = users(:admin_user)
end
def test_pattern_is_monthly
object = RecurringTodosBuilder.new(@admin, { 'recurring_period' => 'monthly', 'monthly_selector' => 'monthly_every_x_day' })
assert object.builder.is_a?(MonthlyRecurringTodosBuilder), "Builder should be of type MonthlyRecurringTodosBuilder"
end
def test_filter_non_daily_attributes
attributes = {
'recurring_period' => 'monthly',
'description' => 'a repeating todo', # generic
'monthly_selector' => 'monthly_every_x_day', # monthly specific
'monthly_every_x_day' => 5, # should be preserved as :every_other1
'bla_bla' => 'go away' # irrelevant for daily
}
result = RecurringTodosBuilder.new(@admin, attributes).attributes
assert_nil result['bla_bla'], "bla_bla should be filtered"
assert_nil result[:bla_bla], "bla_bla should be filtered"
assert_equal 5, result[:every_other1], "should be preserved"
end
end
end

View file

@ -0,0 +1,74 @@
require_relative '../../test_helper'
module RecurringTodos
class MonthlyRepeatPatternTest < ActiveSupport::TestCase
fixtures :users
def setup
@admin = users(:admin_user)
end
def test_valid_selector
attributes = {
'recurring_period' => 'monthly'
}
# should not raise
%w{monthly_every_x_day monthly_every_xth_day}.each do |selector|
attributes['monthly_selector'] = selector
MonthlyRepeatPattern.new(@admin, attributes)
end
# should raise
attributes = {
'recurring_period' => 'monthly',
'monthly_selector' => 'wrong value'
}
# should raise
assert_raise(Exception, "should have exception since monthly_selector has wrong value"){ MonthlyRepeatPattern.new(@admin, attributes) }
end
def test_mapping_of_attributes
attributes = {
'recurring_period' => 'monthly',
'description' => 'a repeating todo', # generic
'monthly_selector' => 'monthly_every_x_day', # monthly specific
'monthly_every_x_day' => '5', # mapped to :every_other1
'monthly_every_xth_day' => '7', # mapped to :every_other3
'monthly_day_of_week' => 3, # mapped to :every_count
'monthly_every_x_month' => '10', # mapped to :every_other2
'monthly_every_x_month2' => '20' # not mapped
}
pattern = MonthlyRepeatPattern.new(@admin, attributes)
assert_equal 0, pattern.mapped_attributes[:recurrence_selector], "selector should be 0 for monthly_every_x_day"
assert_equal '5', pattern.mapped_attributes[:every_other1], "every_other1 should be set to monthly_every_x_days"
assert_equal '10', pattern.mapped_attributes[:every_other2], "every_other2 should be set to monthly_every_x_month when selector is monthly_every_x_day (=0)"
assert_equal '7', pattern.mapped_attributes[:every_other3], "every_other3 should be set to monthly_every_xth_day"
assert_equal 3, pattern.mapped_attributes[:every_count], "every_count should be set to monthly_day_of_week"
pattern.build_recurring_todo
assert pattern.every_x_day?, "every_x_day? should say true for selector monthly_every_x_day"
attributes = {
'recurring_period' => 'monthly',
'description' => 'a repeating todo', # generic
'monthly_selector' => 'monthly_every_xth_day', # monthly specific
'monthly_every_x_day' => '5', # mapped to :every_other1
'monthly_every_x_month' => '10', # not mapped
'monthly_every_x_month2' => '20' # mapped to :every_other2
}
pattern = MonthlyRepeatPattern.new(@admin, attributes)
assert_equal 1, pattern.mapped_attributes[:recurrence_selector], "selector should be 1 for monthly_every_xth_day"
assert_equal '20', pattern.mapped_attributes[:every_other2], "every_other2 should be set to monthly_every_x_month2 when selector is monthly_every_xth_day (=0)"
pattern.build_recurring_todo
assert pattern.every_xth_day?, "every_xth_day? should say true for selector monthly_every_xth_day"
end
end
end

View file

@ -0,0 +1,122 @@
require_relative '../../test_helper'
module RecurringTodos
class RecurringTodosBuilderTest < ActiveSupport::TestCase
fixtures :users
def setup
@admin = users(:admin_user)
end
def test_create_builder_needs_selector
assert_raise(Exception){ builder = RecurringTodosBuilder.new(@admin, {}) }
end
def test_create_builder_uses_selector
builder = RecurringTodosBuilder.new(@admin, {'recurring_period' => "daily", 'daily_selector' => 'daily_every_work_day'}).builder
assert builder.is_a?(DailyRecurringTodosBuilder)
builder = RecurringTodosBuilder.new(@admin, {'recurring_period' => "weekly"}).builder
assert builder.is_a?(WeeklyRecurringTodosBuilder)
builder = RecurringTodosBuilder.new(@admin, {'recurring_period' => "monthly", 'monthly_selector' => 'monthly_every_x_day'}).builder
assert builder.is_a?(MonthlyRecurringTodosBuilder)
builder = RecurringTodosBuilder.new(@admin, {'recurring_period' => "yearly", 'yearly_selector' => 'yearly_every_x_day'}).builder
assert builder.is_a?(YearlyRecurringTodosBuilder)
end
def test_dates_are_parsed
builder = RecurringTodosBuilder.new(@admin, {
'recurring_period' => "daily",
'daily_selector' => 'daily_every_work_day',
'start_from' => "01/01/01",
'end_date' => '05/05/05'
})
assert builder.attributes[:start_from].is_a?(ActiveSupport::TimeWithZone), "Dates should be parsed to ActiveSupport::TimeWithZone class"
assert builder.attributes[:end_date].is_a?(ActiveSupport::TimeWithZone), "Dates should be parsed to ActiveSupport::TimeWithZone class"
end
def test_exisisting_project_is_used
# test by project_name
builder = RecurringTodosBuilder.new(@admin, {
'recurring_period' => "daily",
'project_name' => @admin.projects.first.name,
'daily_selector' => 'daily_every_work_day'})
assert_equal @admin.projects.first, builder.project
# test by project_id
builder = RecurringTodosBuilder.new(@admin, {
'recurring_period' => "daily",
'daily_selector' => 'daily_every_work_day',
'project_id' => @admin.projects.first.id})
assert_equal @admin.projects.first, builder.project
end
def test_not_exisisting_project_is_created
builder = RecurringTodosBuilder.new(@admin, {
'recurring_period' => "daily",
'project_name' => "my new project",
'daily_selector' => 'daily_every_work_day',
'recurring_target' => 'due_date'})
assert_equal "my new project", builder.project.name, "project should exist"
assert !builder.project.persisted?, "new project should not be persisted before save"
builder.save
assert builder.project.persisted?, "new project should be persisted after save"
end
def test_exisisting_context_is_used
builder = RecurringTodosBuilder.new(@admin, {
'recurring_period' => "daily",
'context_name' => @admin.contexts.first.name,
'daily_selector' => 'daily_every_work_day'})
assert_equal @admin.contexts.first, builder.context
builder = RecurringTodosBuilder.new(@admin, {
'recurring_period' => "daily",
'daily_selector' => 'daily_every_work_day',
'context_id' => @admin.contexts.first.id})
assert_equal @admin.contexts.first, builder.context
end
def test_not_exisisting_context_is_created
builder = RecurringTodosBuilder.new(@admin, {
'recurring_period' => "daily",
'context_name' => "my new context",
'daily_selector' => 'daily_every_work_day',
'recurring_target' => 'due_date'})
assert_equal "my new context", builder.context.name, "context should exist"
assert !builder.context.persisted?, "new context should not be persisted before save"
builder.save
assert builder.context.persisted?, "new context should be persisted after save"
end
def test_project_is_optional
builder = RecurringTodosBuilder.new(@admin, {
'recurring_period' => "daily",
'description' => "test",
'context_name' => "my new context",
'daily_selector' => 'daily_every_work_day',
'recurring_target' => 'show_from_date',
'show_always' => true,
'start_from' => '01/01/01',
'ends_on' => 'no_end_date'})
assert_nil builder.project, "project should not exist"
builder.save
assert_nil builder.saved_recurring_todo.project
end
end
end

View file

@ -0,0 +1,35 @@
require_relative '../../test_helper'
module RecurringTodos
class WeeklyRecurringTodosBuilderTest < ActiveSupport::TestCase
fixtures :users
def setup
@admin = users(:admin_user)
end
def test_pattern_is_weekly
object = RecurringTodosBuilder.new(@admin, { 'recurring_period' => 'weekly' })
assert object.builder.is_a? WeeklyRecurringTodosBuilder
end
def test_filter_non_daily_attributes
attributes = {
'recurring_period' => 'weekly',
'description' => 'a repeating todo', # generic
'weekly_return_monday' => 'm', # weekly specific
'bla_bla' => 'go away' # irrelevant
}
result = RecurringTodosBuilder.new(@admin, attributes).attributes
assert_nil result['bla_bla'], "bla_bla should be filtered"
assert_nil result[:bla_bla], "bla_bla should be filtered"
assert_equal ' m ', result[:every_day], "weekly attributes should be preserved"
assert_equal "a repeating todo", result[:description], "description should be preserved"
end
end
end

View file

@ -0,0 +1,52 @@
require_relative '../../test_helper'
module RecurringTodos
class WeeklyRepeatPatternTest < ActiveSupport::TestCase
fixtures :users
def setup
@admin = users(:admin_user)
end
def test_mapping_of_attributes
attributes = {
'recurring_period' => 'weekly',
'description' => 'a repeating todo', # generic
'weekly_every_x_week' => '5', # mapped to every_other1
'weekly_return_monday' => 'm'
}
pattern = WeeklyRepeatPattern.new(@admin, attributes)
assert_equal '5', pattern.mapped_attributes[:every_other1], "every_other1 should be set to weekly_every_x_week"
assert_equal ' m ', pattern.mapped_attributes[:every_day], "weekly_return_<weekday> should be mapped to :every_day in format 'smtwtfs'"
end
def test_map_day
attributes = {
'recurring_period' => 'weekly',
'description' => 'a repeating todo', # generic
'weekly_every_x_week' => '5' # mapped to every_other1
}
pattern = WeeklyRepeatPattern.new(@admin, attributes)
assert_equal ' ', pattern.mapped_attributes[:every_day], "all days should be empty in :every_day"
# add all days
{ sunday: 's', monday: 'm', tuesday: 't', wednesday: 'w', thursday: 't', friday: 'f', saturday: 's' }.each do |day, short|
attributes["weekly_return_#{day}"] = short
end
pattern = WeeklyRepeatPattern.new(@admin, attributes)
assert_equal 'smtwtfs', pattern.mapped_attributes[:every_day], "all days should be filled in :every_day"
# remove wednesday
attributes = attributes.except('weekly_return_wednesday')
pattern = WeeklyRepeatPattern.new(@admin, attributes)
assert_equal 'smt tfs', pattern.mapped_attributes[:every_day], "only wednesday should be empty in :every_day"
end
end
end

View file

@ -0,0 +1,36 @@
require_relative '../../test_helper'
module RecurringTodos
class YearlyRecurringTodosBuilderTest < ActiveSupport::TestCase
fixtures :users
def setup
@admin = users(:admin_user)
end
def test_pattern_is_yearly
object = RecurringTodosBuilder.new(@admin, { 'recurring_period' => 'yearly', 'yearly_selector' => 'yearly_every_x_day' })
assert object.builder.is_a? YearlyRecurringTodosBuilder
end
def test_filter_non_daily_attributes
attributes = {
'recurring_period' => 'yearly',
'description' => 'a repeating todo', # generic
'yearly_selector' => 'yearly_every_x_day', # daily specific
'yearly_month_of_year' => '1', # mapped to evert_other2 because yearly_selector is yearly_every_x_day
'bla_bla' => 'go away' # irrelevant for daily
}
result = RecurringTodosBuilder.new(@admin, attributes).attributes
assert_nil result['bla_bla'], "bla_bla should be filtered"
assert_nil result[:bla_bla], "bla_bla should be filtered"
assert_equal '1', result[:every_other2], "yearly attributes should be preserved"
assert_equal "a repeating todo", result[:description], "description should be preserved"
end
end
end

View file

@ -0,0 +1,66 @@
require_relative '../../test_helper'
module RecurringTodos
class YearlyRepeatPatternTest < ActiveSupport::TestCase
fixtures :users
def setup
@admin = users(:admin_user)
end
def test_valid_selector
attributes = {
'recurring_period' => 'yearly'
}
# should not raise
%w{yearly_every_x_day yearly_every_xth_day}.each do |selector|
attributes['yearly_selector'] = selector
YearlyRepeatPattern.new(@admin, attributes)
end
# should raise
attributes = {
'recurring_period' => 'yearly',
'yearly_selector' => 'wrong value'
}
# should raise
assert_raise(Exception, "should have exception since yearly_selector has wrong value"){ YearlyRepeatPattern.new(@admin, attributes) }
end
def test_mapping_of_attributes
attributes = {
'recurring_period' => 'yearly',
'description' => 'a repeating todo', # generic
'yearly_selector' => 'yearly_every_x_day', # yearly specific
'yearly_every_x_day' => '5', # mapped to every_other1
'yearly_every_xth_day' => '7', # mapped to every_other3
'yearly_day_of_week' => '3', # mapped to every_count
'yearly_month_of_year' => '1', # mapped to evert_other2 because yearly_selector is yearly_every_x_day
'yearly_month_of_year2' => '2' # ignored because yearly_selector is yearly_every_x_day
}
pattern = YearlyRepeatPattern.new(@admin, attributes)
assert_equal '5', pattern.mapped_attributes[:every_other1], "every_other1 should be set to yearly_every_x_day"
assert_equal '1', pattern.mapped_attributes[:every_other2], "every_other2 should be set to yearly_month_of_year because selector is yearly_every_x_day"
assert_equal '7', pattern.mapped_attributes[:every_other3], "every_other3 should be set to yearly_every_xth_day"
assert_equal '3', pattern.mapped_attributes[:every_count], "every_count should be set to yearly_day_of_week"
attributes = {
'recurring_period' => 'yearly',
'description' => 'a repeating todo', # generic
'yearly_selector' => 'yearly_every_xth_day', # daily specific --> mapped to only_work_days=false
'yearly_month_of_year' => '1', # ignored because yearly_selector is yearly_every_xth_day
'yearly_month_of_year2' => '2' # mapped to evert_other2 because yearly_selector is yearly_every_xth_day
}
pattern = YearlyRepeatPattern.new(@admin, attributes)
assert_equal '2', pattern.mapped_attributes[:every_other2], "every_other2 should be set to yearly_month_of_year2 because selector is yearly_every_xth_day"
end
end
end