refactored edit-position to MVP, wrote tests, completely removed old validation stuff

This commit is contained in:
mgroves 2011-03-19 23:21:12 -04:00
parent 9a0d711294
commit efdf271f1a
16 changed files with 476 additions and 266 deletions

View file

@ -8,12 +8,12 @@ namespace MonoStockPortfolio.Tests.Framework
{
public class ValidationTests
{
static NewFormValidator _validator;
static FormValidator _validator;
static IEnumerable<string> _errors;
Establish context = () =>
{
_validator = new NewFormValidator();
_validator = new FormValidator();
};
Because of = () =>

View file

@ -64,6 +64,7 @@
<ItemGroup>
<Compile Include="Framework\ValidationTests.cs" />
<Compile Include="Presenters\EditPortfolioTests.cs" />
<Compile Include="Presenters\EditPositionTests.cs" />
<Compile Include="Presenters\MainPresenterTests.cs" />
<Compile Include="Presenters\PortfolioPresenterTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

View file

@ -15,23 +15,23 @@ namespace MonoStockPortfolio.Tests.Presenters
protected static IEditPortfolioView _mockEditPortfolioView;
Establish context = () =>
{
_mockPortfolioRepository = Mock.Create<IPortfolioRepository>();
Mock.Arrange(() => _mockPortfolioRepository.GetPortfolioById(999)).Returns(
new Portfolio(999) { Name = "Testing Portfolio!" });
{
_mockPortfolioRepository = Mock.Create<IPortfolioRepository>();
Mock.Arrange(() => _mockPortfolioRepository.GetPortfolioById(999)).Returns(
new Portfolio(999) {Name = "Testing Portfolio!"});
_mockEditPortfolioView = Mock.Create<IEditPortfolioView>();
_mockEditPortfolioView = Mock.Create<IEditPortfolioView>();
_presenter = new EditPortfolioPresenter(_mockPortfolioRepository);
};
_presenter = new EditPortfolioPresenter(_mockPortfolioRepository);
};
}
public class When_initializing_the_edit_portfolio_presenter_with_no_id : EditPortfolioTests
{
Because of = () =>
{
_presenter.Initialize(_mockEditPortfolioView, null);
};
{
_presenter.Initialize(_mockEditPortfolioView, null);
};
It should_set_the_title_to_Add_New_Portfolio = () =>
Mock.Assert(() => _mockEditPortfolioView.SetTitle("Add New Portfolio"), Occurs.Exactly(1));
@ -42,9 +42,9 @@ namespace MonoStockPortfolio.Tests.Presenters
public class When_initializing_the_edit_portfolio_presenter_with_an_id : EditPortfolioTests
{
Because of = () =>
{
_presenter.Initialize(_mockEditPortfolioView, 999);
};
{
_presenter.Initialize(_mockEditPortfolioView, 999);
};
It should_set_the_title_to_Edit_Portfolio = () =>
Mock.Assert(() => _mockEditPortfolioView.SetTitle("Edit Portfolio"), Occurs.Exactly(1));
@ -55,14 +55,14 @@ namespace MonoStockPortfolio.Tests.Presenters
public class When_the_user_wants_to_save_a_valid_portfolio : EditPortfolioTests
{
Establish context = () =>
{
_presenter.Initialize(_mockEditPortfolioView, null);
};
{
_presenter.Initialize(_mockEditPortfolioView, null);
};
Because of = () =>
{
_presenter.SavePortfolio(new Portfolio(999) { Name = "Whatever Portfolio" });
};
{
_presenter.SavePortfolio(new Portfolio(999) {Name = "Whatever Portfolio"});
};
It should_use_the_repository_to_save_the_portfolio = () =>
Mock.Assert(() => _mockPortfolioRepository.SavePortfolio(Arg.Matches<Portfolio>(x => x.ID == 999 && x.Name == "Whatever Portfolio")), Occurs.Exactly(1));
@ -75,14 +75,14 @@ namespace MonoStockPortfolio.Tests.Presenters
public class When_the_user_tries_to_save_a_new_portfolio_with_a_blank_name : EditPortfolioTests
{
Establish context = () =>
{
_presenter.Initialize(_mockEditPortfolioView);
};
{
_presenter.Initialize(_mockEditPortfolioView);
};
Because of = () =>
{
_presenter.SavePortfolio(new Portfolio { Name = "" });
};
{
_presenter.SavePortfolio(new Portfolio {Name = ""});
};
It should_return_1_validation_error = () =>
Mock.Assert(() => _mockEditPortfolioView.ShowValidationErrors(Arg.Matches<IEnumerable<string>>(x => x.Count() == 1)), Occurs.Exactly(1));
@ -93,16 +93,16 @@ namespace MonoStockPortfolio.Tests.Presenters
public class When_the_user_tries_to_save_a_portfolio_with_a_duplicated_name : EditPortfolioTests
{
Establish context = () =>
{
_presenter.Initialize(_mockEditPortfolioView);
};
{
_presenter.Initialize(_mockEditPortfolioView);
};
Because of = () =>
{
Mock.Arrange(() => _mockPortfolioRepository.GetPortfolioByName(Arg.AnyString)).Returns(
new Portfolio(998) {Name = "Some Name"});
_presenter.SavePortfolio(new Portfolio { Name = "Some Name" });
};
{
Mock.Arrange(() => _mockPortfolioRepository.GetPortfolioByName(Arg.AnyString)).Returns(
new Portfolio(998) {Name = "Some Name"});
_presenter.SavePortfolio(new Portfolio {Name = "Some Name"});
};
It should_return_1_validation_error = () =>
Mock.Assert(() => _mockEditPortfolioView.ShowValidationErrors(Arg.Matches<IEnumerable<string>>(x => x.Count() == 1)), Occurs.Exactly(1));

View file

@ -0,0 +1,164 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Machine.Specifications;
using MonoStockPortfolio.Activites.EditPositionScreen;
using MonoStockPortfolio.Core.PortfolioRepositories;
using MonoStockPortfolio.Core.StockData;
using MonoStockPortfolio.Entities;
using Telerik.JustMock;
namespace MonoStockPortfolio.Tests.Presenters
{
public class EditPositionTests
{
protected static EditPositionPresenter _presenter;
protected static IPortfolioRepository _mockPortfolioRepository;
protected static IStockDataProvider _mockStockService;
protected static IEditPositionView _mockView;
Establish context = () =>
{
_mockPortfolioRepository = Mock.Create<IPortfolioRepository>();
_mockStockService = Mock.Create<IStockDataProvider>();
_mockView = Mock.Create<IEditPositionView>();
_presenter = new EditPositionPresenter(_mockPortfolioRepository, _mockStockService);
};
}
public class When_initializing_the_edit_position_presenter_with_no_id : EditPositionTests
{
Because of = () =>
{
_presenter.Initialize(_mockView, 1);
};
It should_set_the_title_to_Add_Position = () =>
Mock.Assert(() => _mockView.SetTitle("Add Position"), Occurs.Exactly(1));
It shouldnt_prepopulate_the_form_with_anything = () =>
Mock.Assert(() => _mockView.PopulateForm(Arg.IsAny<Position>()),Occurs.Never());
}
public class When_initializing_the_edit_position_presenter_with_an_id : EditPositionTests
{
Establish context = () =>
{
var fakePosition = new Position(999) { ContainingPortfolioID = 1, PricePerShare = 5.99M, Shares = 50M, Ticker = "FAKE" };
Mock.Arrange(() => _mockPortfolioRepository.GetPositionById(999)).Returns(fakePosition);
};
Because of = () =>
{
_presenter.Initialize(_mockView, 1, 999);
};
It should_set_the_title_to_Edit_Position = () =>
Mock.Assert(() => _mockView.SetTitle("Edit Position"), Occurs.Exactly(1));
It should_prepopulate_the_PricePerShare_on_the_form = () =>
Mock.Assert(() => _mockView.PopulateForm(Arg.Matches<Position>(p => p.PricePerShare == 5.99M)), Occurs.Exactly(1));
It should_prepopulate_the_Shares_on_the_form = () =>
Mock.Assert(() => _mockView.PopulateForm(Arg.Matches<Position>(p => p.Shares == 50M)), Occurs.Exactly(1));
It should_prepopulate_the_Ticker_on_the_form = () =>
Mock.Assert(() => _mockView.PopulateForm(Arg.Matches<Position>(p => p.Ticker == "FAKE")), Occurs.Exactly(1));
}
public class When_the_user_wants_to_save_a_valid_position : EditPositionTests
{
Establish context = () =>
{
_presenter.Initialize(_mockView, 1);
Mock.Arrange(() => _mockStockService.IsValidTicker(Arg.AnyString)).Returns(true);
};
Because of = () =>
{
var fakeInputModel = new PositionInputModel {PriceText = "2.34", SharesText = "671", TickerText = "LOL"};
_presenter.Save(fakeInputModel);
};
It should_save_a_position_with_the_portfolio_repository = () =>
Mock.Assert(() => _mockPortfolioRepository.SavePosition(Arg.IsAny<Position>()), Occurs.Exactly(1));
It should_save_a_position_with_the_correct_Price = () =>
Mock.Assert(() => _mockPortfolioRepository.SavePosition(Arg.Matches<Position>(p => p.PricePerShare == 2.34M)), Occurs.Exactly(1));
It should_save_a_position_with_the_correct_Shares = () =>
Mock.Assert(() => _mockPortfolioRepository.SavePosition(Arg.Matches<Position>(p => p.Shares == 671M)), Occurs.Exactly(1));
It should_save_a_position_with_the_correct_Ticker = () =>
Mock.Assert(() => _mockPortfolioRepository.SavePosition(Arg.Matches<Position>(p => p.Ticker == "LOL")), Occurs.Exactly(1));
It should_save_a_position_with_the_correct_Containing_Portfolio_ID = () =>
Mock.Assert(() => _mockPortfolioRepository.SavePosition(Arg.Matches<Position>(p => p.ContainingPortfolioID == 1)), Occurs.Exactly(1));
It should_tell_the_view_to_go_back_to_the_main_activity = () =>
Mock.Assert(() => _mockView.GoBackToMainActivity(), Occurs.Exactly(1));
}
public class When_the_user_wants_to_save_an_invalid_position : EditPositionTests
{
Establish context = () =>
{
_presenter.Initialize(_mockView, 1);
Mock.Arrange(() => _mockStockService.IsValidTicker(Arg.AnyString)).Returns(false);
};
Because of = () =>
{
var fakeInputModel = new PositionInputModel {PriceText = "cows", SharesText = "WALRUS!!", TickerText = "fail"};
_presenter.Save(fakeInputModel);
};
It should_not_try_to_save_the_portfolio = () =>
Mock.Assert(() => _mockPortfolioRepository.SavePosition(Arg.IsAny<Position>()), Occurs.Never());
It should_send_the_validation_errors_to_the_view = () =>
Mock.Assert(() => _mockView.ShowErrorMessages(Arg.IsAny<IList<string>>()), Occurs.Exactly(1));
It should_send_an_invalid_ticker_error_to_the_view = () =>
MockAssertPositionMatches(x => x.Any(p => p == "Invalid Ticker Name"));
It should_send_an_invalid_shares_number_error_to_the_view = () =>
MockAssertPositionMatches(x => x.Any(p => p == "Please enter a valid, positive number of shares"));
It should_send_an_invalid_price_per_share_error_to_the_view = () =>
MockAssertPositionMatches(x => x.Any(p => p == "Please enter a valid, positive price per share"));
It should_not_tell_the_view_to_go_back_to_the_main_activity = () =>
Mock.Assert(() => _mockView.GoBackToMainActivity(), Occurs.Never());
private static void MockAssertPositionMatches(Expression<Predicate<IList<string>>> match)
{
Mock.Assert(() => _mockView.ShowErrorMessages(Arg.Matches(match)), Occurs.Exactly(1));
}
}
public class When_the_user_wants_to_save_an_invalid_position_with_blank_fields : EditPositionTests
{
Establish context = () =>
{
_presenter.Initialize(_mockView, 1);
Mock.Arrange(() => _mockStockService.IsValidTicker(Arg.AnyString)).Returns(false);
};
Because of = () =>
{
var fakeInputModel = new PositionInputModel { PriceText = "", SharesText = "", TickerText = "" };
_presenter.Save(fakeInputModel);
};
It should_not_try_to_save_the_portfolio = () =>
Mock.Assert(() => _mockPortfolioRepository.SavePosition(Arg.IsAny<Position>()), Occurs.Never());
It should_send_the_validation_errors_to_the_view = () =>
Mock.Assert(() => _mockView.ShowErrorMessages(Arg.IsAny<IList<string>>()), Occurs.Exactly(1));
It should_send_an_invalid_ticker_error_to_the_view = () =>
MockPositionMatches(x => x.Any(p => p == "Please enter a ticker"));
It should_send_an_invalid_shares_number_error_to_the_view = () =>
MockPositionMatches(x => x.Any(p => p == "Please enter a valid, positive number of shares"));
It should_send_an_invalid_price_per_share_error_to_the_view = () =>
MockPositionMatches(x => x.Any(p => p == "Please enter a valid, positive price per share"));
It should_not_tell_the_view_to_go_back_to_the_main_activity = () =>
Mock.Assert(() => _mockView.GoBackToMainActivity(), Occurs.Never());
private static void MockPositionMatches(Expression<Predicate<IList<string>>> match)
{
Mock.Assert(() => _mockView.ShowErrorMessages(Arg.Matches(match)), Occurs.Exactly(1));
}
}
}

View file

@ -46,9 +46,9 @@ namespace MonoStockPortfolio.Activites.EditPortfolioScreen
private IEnumerable<string> Validate(Portfolio portfolioToSave)
{
var validator = new NewFormValidator();
var validator = new FormValidator();
validator.AddRequired(() => portfolioToSave.Name, "Please enter a portfolio name");
validator.AddValidation(() => portfolioToSave.Name, () => IsDuplicateName(portfolioToSave));
validator.AddValidation(() => IsDuplicateName(portfolioToSave));
return validator.Apply().ToList();
}

View file

@ -1,140 +0,0 @@
using System;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Widget;
using MonoStockPortfolio.Core.PortfolioRepositories;
using MonoStockPortfolio.Core.StockData;
using MonoStockPortfolio.Entities;
using MonoStockPortfolio.Framework;
namespace MonoStockPortfolio.Activites
{
[Activity(Label = "Add Position", MainLauncher = false, Name = "monostockportfolio.activites.EditPositionActivity")]
public class EditPositionActivity : Activity
{
[IoC] private IPortfolioRepository _repo;
[IoC] private IStockDataProvider _svc;
[LazyView(Resource.Id.addPositionTicker)] protected EditText TickerTextBox;
[LazyView(Resource.Id.addPositionPrice)] protected EditText PriceTextBox;
[LazyView(Resource.Id.addPositionShares)] protected EditText SharesTextBox;
[LazyView(Resource.Id.addPositionSaveButton)] protected Button SaveButton;
private const string POSITIONIDEXTRA = "monoStockPortfolio.EditPositionActivity.PositionID";
private const string PORTFOLIOIDEXTRA = "monoStockPortfolio.EditPositionActivity.PortfolioID";
public static Intent AddIntent(Context context, long portfolioId)
{
var intent = new Intent();
intent.SetClassName(context, ManifestNames.GetName<EditPositionActivity>());
intent.PutExtra(PORTFOLIOIDEXTRA, portfolioId);
return intent;
}
public static Intent EditIntent(Context context, long positionId, long portfolioId)
{
var intent = new Intent();
intent.SetClassName(context, ManifestNames.GetName<EditPositionActivity>());
intent.PutExtra(POSITIONIDEXTRA, positionId);
intent.PutExtra(PORTFOLIOIDEXTRA, portfolioId);
return intent;
}
public long ThisPortfolioId { get { return Intent.GetLongExtra(PORTFOLIOIDEXTRA, -1); } }
public long ThisPositionId { get { return Intent.GetLongExtra(POSITIONIDEXTRA, -1); } }
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.addposition);
var positionId = ThisPositionId;
if (positionId != -1)
{
this.Title = "Edit Position";
PopulateForm(positionId);
}
WireUpEvents();
}
private void PopulateForm(long positionId)
{
var position = _repo.GetPositionById(positionId);
this.TickerTextBox.Text = position.Ticker;
this.PriceTextBox.Text = position.PricePerShare.ToString();
this.SharesTextBox.Text = position.Shares.ToString();
}
private void WireUpEvents()
{
SaveButton.Click += saveButton_Click;
}
void saveButton_Click(object sender, EventArgs e)
{
if(Validate())
{
var positionToSave = GetPositionToSave();
_repo.SavePosition(positionToSave);
this.EndActivity();
}
}
private bool Validate()
{
var result = ValidationRules.Apply();
if (result == string.Empty)
{
return true;
}
this.LongToast(result);
return false;
}
private FormValidator ValidationRules
{
get
{
var validator = new FormValidator();
validator.AddRequired(TickerTextBox, "Please enter a ticker");
validator.AddValidPositiveDecimal(SharesTextBox, "Please enter a valid, positive number of shares");
validator.AddValidPositiveDecimal(PriceTextBox, "Please enter a valid, positive price per share");
validator.AddValidation(TickerTextBox, () => ValidateTicker(TickerTextBox.Text));
return validator;
}
}
private string ValidateTicker(string ticker)
{
if(_svc.IsValidTicker(ticker))
{
return string.Empty;
}
return "Invalid Ticker Name";
}
private Position GetPositionToSave()
{
Position positionToSave;
var positionId = ThisPositionId;
if (positionId != -1)
{
positionToSave = new Position(positionId);
}
else
{
positionToSave = new Position();
}
positionToSave.Shares = decimal.Parse(SharesTextBox.Text);
positionToSave.PricePerShare = decimal.Parse(PriceTextBox.Text);
positionToSave.Ticker = TickerTextBox.Text.ToUpper();
positionToSave.ContainingPortfolioID = ThisPortfolioId;
return positionToSave;
}
}
}

View file

@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Widget;
using MonoStockPortfolio.Entities;
using MonoStockPortfolio.Framework;
namespace MonoStockPortfolio.Activites.EditPositionScreen
{
[Activity(Label = "Add Position", MainLauncher = false, Name = "monostockportfolio.activites.EditPositionActivity")]
public class EditPositionActivity : Activity, IEditPositionView
{
[IoC] IEditPositionPresenter _presenter;
[LazyView(Resource.Id.addPositionTicker)] protected EditText TickerTextBox;
[LazyView(Resource.Id.addPositionPrice)] protected EditText PriceTextBox;
[LazyView(Resource.Id.addPositionShares)] protected EditText SharesTextBox;
[LazyView(Resource.Id.addPositionSaveButton)] protected Button SaveButton;
private const string POSITIONIDEXTRA = "monoStockPortfolio.EditPositionActivity.PositionID";
private const string PORTFOLIOIDEXTRA = "monoStockPortfolio.EditPositionActivity.PortfolioID";
public static Intent AddIntent(Context context, long portfolioId)
{
var intent = new Intent();
intent.SetClassName(context, ManifestNames.GetName<EditPositionActivity>());
intent.PutExtra(PORTFOLIOIDEXTRA, portfolioId);
return intent;
}
public static Intent EditIntent(Context context, long positionId, long portfolioId)
{
var intent = new Intent();
intent.SetClassName(context, ManifestNames.GetName<EditPositionActivity>());
intent.PutExtra(POSITIONIDEXTRA, positionId);
intent.PutExtra(PORTFOLIOIDEXTRA, portfolioId);
return intent;
}
#region IEditPositionView implementation
public void SetTitle(string title)
{
this.Title = title;
}
public void PopulateForm(Position position)
{
this.TickerTextBox.Text = position.Ticker;
this.PriceTextBox.Text = position.PricePerShare.ToString();
this.SharesTextBox.Text = position.Shares.ToString();
}
public void GoBackToMainActivity()
{
this.EndActivity();
}
public void ShowErrorMessages(IList<string> errorMessages)
{
var errorMessage = string.Empty;
foreach (var error in errorMessages)
{
errorMessage += error + "\n";
}
errorMessage = errorMessage.Trim('\n');
this.LongToast(errorMessage);
}
#endregion
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.addposition);
var portfolioId = Intent.GetLongExtra(PORTFOLIOIDEXTRA, -1);
var positionId = Intent.GetLongExtra(POSITIONIDEXTRA, -1);
if (positionId != -1)
{
_presenter.Initialize(this, portfolioId, positionId);
}
else
{
_presenter.Initialize(this, portfolioId);
}
WireUpEvents();
}
private void WireUpEvents()
{
SaveButton.Click += saveButton_Click;
}
void saveButton_Click(object sender, EventArgs e)
{
_presenter.Save(GetPositionInputModel());
}
private PositionInputModel GetPositionInputModel()
{
var model = new PositionInputModel();
model.TickerText = this.TickerTextBox.Text;
model.PriceText = this.PriceTextBox.Text;
model.SharesText = this.SharesTextBox.Text;
return model;
}
}
}

View file

@ -0,0 +1,89 @@
using System.Linq;
using MonoStockPortfolio.Core.PortfolioRepositories;
using MonoStockPortfolio.Core.StockData;
using MonoStockPortfolio.Entities;
using MonoStockPortfolio.Framework;
namespace MonoStockPortfolio.Activites.EditPositionScreen
{
public class EditPositionPresenter : IEditPositionPresenter
{
private IEditPositionView _currentView;
private readonly IPortfolioRepository _portfolioRepository;
private readonly IStockDataProvider _stockService;
private long? _positionId;
private long _portfolioId;
public EditPositionPresenter(IPortfolioRepository portfolioRepository, IStockDataProvider stockService)
{
_portfolioRepository = portfolioRepository;
_stockService = stockService;
}
public void Initialize(IEditPositionView editPositionView, long portfolioId, long? positionId = null)
{
_currentView = editPositionView;
_positionId = positionId;
_portfolioId = portfolioId;
if (positionId != null)
{
_currentView.SetTitle("Edit Position");
var position = _portfolioRepository.GetPositionById(positionId ?? -1);
_currentView.PopulateForm(position);
}
else
{
_currentView.SetTitle("Add Position");
}
}
public void Save(PositionInputModel positionInputModel)
{
var validator = new FormValidator();
validator.AddRequired(() => positionInputModel.TickerText, "Please enter a ticker");
validator.AddValidPositiveDecimal(() => positionInputModel.SharesText, "Please enter a valid, positive number of shares");
validator.AddValidPositiveDecimal(() => positionInputModel.PriceText, "Please enter a valid, positive price per share");
validator.AddValidation(() => ValidateTicker(positionInputModel.TickerText));
var errorMessages = validator.Apply();
if (!errorMessages.Any())
{
_portfolioRepository.SavePosition(GetPosition(positionInputModel));
_currentView.GoBackToMainActivity();
}
else
{
_currentView.ShowErrorMessages(errorMessages.ToList());
}
}
private Position GetPosition(PositionInputModel positionInputModel)
{
Position positionToSave;
if (_positionId != null)
{
positionToSave = new Position(_positionId ?? -1);
}
else
{
positionToSave = new Position();
}
positionToSave.Shares = decimal.Parse(positionInputModel.SharesText);
positionToSave.PricePerShare = decimal.Parse(positionInputModel.PriceText);
positionToSave.Ticker = positionInputModel.TickerText.ToUpper();
positionToSave.ContainingPortfolioID = _portfolioId;
return positionToSave;
}
private string ValidateTicker(string ticker)
{
if (_stockService.IsValidTicker(ticker))
{
return string.Empty;
}
return "Invalid Ticker Name";
}
}
}

View file

@ -0,0 +1,8 @@
namespace MonoStockPortfolio.Activites.EditPositionScreen
{
public interface IEditPositionPresenter
{
void Initialize(IEditPositionView editPositionActivity, long portfolioId, long? positionId = null);
void Save(PositionInputModel getPositionInputModel);
}
}

View file

@ -0,0 +1,13 @@
using System.Collections.Generic;
using MonoStockPortfolio.Entities;
namespace MonoStockPortfolio.Activites.EditPositionScreen
{
public interface IEditPositionView
{
void SetTitle(string title);
void PopulateForm(Position position);
void GoBackToMainActivity();
void ShowErrorMessages(IList<string> errorMessages);
}
}

View file

@ -0,0 +1,9 @@
namespace MonoStockPortfolio.Activites.EditPositionScreen
{
public class PositionInputModel
{
public string TickerText { get; set; }
public string PriceText { get; set; }
public string SharesText { get; set; }
}
}

View file

@ -6,6 +6,7 @@ using Android.Content;
using Android.OS;
using Android.Views;
using Android.Widget;
using MonoStockPortfolio.Activites.EditPositionScreen;
using MonoStockPortfolio.Core;
using MonoStockPortfolio.Entities;
using MonoStockPortfolio.Framework;

View file

@ -1,80 +1,73 @@
using System;
using System;
using System.Collections.Generic;
using Android.Widget;
using System.Linq;
namespace MonoStockPortfolio.Framework
{
public class FormValidator
{
private IList<KeyValuePair<EditText, Func<string>>> _dict;
private readonly IList<Func<string>> _list;
public FormValidator()
{
_dict = new List<KeyValuePair<EditText, Func<string>>>();
_list = new List<Func<string>>();
}
public void AddValidation(EditText control, Func<string> validationFunction)
public void AddValidation(Func<string> validationFunction)
{
_dict.Add(new KeyValuePair<EditText, Func<string>>(control, validationFunction));
}
public void AddRequired(EditText control, string errorMessage)
{
AddValidation(control, () => Required(control, errorMessage));
}
public void AddValidDecimal(EditText control, string errorMessage)
{
AddValidation(control, () => ValidDecimal(control, errorMessage));
}
public void AddValidPositiveDecimal(EditText control, string errorMessage)
{
AddValidation(control, () => ValidPositiveDecimal(control, errorMessage));
_list.Add(validationFunction);
}
public string Apply()
public void AddRequired(Func<string> getValue, string errorMessage)
{
var errorMessage = string.Empty;
foreach (var keyValuePair in _dict)
{
var result = keyValuePair.Value();
errorMessage += keyValuePair.Value();
if(result != string.Empty)
{
errorMessage += "\n";
}
}
return errorMessage;
AddValidation(() => Required(getValue(), errorMessage));
}
#region Validation Functions
private static string Required(EditText control, string errorMessage)
public void AddValidDecimal(Func<string> getValue, string errorMessage)
{
if (string.IsNullOrEmpty(control.Text.ToString()))
AddValidation(() => ValidDecimal(getValue(), errorMessage));
}
public void AddValidPositiveDecimal(Func<string> getValue, string errorMessage)
{
AddValidation(() => ValidPositiveDecimal(getValue(), errorMessage));
}
public IEnumerable<string> Apply()
{
return _list.Select(validation => validation())
.Where(result => !string.IsNullOrEmpty(result));
}
#region validation functions
private static string Required(string getValue, string errorMessage)
{
if (string.IsNullOrEmpty(getValue))
{
return errorMessage;
}
return string.Empty;
}
private static string ValidDecimal(EditText control, string errorMessage)
private static string ValidDecimal(string getValue, string errorMessage)
{
var test = control.Text.ToString();
decimal dummy;
if(!decimal.TryParse(test, out dummy))
if (!decimal.TryParse(getValue, out dummy))
{
return errorMessage;
}
return string.Empty;
}
private static string ValidPositiveDecimal(EditText control, string errorMessage)
private static string ValidPositiveDecimal(string getValue, string errorMessage)
{
if(ValidDecimal(control, errorMessage) == string.Empty)
if (ValidDecimal(getValue, errorMessage) == string.Empty)
{
var val = decimal.Parse(control.Text.ToString());
var val = decimal.Parse(getValue);
if (val >= 0) return string.Empty;
}
return errorMessage;
}
#endregion
}
}

View file

@ -1,45 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace MonoStockPortfolio.Framework
{
public class NewFormValidator
{
private readonly IList<Func<string>> _list;
public NewFormValidator()
{
_list = new List<Func<string>>();
}
public void AddValidation(Func<string> getValue, Func<string> validationFunction)
{
_list.Add(validationFunction);
}
public void AddRequired(Func<string> getValue, string errorMessage)
{
AddValidation(getValue, () => Required(getValue(), errorMessage));
}
public IEnumerable<string> Apply()
{
return _list.Select(validation => validation())
.Where(result => !string.IsNullOrEmpty(result));
}
#region validation functions
private static string Required(string getValue, string errorMessage)
{
if (string.IsNullOrEmpty(getValue))
{
return errorMessage;
}
return string.Empty;
}
#endregion
}
}

View file

@ -2,6 +2,7 @@
using Android.Content;
using Android.Util;
using MonoStockPortfolio.Activites.EditPortfolioScreen;
using MonoStockPortfolio.Activites.EditPositionScreen;
using MonoStockPortfolio.Activites.MainScreen;
using MonoStockPortfolio.Activites.PortfolioScreen;
using MonoStockPortfolio.Core.Config;
@ -28,6 +29,7 @@ namespace MonoStockPortfolio.Framework
IttyBittyIoC.Register<IMainPresenter, MainPresenter>();
IttyBittyIoC.Register<IPortfolioPresenter, PortfolioPresenter>();
IttyBittyIoC.Register<IEditPortfolioPresenter, EditPortfolioPresenter>();
IttyBittyIoC.Register<IEditPositionPresenter, EditPositionPresenter>();
}
public static object Get(Type serviceType)

View file

@ -59,7 +59,11 @@
<Compile Include="Activites\EditPortfolioScreen\EditPortfolioPresenter.cs" />
<Compile Include="Activites\EditPortfolioScreen\IEditPortfolioPresenter.cs" />
<Compile Include="Activites\EditPortfolioScreen\IEditPortfolioView.cs" />
<Compile Include="Framework\NewFormValidator.cs" />
<Compile Include="Activites\EditPositionScreen\EditPositionPresenter.cs" />
<Compile Include="Activites\EditPositionScreen\IEditPositionPresenter.cs" />
<Compile Include="Activites\EditPositionScreen\IEditPositionView.cs" />
<Compile Include="Activites\EditPositionScreen\PositionInputModel.cs" />
<Compile Include="Framework\FormValidator.cs" />
<Compile Include="Activites\MainScreen\IMainPresenter.cs" />
<Compile Include="Activites\MainScreen\IMainView.cs" />
<Compile Include="Activites\MainScreen\MainPresenter.cs" />
@ -73,7 +77,7 @@
<Compile Include="Framework\GenericArrayAdapter.cs" />
<Compile Include="Activites\PortfolioScreen\PortfolioActivity.cs" />
<Compile Include="Activites\MainScreen\MainActivity.cs" />
<Compile Include="Activites\EditPositionActivity.cs" />
<Compile Include="Activites\EditPositionScreen\EditPositionActivity.cs" />
<Compile Include="Framework\IoCAttribute.cs" />
<Compile Include="Framework\IttyBittyIoC.cs" />
<Compile Include="Framework\LazyViewAttribute.cs" />
@ -84,7 +88,6 @@
<Compile Include="Resources\Resource.Designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Framework\StringExtensions.cs" />
<Compile Include="Framework\FormValidator.cs" />
</ItemGroup>
<ItemGroup>
<None Include="PostSharp.Custom.targets" />