├── DDD.db ├── DDD.Domain ├── Exceptions │ └── InputException.cs ├── Repositories │ ├── IAreasRepository.cs │ └── IWeatherRepository.cs ├── Entities │ ├── AreaEntity.cs │ └── WeatherEntity.cs ├── Helpers │ ├── FloatHelper.cs │ └── Guard.cs ├── ValueObjects │ ├── AreaId.cs │ ├── ValueObject.cs │ ├── Temperature.cs │ └── Condition.cs ├── Properties │ └── AssemblyInfo.cs └── DDD.Domain.csproj ├── DDD.WinForm ├── Properties │ ├── Settings.settings │ ├── Settings.Designer.cs │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── Views │ ├── WeatherListView.cs │ ├── WeatherLatestView.cs │ ├── WeatherSaveView.cs │ ├── WeatherListView.Designer.cs │ ├── WeatherLatestView.resx │ ├── WeatherListView.resx │ ├── WeatherSaveView.resx │ ├── WeatherSaveView.Designer.cs │ └── WeatherLatestView.Designer.cs ├── Program.cs ├── ViewModels │ ├── WeatherListViewModelWeather.cs │ ├── WeatherListViewModel.cs │ ├── ViewModelBase.cs │ ├── WeatherSaveViewModel.cs │ └── WeatherLatestViewModel.cs ├── packages.config ├── App.config └── DDD.WinForm.csproj ├── DDD.Infrastructure ├── packages.config ├── SQLite │ ├── AreasSQLite.cs │ ├── WeatherSQLite.cs │ └── SQLiteHelper.cs ├── Properties │ └── AssemblyInfo.cs ├── App.config └── DDD.Infrastructure.csproj ├── DDDTest.Tests ├── packages.config ├── Properties │ └── AssemblyInfo.cs ├── TemperatureTest.cs ├── WeatherListViewModelTest.cs ├── WeatherSaveViewModelTest.cs ├── WeatherLatestViewModelTest.cs ├── DDDTest.Tests.csproj └── ChainingAssertion.MSTest.cs ├── DDD.sln └── .gitignore /DDD.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tak001/csharp-windows-form-ddd-tdd/HEAD/DDD.db -------------------------------------------------------------------------------- /DDD.Domain/Exceptions/InputException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DDD.Domain.Exceptions 4 | { 5 | public sealed class InputException : Exception 6 | { 7 | public InputException(string message) : base(message) 8 | { 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /DDD.Domain/Repositories/IAreasRepository.cs: -------------------------------------------------------------------------------- 1 | using DDD.Domain.Entities; 2 | using System.Collections.Generic; 3 | 4 | namespace DDD.Domain.Repositories 5 | { 6 | public interface IAreasRepository 7 | { 8 | IReadOnlyList GetData(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /DDD.WinForm/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DDD.Domain/Repositories/IWeatherRepository.cs: -------------------------------------------------------------------------------- 1 | using DDD.Domain.Entities; 2 | using System.Collections.Generic; 3 | 4 | namespace DDD.Domain.Repositories 5 | { 6 | public interface IWeatherRepository 7 | { 8 | WeatherEntity GetLatest(int areaId); 9 | IReadOnlyList GetData(); 10 | void Save(WeatherEntity weather); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /DDD.Domain/Entities/AreaEntity.cs: -------------------------------------------------------------------------------- 1 | namespace DDD.Domain.Entities 2 | { 3 | public sealed class AreaEntity 4 | { 5 | public AreaEntity(int areaId, string areaName) 6 | { 7 | AreaId = areaId; 8 | AreaName = areaName; 9 | } 10 | 11 | public int AreaId { get; } 12 | public string AreaName { get; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /DDD.WinForm/Views/WeatherListView.cs: -------------------------------------------------------------------------------- 1 | using DDD.WinForm.ViewModels; 2 | using System.Windows.Forms; 3 | 4 | namespace DDD.WinForm.Views 5 | { 6 | public partial class WeatherListView : Form 7 | { 8 | private WeatherListViewModel _viewModel = new WeatherListViewModel(); 9 | public WeatherListView() 10 | { 11 | InitializeComponent(); 12 | 13 | WeathersDataGrid.DataBindings.Add( 14 | "DataSource", _viewModel, nameof(_viewModel.Weathers)); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /DDD.Domain/Helpers/FloatHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DDD.Domain.Helpers 4 | { 5 | public static class FloatHelper 6 | { 7 | /// 8 | /// 小数点以下を指定桁数で四捨五入します 9 | /// 10 | /// 11 | /// 12 | /// 13 | public static string RoundString(this float value, int decimalPoint) 14 | { 15 | var temp = Convert.ToSingle(Math.Round(value, decimalPoint)); 16 | return temp.ToString("F" + decimalPoint); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /DDD.WinForm/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using System.Windows.Forms; 6 | 7 | namespace DDD.WinForm 8 | { 9 | internal static class Program 10 | { 11 | /// 12 | /// アプリケーションのメイン エントリ ポイントです。 13 | /// 14 | [STAThread] 15 | static void Main() 16 | { 17 | Application.EnableVisualStyles(); 18 | Application.SetCompatibleTextRenderingDefault(false); 19 | Application.Run(new WeatherLatestView()); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /DDD.Infrastructure/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DDD.Domain/ValueObjects/AreaId.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DDD.Domain.ValueObjects 4 | { 5 | public sealed class AreaId : ValueObject 6 | { 7 | 8 | public AreaId(int value) 9 | { 10 | Value = value; 11 | } 12 | 13 | public int Value { get; } 14 | 15 | protected override bool EqualsCore(AreaId other) 16 | { 17 | return Value == other.Value; 18 | } 19 | 20 | public string DisplayValue 21 | { 22 | get 23 | { 24 | return Value.ToString().PadLeft(4, '0'); 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /DDDTest.Tests/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /DDD.Domain/Helpers/Guard.cs: -------------------------------------------------------------------------------- 1 | using DDD.Domain.Exceptions; 2 | 3 | namespace DDD.Domain.Helpers 4 | { 5 | public static class Guard 6 | { 7 | public static void IsNull(object o, string message) 8 | { 9 | if (o == null) 10 | { 11 | throw new InputException(message); 12 | } 13 | } 14 | 15 | public static float IsFloat(string text, string message) 16 | { 17 | float floatValue; 18 | if (!float.TryParse(text, out floatValue)) 19 | { 20 | throw new InputException(message); 21 | } 22 | 23 | return floatValue; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /DDD.WinForm/ViewModels/WeatherListViewModelWeather.cs: -------------------------------------------------------------------------------- 1 | using DDD.Domain.Entities; 2 | 3 | namespace DDD.WinForm.ViewModels 4 | { 5 | public sealed class WeatherListViewModelWeather 6 | { 7 | private WeatherEntity _entity; 8 | public WeatherListViewModelWeather(WeatherEntity entity) 9 | { 10 | _entity = entity; 11 | } 12 | 13 | public string AreaId => _entity.AreaId.DisplayValue; 14 | public string AreaName => _entity.AreaName; 15 | public string DateDate => _entity.DataDate.ToString(); 16 | public string Condition => _entity.Condition.DisplayValue; 17 | public string Temperature => _entity.Temperature.DisplayValueWithUnitSpace; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /DDD.Infrastructure/SQLite/AreasSQLite.cs: -------------------------------------------------------------------------------- 1 | using DDD.Domain.Entities; 2 | using DDD.Domain.Repositories; 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | namespace DDD.Infrastructure.SQLite 7 | { 8 | public sealed class AreasSQLite : IAreasRepository 9 | { 10 | public IReadOnlyList GetData() 11 | { 12 | string sql = @" 13 | select AreaId, 14 | AreaName 15 | from Areas"; 16 | 17 | return SQLiteHelper.Query(sql, 18 | reader => 19 | { 20 | return new AreaEntity(Convert.ToInt32(reader["AreaId"]), Convert.ToString(reader["AreaName"])); 21 | } 22 | ); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /DDDTest.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | [assembly: AssemblyTitle("DDDTest.Tests")] 6 | [assembly: AssemblyDescription("")] 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("DDDTest.Tests")] 10 | [assembly: AssemblyCopyright("Copyright © 2022")] 11 | [assembly: AssemblyTrademark("")] 12 | [assembly: AssemblyCulture("")] 13 | 14 | [assembly: ComVisible(false)] 15 | 16 | [assembly: Guid("60c84acc-6124-449a-8c1f-f2e26e6efe02")] 17 | 18 | // [assembly: AssemblyVersion("1.0.*")] 19 | [assembly: AssemblyVersion("1.0.0.0")] 20 | [assembly: AssemblyFileVersion("1.0.0.0")] 21 | -------------------------------------------------------------------------------- /DDD.Domain/ValueObjects/ValueObject.cs: -------------------------------------------------------------------------------- 1 | namespace DDD.Domain.ValueObjects 2 | { 3 | public abstract class ValueObject where T : ValueObject 4 | { 5 | public override bool Equals(object obj) 6 | { 7 | var vo = obj as T; 8 | if (vo == null) return false; 9 | return EqualsCore(vo); 10 | } 11 | 12 | public static bool operator ==(ValueObject vo1, ValueObject vo2) 13 | { 14 | return Equals(vo1, vo2); 15 | } 16 | 17 | public static bool operator !=(ValueObject vo1, ValueObject vo2) 18 | { 19 | return !Equals(vo1, vo2); 20 | } 21 | 22 | protected abstract bool EqualsCore(T other); 23 | 24 | public override string ToString() 25 | { 26 | return base.ToString(); 27 | } 28 | 29 | public override int GetHashCode() 30 | { 31 | return base.GetHashCode(); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /DDD.WinForm/ViewModels/WeatherListViewModel.cs: -------------------------------------------------------------------------------- 1 | using DDD.Domain.Repositories; 2 | using DDD.Infrastructure.SQLite; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.ComponentModel; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace DDD.WinForm.ViewModels 11 | { 12 | public class WeatherListViewModel : ViewModelBase 13 | { 14 | private IWeatherRepository _weather; 15 | 16 | public WeatherListViewModel() : this(new WeatherSQLite()) 17 | { 18 | } 19 | 20 | public WeatherListViewModel(IWeatherRepository weather) 21 | { 22 | _weather = weather; 23 | 24 | foreach (var entity in _weather.GetData()) 25 | { 26 | Weathers.Add(new WeatherListViewModelWeather(entity)); 27 | } 28 | } 29 | 30 | public BindingList 31 | Weathers 32 | { get; set; } 33 | = new BindingList(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /DDD.WinForm/ViewModels/ViewModelBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Runtime.CompilerServices; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace DDD.WinForm.ViewModels 10 | { 11 | public abstract class ViewModelBase : INotifyPropertyChanged 12 | { 13 | public event PropertyChangedEventHandler PropertyChanged; 14 | 15 | protected bool SetProperty(ref T field, 16 | T value, [CallerMemberName]string propertyName = null) 17 | { 18 | if (Equals(field, value)) 19 | { 20 | return false; 21 | } 22 | 23 | field = value; 24 | var h = this.PropertyChanged; 25 | if (h != null) 26 | { 27 | h(this, new PropertyChangedEventArgs(propertyName)); 28 | } 29 | 30 | return true; 31 | } 32 | 33 | public virtual DateTime GetDateTime() 34 | { 35 | return DateTime.Now; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /DDD.WinForm/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /DDDTest.Tests/TemperatureTest.cs: -------------------------------------------------------------------------------- 1 | using DDD.Domain.ValueObjects; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using System; 4 | 5 | namespace DDDTest.Tests 6 | { 7 | [TestClass] 8 | public class TemperatureTest 9 | { 10 | [TestMethod] 11 | public void 小数点以下2桁でまるめて表示できる() 12 | { 13 | var t = new Temperature(12.3f); 14 | Assert.AreEqual(12.3f, t.Value); 15 | Assert.AreEqual("12.30", t.DisplayValue); 16 | Assert.AreEqual("12.30℃", t.DisplayValueWithUnit); 17 | Assert.AreEqual("12.30 ℃", t.DisplayValueWithUnitSpace); 18 | } 19 | 20 | [TestMethod] 21 | public void 温度Equals() 22 | { 23 | var t1 = new Temperature(12.3f); 24 | var t2 = new Temperature(12.3f); 25 | 26 | Assert.AreEqual(true, t1.Equals(t2)); 27 | } 28 | 29 | [TestMethod] 30 | public void 温度EqualsEquals() 31 | { 32 | var t1 = new Temperature(12.3f); 33 | var t2 = new Temperature(12.3f); 34 | 35 | Assert.AreEqual(true, t1 == t2); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /DDD.Domain/ValueObjects/Temperature.cs: -------------------------------------------------------------------------------- 1 | using DDD.Domain.Helpers; 2 | 3 | namespace DDD.Domain.ValueObjects 4 | { 5 | public sealed class Temperature : ValueObject 6 | { 7 | public const string UnitName = "℃"; 8 | public const int DecimalPoint = 2; 9 | 10 | public Temperature(float value) 11 | { 12 | Value = value; 13 | } 14 | 15 | public float Value { get; } 16 | public string DisplayValue 17 | { 18 | get 19 | { 20 | return Value.RoundString(DecimalPoint); 21 | } 22 | } 23 | 24 | public string DisplayValueWithUnit 25 | { 26 | get 27 | { 28 | return Value.RoundString(DecimalPoint) + UnitName; 29 | } 30 | } 31 | 32 | public string DisplayValueWithUnitSpace 33 | { 34 | get 35 | { 36 | return Value.RoundString(DecimalPoint) + " " + UnitName; 37 | } 38 | } 39 | 40 | protected override bool EqualsCore(Temperature other) 41 | { 42 | return Value == other.Value; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /DDD.WinForm/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace DDD.WinForm.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /DDD.Domain/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // アセンブリに関する一般情報は以下の属性セットをとおして制御されます。 6 | // 制御されます。アセンブリに関連付けられている情報を変更するには、 7 | // これらの属性値を変更してください。 8 | [assembly: AssemblyTitle("DDD.Domain")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("DDD.Domain")] 13 | [assembly: AssemblyCopyright("Copyright © 2022")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // ComVisible を false に設定すると、このアセンブリ内の型は COM コンポーネントから 18 | // 参照できなくなります。COM からこのアセンブリ内の型にアクセスする必要がある場合は、 19 | // その型の ComVisible 属性を true に設定してください。 20 | [assembly: ComVisible(false)] 21 | 22 | // このプロジェクトが COM に公開される場合、次の GUID が typelib の ID になります 23 | [assembly: Guid("96953b4b-cf64-4c86-9474-2920a946c948")] 24 | 25 | // アセンブリのバージョン情報は、以下の 4 つの値で構成されています: 26 | // 27 | // メジャー バージョン 28 | // マイナー バージョン 29 | // ビルド番号 30 | // リビジョン 31 | // 32 | // すべての値を指定するか、次を使用してビルド番号とリビジョン番号を既定に設定できます 33 | // 既定値にすることができます: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DDD.WinForm/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // アセンブリに関する一般情報は以下の属性セットをとおして制御されます。 6 | // 制御されます。アセンブリに関連付けられている情報を変更するには、 7 | // これらの属性値を変更します。 8 | [assembly: AssemblyTitle("DDD.WinForm")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("DDD.WinForm")] 13 | [assembly: AssemblyCopyright("Copyright © 2022")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // ComVisible を false に設定すると、このアセンブリ内の型は COM コンポーネントから 18 | // 参照できなくなります。COM からこのアセンブリ内の型にアクセスする必要がある場合は、 19 | // その型の ComVisible 属性を true に設定してください。 20 | [assembly: ComVisible(false)] 21 | 22 | // このプロジェクトが COM に公開される場合、次の GUID が typelib の ID になります 23 | [assembly: Guid("9a4ae28c-86ee-4540-a14d-8ed616abb499")] 24 | 25 | // アセンブリのバージョン情報は、以下の 4 つの値で構成されています: 26 | // 27 | // メジャー バージョン 28 | // マイナー バージョン 29 | // ビルド番号 30 | // リビジョン 31 | // 32 | // すべての値を指定するか、次を使用してビルド番号とリビジョン番号を既定に設定できます 33 | // 既定値にすることができます: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DDD.Infrastructure/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // アセンブリに関する一般情報は以下の属性セットをとおして制御されます。 6 | // 制御されます。アセンブリに関連付けられている情報を変更するには、 7 | // これらの属性値を変更してください。 8 | [assembly: AssemblyTitle("DDD.Infrastructure")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("DDD.Infrastructure")] 13 | [assembly: AssemblyCopyright("Copyright © 2022")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // ComVisible を false に設定すると、このアセンブリ内の型は COM コンポーネントから 18 | // 参照できなくなります。COM からこのアセンブリ内の型にアクセスする必要がある場合は、 19 | // その型の ComVisible 属性を true に設定してください。 20 | [assembly: ComVisible(false)] 21 | 22 | // このプロジェクトが COM に公開される場合、次の GUID が typelib の ID になります 23 | [assembly: Guid("6de6357e-7563-4e71-aaf3-50334e3be85d")] 24 | 25 | // アセンブリのバージョン情報は、以下の 4 つの値で構成されています: 26 | // 27 | // メジャー バージョン 28 | // マイナー バージョン 29 | // ビルド番号 30 | // リビジョン 31 | // 32 | // すべての値を指定するか、次を使用してビルド番号とリビジョン番号を既定に設定できます 33 | // 既定値にすることができます: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DDD.Infrastructure/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /DDD.Domain/Entities/WeatherEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DDD.Domain.ValueObjects; 3 | 4 | namespace DDD.Domain.Entities 5 | { 6 | public sealed class WeatherEntity 7 | { 8 | // 完全コンストラクタパターン 9 | public WeatherEntity( 10 | int areaId, 11 | DateTime dataDate, 12 | int condition, 13 | float temperature 14 | ) : this(areaId, string.Empty, dataDate, condition, temperature) 15 | { 16 | } 17 | 18 | public WeatherEntity( 19 | int areaId, 20 | string areaName, 21 | DateTime dataDate, 22 | int condition, 23 | float temperature 24 | ) 25 | { 26 | AreaId = new AreaId(areaId); 27 | AreaName = areaName; 28 | DataDate = dataDate; 29 | Condition = new Condition(condition); 30 | Temperature = new Temperature(temperature); 31 | 32 | } 33 | 34 | public AreaId AreaId { get; } 35 | public string AreaName { get; } 36 | public DateTime DataDate { get; } 37 | public Condition Condition { get; } 38 | public Temperature Temperature { get; } 39 | 40 | public bool IsMousho() 41 | { 42 | if (Condition.IsSunny()) 43 | { 44 | if (Temperature.Value > 30) 45 | { 46 | return true; 47 | } 48 | } 49 | return false; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /DDD.WinForm/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /DDDTest.Tests/WeatherListViewModelTest.cs: -------------------------------------------------------------------------------- 1 | using DDD.Domain.Entities; 2 | using DDD.Domain.Repositories; 3 | using DDD.WinForm.ViewModels; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | using Moq; 6 | using System; 7 | using System.Collections.Generic; 8 | 9 | namespace DDDTest.Tests 10 | { 11 | [TestClass] 12 | public class WeatherListViewModelTest 13 | { 14 | [TestMethod] 15 | public void 天気一覧画面シナリオ() 16 | { 17 | var weatherMock = new Mock(); 18 | 19 | var entities = new List(); 20 | entities.Add( 21 | new WeatherEntity( 22 | 1, 23 | "東京", 24 | Convert.ToDateTime("2018/01/01 12:34:56"), 25 | 2, 26 | 12.3f 27 | ) 28 | ); 29 | entities.Add( 30 | new WeatherEntity( 31 | 2, 32 | "神戸", 33 | Convert.ToDateTime("2018/01/02 12:34:56"), 34 | 1, 35 | 22.123f 36 | ) 37 | ); 38 | 39 | 40 | weatherMock.Setup(x => x.GetData()).Returns(entities); 41 | 42 | var viewModel = new WeatherListViewModel(weatherMock.Object); 43 | viewModel.Weathers.Count.Is(2); 44 | viewModel.Weathers[0].AreaId.Is("0001"); 45 | viewModel.Weathers[0].AreaName.Is("東京"); 46 | viewModel.Weathers[0].DateDate.Is("2018/01/01 12:34:56"); 47 | viewModel.Weathers[0].Condition.Is("曇り"); 48 | viewModel.Weathers[0].Temperature.Is("12.30 ℃"); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /DDD.WinForm/Views/WeatherLatestView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | using DDD.Domain.Entities; 4 | using DDD.WinForm.ViewModels; 5 | using DDD.WinForm.Views; 6 | 7 | namespace DDD.WinForm 8 | { 9 | public partial class WeatherLatestView : Form 10 | { 11 | private WeatherLatestViewModel _viewModel = new WeatherLatestViewModel(); 12 | public WeatherLatestView() 13 | { 14 | InitializeComponent(); 15 | 16 | this.AreasComboBox.DropDownStyle = ComboBoxStyle.DropDownList; 17 | this.AreasComboBox.DataBindings.Add( 18 | "SelectedValue", _viewModel, nameof(_viewModel.SelectedAreaId)); 19 | this.AreasComboBox.DataBindings.Add( 20 | "DataSource", _viewModel, nameof(_viewModel.Areas)); 21 | this.AreasComboBox.ValueMember = nameof(AreaEntity.AreaId); 22 | this.AreasComboBox.DisplayMember = nameof(AreaEntity.AreaName); 23 | this.DataDateLabel.DataBindings.Add( 24 | "Text", _viewModel, nameof(_viewModel.DataDateText)); 25 | this.ConditionLabel.DataBindings.Add( 26 | "Text", _viewModel, nameof(_viewModel.ConditionText)); 27 | this.TemperatureLabel.DataBindings.Add( 28 | "Text", _viewModel, nameof(_viewModel.TemperatureText)); 29 | } 30 | 31 | private void LatestButton_Click(object sender, EventArgs e) 32 | { 33 | _viewModel.Search(); 34 | } 35 | 36 | private void button1_Click(object sender, EventArgs e) 37 | { 38 | using(var f = new WeatherListView()) 39 | { 40 | f.ShowDialog(); 41 | } 42 | } 43 | 44 | private void button2_Click(object sender, EventArgs e) 45 | { 46 | using (var f = new WeatherSaveView()) 47 | { 48 | f.ShowDialog(); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /DDD.Domain/ValueObjects/Condition.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DDD.Domain.ValueObjects 8 | { 9 | public sealed class Condition : ValueObject 10 | { 11 | /// 12 | /// 不明 13 | /// 14 | public static readonly Condition None = new Condition(0); 15 | 16 | /// 17 | /// 晴れ 18 | /// 19 | public static readonly Condition Sunny = new Condition(1); 20 | 21 | /// 22 | /// 曇り 23 | /// 24 | public static readonly Condition Cloudy = new Condition(2); 25 | 26 | /// 27 | /// 雨 28 | /// 29 | public static readonly Condition Rain = new Condition(3); 30 | 31 | public Condition(int value) 32 | { 33 | Value = value; 34 | } 35 | 36 | public int Value { get; } 37 | 38 | public string DisplayValue 39 | { 40 | get 41 | { 42 | if (this == Sunny) 43 | { 44 | return "晴れ"; 45 | } 46 | if (this == Cloudy) 47 | { 48 | return "曇り"; 49 | } 50 | if (this == Rain) 51 | { 52 | return "雨"; 53 | } 54 | return "不明"; 55 | } 56 | } 57 | 58 | public bool IsSunny() 59 | { 60 | return this == Sunny; 61 | } 62 | 63 | protected override bool EqualsCore(Condition other) 64 | { 65 | return this.Value == other.Value; 66 | } 67 | 68 | public static IList ToList() 69 | { 70 | return new List 71 | { 72 | None, 73 | Sunny, 74 | Cloudy, 75 | Rain 76 | }; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /DDD.WinForm/ViewModels/WeatherSaveViewModel.cs: -------------------------------------------------------------------------------- 1 | using DDD.Domain.Entities; 2 | using DDD.Domain.Exceptions; 3 | using DDD.Domain.Helpers; 4 | using DDD.Domain.Repositories; 5 | using DDD.Domain.ValueObjects; 6 | using DDD.Infrastructure.SQLite; 7 | using System; 8 | using System.ComponentModel; 9 | 10 | namespace DDD.WinForm.ViewModels 11 | { 12 | public class WeatherSaveViewModel : ViewModelBase 13 | { 14 | private IWeatherRepository _weather; 15 | private IAreasRepository _areas; 16 | 17 | public WeatherSaveViewModel() 18 | : this(new WeatherSQLite(), new AreasSQLite()) 19 | { 20 | } 21 | 22 | public WeatherSaveViewModel(IWeatherRepository weather, IAreasRepository areas) 23 | { 24 | _weather = weather; 25 | _areas = areas; 26 | DataDateValue = GetDateTime(); 27 | SelectedCondition = Condition.Sunny.Value; 28 | TemperatureText = string.Empty; 29 | 30 | foreach (var area in _areas.GetData()) 31 | { 32 | Areas.Add(new AreaEntity(area.AreaId, area.AreaName)); 33 | } 34 | } 35 | 36 | public object SelectedAreaId { get; set; } 37 | public DateTime DataDateValue { get; set; } 38 | public object SelectedCondition { get; set; } 39 | public string TemperatureText { get; set; } 40 | public BindingList Areas { get; set; } 41 | = new BindingList(); 42 | 43 | public BindingList Conditions { get; set; } 44 | = new BindingList(Condition.ToList()); 45 | public string TemperatureUnitName => Temperature.UnitName; 46 | 47 | public void Save() 48 | { 49 | Guard.IsNull(SelectedAreaId, "エリアを選択して下さい"); 50 | var temperature = Guard.IsFloat(TemperatureText, "温度の入力に誤りがあります"); 51 | 52 | var entity = new WeatherEntity( 53 | Convert.ToInt32(SelectedAreaId), 54 | DataDateValue, 55 | Convert.ToInt32(SelectedCondition), 56 | temperature 57 | ); 58 | _weather.Save(entity); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /DDD.WinForm/Views/WeatherSaveView.cs: -------------------------------------------------------------------------------- 1 | using DDD.Domain.Entities; 2 | using DDD.Domain.ValueObjects; 3 | using DDD.WinForm.ViewModels; 4 | using System; 5 | using System.Windows.Forms; 6 | 7 | namespace DDD.WinForm.Views 8 | { 9 | public partial class WeatherSaveView : Form 10 | { 11 | private WeatherSaveViewModel _viewModel = new WeatherSaveViewModel(); 12 | public WeatherSaveView() 13 | { 14 | InitializeComponent(); 15 | 16 | this.AreaIdComboBox.DropDownStyle = ComboBoxStyle.DropDownList; 17 | this.AreaIdComboBox.DataBindings.Add( 18 | "SelectedValue", _viewModel, nameof(_viewModel.SelectedAreaId)); 19 | this.AreaIdComboBox.DataBindings.Add( 20 | "DataSource", _viewModel, nameof(_viewModel.Areas)); 21 | this.AreaIdComboBox.ValueMember = nameof(AreaEntity.AreaId); 22 | this.AreaIdComboBox.DisplayMember = nameof(AreaEntity.AreaName); 23 | 24 | DateTimeTextBox.DataBindings.Add( 25 | "Value", _viewModel, nameof(_viewModel.DataDateValue)); 26 | this.ConditionComboBox.DropDownStyle = ComboBoxStyle.DropDownList; 27 | 28 | this.ConditionComboBox.DataBindings.Add( 29 | "SelectedValue", _viewModel, nameof(_viewModel.SelectedCondition)); 30 | this.ConditionComboBox.DataBindings.Add( 31 | "DataSource", _viewModel, nameof(_viewModel.Conditions)); 32 | this.ConditionComboBox.ValueMember = nameof(Condition.Value); 33 | this.ConditionComboBox.DisplayMember = nameof(Condition.DisplayValue); 34 | 35 | TemperatureTextBox.DataBindings.Add( 36 | "Text", _viewModel, nameof(_viewModel.TemperatureText)); 37 | 38 | UnitLabel.DataBindings.Add( 39 | "Text", _viewModel, nameof(_viewModel.TemperatureUnitName)); 40 | 41 | SaveButton.Click += (_, __) => 42 | { 43 | try 44 | { 45 | _viewModel.Save(); 46 | } 47 | catch(Exception ex) 48 | { 49 | MessageBox.Show(ex.Message); 50 | } 51 | 52 | }; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /DDDTest.Tests/WeatherSaveViewModelTest.cs: -------------------------------------------------------------------------------- 1 | using DDD.Domain.Entities; 2 | using DDD.Domain.Exceptions; 3 | using DDD.Domain.Repositories; 4 | using DDD.WinForm.ViewModels; 5 | using Microsoft.VisualStudio.TestTools.UnitTesting; 6 | using Moq; 7 | using System; 8 | using System.Collections.Generic; 9 | 10 | namespace DDDTest.Tests 11 | { 12 | [TestClass] 13 | public class WeatherSaveViewModelTest 14 | { 15 | 16 | [TestMethod] 17 | public void 天気登録シナリオ() 18 | { 19 | var weatherMock = new Mock(); 20 | var areasMock = new Mock(); 21 | 22 | var areas = new List(); 23 | areas.Add(new AreaEntity(1, "東京")); 24 | areas.Add(new AreaEntity(2, "神戸")); 25 | areasMock.Setup(x => x.GetData()).Returns(areas); 26 | 27 | var viewModelMock = new Mock(weatherMock.Object, areasMock.Object); 28 | viewModelMock.Setup(x => x.GetDateTime()).Returns( 29 | Convert.ToDateTime("2018/01/01 12:24:56")); 30 | 31 | var viewModel = viewModelMock.Object; 32 | viewModel.SelectedAreaId.IsNull(); 33 | viewModel.DataDateValue.Is(Convert.ToDateTime("2018/01/01 12:24:56")); 34 | viewModel.SelectedCondition.Is(1); 35 | viewModel.TemperatureText.Is(""); 36 | viewModel.TemperatureUnitName.Is("℃"); 37 | 38 | viewModel.Areas.Count.Is(2); 39 | viewModel.Conditions.Count.Is(4); 40 | 41 | var ex = AssertEx.Throws(() => viewModel.Save()); 42 | ex.Message.Is("エリアを選択して下さい"); 43 | 44 | viewModel.SelectedAreaId = 2; 45 | ex = AssertEx.Throws(() => viewModel.Save()); 46 | ex.Message.Is("温度の入力に誤りがあります"); 47 | 48 | viewModel.TemperatureText = "12.345"; 49 | 50 | weatherMock.Setup(x => x.Save(It.IsAny())). 51 | Callback(saveValue => 52 | { 53 | saveValue.AreaId.Value.Is(2); 54 | saveValue.DataDate.Is(Convert.ToDateTime("2018/01/01 12:24:56")); 55 | saveValue.Condition.Value.Is(1); 56 | saveValue.Temperature.Value.Is(12.345f); 57 | }); 58 | 59 | viewModel.Save(); 60 | weatherMock.VerifyAll(); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /DDD.WinForm/Views/WeatherListView.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace DDD.WinForm.Views 2 | { 3 | partial class WeatherListView 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.WeathersDataGrid = new System.Windows.Forms.DataGridView(); 32 | ((System.ComponentModel.ISupportInitialize)(this.WeathersDataGrid)).BeginInit(); 33 | this.SuspendLayout(); 34 | // 35 | // WeathersDataGrid 36 | // 37 | this.WeathersDataGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; 38 | this.WeathersDataGrid.Dock = System.Windows.Forms.DockStyle.Fill; 39 | this.WeathersDataGrid.Location = new System.Drawing.Point(0, 0); 40 | this.WeathersDataGrid.Name = "WeathersDataGrid"; 41 | this.WeathersDataGrid.RowTemplate.Height = 21; 42 | this.WeathersDataGrid.Size = new System.Drawing.Size(539, 305); 43 | this.WeathersDataGrid.TabIndex = 0; 44 | // 45 | // WeatherListView 46 | // 47 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); 48 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 49 | this.ClientSize = new System.Drawing.Size(539, 305); 50 | this.Controls.Add(this.WeathersDataGrid); 51 | this.Name = "WeatherListView"; 52 | this.Text = "WeatherListView"; 53 | ((System.ComponentModel.ISupportInitialize)(this.WeathersDataGrid)).EndInit(); 54 | this.ResumeLayout(false); 55 | 56 | } 57 | 58 | #endregion 59 | 60 | private System.Windows.Forms.DataGridView WeathersDataGrid; 61 | } 62 | } -------------------------------------------------------------------------------- /DDD.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.32112.339 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DDD.WinForm", "DDD.WinForm\DDD.WinForm.csproj", "{9A4AE28C-86EE-4540-A14D-8ED616ABB499}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DDD.Infrastructure", "DDD.Infrastructure\DDD.Infrastructure.csproj", "{6DE6357E-7563-4E71-AAF3-50334E3BE85D}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DDD.Domain", "DDD.Domain\DDD.Domain.csproj", "{96953B4B-CF64-4C86-9474-2920A946C948}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DDDTest.Tests", "DDDTest.Tests\DDDTest.Tests.csproj", "{60C84ACC-6124-449A-8C1F-F2E26E6EFE02}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {9A4AE28C-86EE-4540-A14D-8ED616ABB499}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {9A4AE28C-86EE-4540-A14D-8ED616ABB499}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {9A4AE28C-86EE-4540-A14D-8ED616ABB499}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {9A4AE28C-86EE-4540-A14D-8ED616ABB499}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {6DE6357E-7563-4E71-AAF3-50334E3BE85D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {6DE6357E-7563-4E71-AAF3-50334E3BE85D}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {6DE6357E-7563-4E71-AAF3-50334E3BE85D}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {6DE6357E-7563-4E71-AAF3-50334E3BE85D}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {96953B4B-CF64-4C86-9474-2920A946C948}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {96953B4B-CF64-4C86-9474-2920A946C948}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {96953B4B-CF64-4C86-9474-2920A946C948}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {96953B4B-CF64-4C86-9474-2920A946C948}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {60C84ACC-6124-449A-8C1F-F2E26E6EFE02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {60C84ACC-6124-449A-8C1F-F2E26E6EFE02}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {60C84ACC-6124-449A-8C1F-F2E26E6EFE02}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {60C84ACC-6124-449A-8C1F-F2E26E6EFE02}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {139A8112-452C-4246-924C-195048D26C89} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /DDD.WinForm/ViewModels/WeatherLatestViewModel.cs: -------------------------------------------------------------------------------- 1 | using DDD.Domain.Repositories; 2 | using System; 3 | using DDD.Infrastructure.SQLite; 4 | using System.ComponentModel; 5 | using DDD.Domain.Entities; 6 | 7 | namespace DDD.WinForm.ViewModels 8 | { 9 | public class WeatherLatestViewModel : ViewModelBase 10 | { 11 | private IWeatherRepository _weather; 12 | private IAreasRepository _areas; 13 | 14 | public WeatherLatestViewModel() 15 | : this(new WeatherSQLite(), new AreasSQLite()) 16 | { 17 | } 18 | 19 | // 抽象に依存させて中身を入れ替える 20 | public WeatherLatestViewModel( 21 | IWeatherRepository weather, 22 | IAreasRepository areas) 23 | { 24 | _weather = weather; 25 | _areas = areas; 26 | 27 | foreach (var area in _areas.GetData()) 28 | { 29 | Areas.Add(new AreaEntity(area.AreaId, area.AreaName)); 30 | } 31 | } 32 | 33 | private object _selectedAreaId; 34 | public object SelectedAreaId 35 | { 36 | get { return _selectedAreaId; } 37 | set 38 | { 39 | SetProperty(ref _selectedAreaId, value); 40 | } 41 | } 42 | 43 | private string _dataDateText = string.Empty; 44 | public string DataDateText 45 | { 46 | get { return _dataDateText; } 47 | set 48 | { 49 | SetProperty(ref _dataDateText, value); 50 | } 51 | } 52 | 53 | private string _conditionText = string.Empty; 54 | public string ConditionText 55 | { 56 | get { return _conditionText; } 57 | set 58 | { 59 | SetProperty(ref _conditionText, value); 60 | } 61 | } 62 | 63 | private string _temperatureText = string.Empty; 64 | public string TemperatureText 65 | { 66 | get { return _temperatureText; } 67 | set 68 | { 69 | SetProperty(ref _temperatureText, value); 70 | } 71 | } 72 | 73 | public BindingList Areas { get; set; } 74 | = new BindingList(); 75 | 76 | public void Search() 77 | { 78 | var entity = _weather.GetLatest(Convert.ToInt32(_selectedAreaId)); 79 | if (entity == null) 80 | { 81 | DataDateText = string.Empty; 82 | ConditionText = string.Empty; 83 | TemperatureText = string.Empty; 84 | return; 85 | } 86 | 87 | DataDateText = entity.DataDate.ToString(); 88 | ConditionText = entity.Condition.DisplayValue; 89 | TemperatureText = entity.Temperature.DisplayValueWithUnitSpace; 90 | 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /DDD.WinForm/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // このコードはツールによって生成されました。 4 | // ランタイム バージョン:4.0.30319.42000 5 | // 6 | // このファイルへの変更は、以下の状況下で不正な動作の原因になったり、 7 | // コードが再生成されるときに損失したりします 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace DDD.WinForm.Properties 12 | { 13 | 14 | 15 | /// 16 | /// ローカライズされた文字列などを検索するための、厳密に型指定されたリソース クラスです。 17 | /// 18 | // このクラスは StronglyTypedResourceBuilder クラスが ResGen 19 | // または Visual Studio のようなツールを使用して自動生成されました。 20 | // メンバーを追加または削除するには、.ResX ファイルを編集して、/str オプションと共に 21 | // ResGen を実行し直すか、または VS プロジェクトをリビルドします。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// このクラスで使用されるキャッシュされた ResourceManager インスタンスを返します。 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DDD.WinForm.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// すべてについて、現在のスレッドの CurrentUICulture プロパティをオーバーライドします 56 | /// 現在のスレッドの CurrentUICulture プロパティをオーバーライドします。 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /DDD.Domain/DDD.Domain.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {96953B4B-CF64-4C86-9474-2920A946C948} 8 | Library 9 | Properties 10 | DDD.Domain 11 | DDD.Domain 12 | v4.7.2 13 | 512 14 | true 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /DDD.Infrastructure/SQLite/WeatherSQLite.cs: -------------------------------------------------------------------------------- 1 | using DDD.Domain.Entities; 2 | using DDD.Domain.Repositories; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Data.SQLite; 6 | 7 | namespace DDD.Infrastructure.SQLite 8 | { 9 | public class WeatherSQLite : IWeatherRepository 10 | { 11 | public WeatherEntity GetLatest(int areaId) 12 | { 13 | string sql = @" 14 | select DataDate, 15 | Condition, 16 | Temperature 17 | from Weather 18 | where AreaId = @AreaId 19 | order by DataDate desc 20 | LIMIT 1 21 | "; 22 | 23 | return SQLiteHelper.QuerySingle( 24 | sql, 25 | new List 26 | { 27 | new SQLiteParameter("@AreaId", areaId) 28 | }.ToArray(), 29 | reader => 30 | { 31 | return new WeatherEntity( 32 | areaId, 33 | Convert.ToDateTime(reader["DataDate"]), 34 | Convert.ToInt32(reader["Condition"]), 35 | Convert.ToSingle(reader["Temperature"])); 36 | }, 37 | null); 38 | } 39 | 40 | public IReadOnlyList GetData() 41 | { 42 | string sql = @" 43 | select A.AreaId, 44 | ifnull(B.AreaName,'') as AreaName, 45 | A.DataDate, 46 | A.Condition, 47 | A.Temperature 48 | from Weather A 49 | left outer join Areas B 50 | on A.AreaId = B.AreaId 51 | "; 52 | 53 | return SQLiteHelper.Query(sql, 54 | reader => 55 | { 56 | return new WeatherEntity( 57 | Convert.ToInt32(reader["AreaId"]), 58 | Convert.ToString(reader["AreaName"]), 59 | Convert.ToDateTime(reader["DataDate"]), 60 | Convert.ToInt32(reader["Condition"]), 61 | Convert.ToSingle(reader["Temperature"])); 62 | }); 63 | } 64 | 65 | public void Save(WeatherEntity weather) 66 | { 67 | string insert = @" 68 | insert into Weather 69 | (AreaId,DataDate,Condition,Temperature) 70 | values 71 | (@AreaId,@DataDate,@Condition,@Temperature) 72 | "; 73 | 74 | string update = @" 75 | update Weather 76 | set Condition = @Condition, 77 | Temperature = @Temperature 78 | where AreaId = @AreaId 79 | and DataDate = @DataDate 80 | "; 81 | 82 | var args = new List 83 | { 84 | new SQLiteParameter("@AreaId", weather.AreaId.Value), 85 | new SQLiteParameter("@DataDate", weather.DataDate), 86 | new SQLiteParameter("@Condition", weather.Condition.Value), 87 | new SQLiteParameter("@Temperature", weather.Temperature.Value), 88 | 89 | }; 90 | 91 | SQLiteHelper.Execute(insert, update, args.ToArray()); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /DDDTest.Tests/WeatherLatestViewModelTest.cs: -------------------------------------------------------------------------------- 1 | using DDD.Domain.Entities; 2 | using DDD.Domain.Repositories; 3 | using DDD.WinForm.ViewModels; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | using Moq; 6 | using System; 7 | using System.Collections.Generic; 8 | 9 | namespace DDDTest.Tests 10 | { 11 | [TestClass] 12 | public class WeatherLatestViewModelTest 13 | { 14 | [TestMethod] 15 | public void シナリオ() 16 | { 17 | // Moq 18 | var weatherMock = new Mock(); 19 | 20 | weatherMock.Setup(x => x.GetLatest(1)).Returns( 21 | new WeatherEntity( 22 | 1, 23 | Convert.ToDateTime("2018/01/01 12:34:56"), 24 | 2, 25 | 12.3f 26 | ) 27 | ); 28 | 29 | weatherMock.Setup(x => x.GetLatest(2)).Returns( 30 | new WeatherEntity( 31 | 2, 32 | Convert.ToDateTime("2018/01/02 12:34:56"), 33 | 1, 34 | 22.123f 35 | ) 36 | ); 37 | 38 | var areasMock = new Mock(); 39 | 40 | var areas = new List(); 41 | areas.Add(new AreaEntity(1, "東京")); 42 | areas.Add(new AreaEntity(2, "神戸")); 43 | areas.Add(new AreaEntity(3, "沖縄")); 44 | areasMock.Setup(x => x.GetData()).Returns(areas); 45 | 46 | var viewModel = new WeatherLatestViewModel( 47 | weatherMock.Object, 48 | areasMock.Object); 49 | Assert.IsNull(viewModel.SelectedAreaId); 50 | Assert.AreEqual("", viewModel.DataDateText); 51 | Assert.AreEqual("", viewModel.ConditionText); 52 | Assert.AreEqual("", viewModel.TemperatureText); 53 | Assert.AreEqual(3, viewModel.Areas.Count); 54 | Assert.AreEqual(1, viewModel.Areas[0].AreaId); 55 | Assert.AreEqual("東京", viewModel.Areas[0].AreaName); 56 | Assert.AreEqual(2, viewModel.Areas[1].AreaId); 57 | Assert.AreEqual("神戸", viewModel.Areas[1].AreaName); 58 | 59 | viewModel.SelectedAreaId = 1; 60 | viewModel.Search(); 61 | Assert.AreEqual(1, viewModel.SelectedAreaId); 62 | Assert.AreEqual("2018/01/01 12:34:56", viewModel.DataDateText); 63 | Assert.AreEqual("曇り", viewModel.ConditionText); 64 | Assert.AreEqual("12.30 ℃", viewModel.TemperatureText); 65 | 66 | viewModel.SelectedAreaId = 2; 67 | viewModel.Search(); 68 | Assert.AreEqual(2, viewModel.SelectedAreaId); 69 | Assert.AreEqual("2018/01/02 12:34:56", viewModel.DataDateText); 70 | Assert.AreEqual("晴れ", viewModel.ConditionText); 71 | Assert.AreEqual("22.12 ℃", viewModel.TemperatureText); 72 | 73 | viewModel.SelectedAreaId = 3; 74 | viewModel.Search(); 75 | Assert.AreEqual(3, viewModel.SelectedAreaId); 76 | Assert.AreEqual("", viewModel.DataDateText); 77 | Assert.AreEqual("", viewModel.ConditionText); 78 | Assert.AreEqual("", viewModel.TemperatureText); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /DDD.Infrastructure/SQLite/SQLiteHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.SQLite; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DDD.Infrastructure.SQLite 9 | { 10 | internal class SQLiteHelper 11 | { 12 | internal const string ConnectionString = @"Data Source=C:\Users\admin\task2\DDD\DDD.db;Version=3;"; 13 | 14 | 15 | internal static IReadOnlyList Query( 16 | string sql, 17 | Func createEntity) 18 | { 19 | return Query(sql, null, createEntity); 20 | } 21 | 22 | internal static IReadOnlyList Query( 23 | string sql, 24 | SQLiteParameter[] parameters, 25 | Func createEntity) 26 | { 27 | var result = new List(); 28 | using (var connection = new SQLiteConnection(SQLiteHelper.ConnectionString)) 29 | using (var command = new SQLiteCommand(sql, connection)) 30 | { 31 | connection.Open(); 32 | if (parameters != null) 33 | { 34 | command.Parameters.AddRange(parameters); 35 | } 36 | using (var reader = command.ExecuteReader()) 37 | { 38 | while (reader.Read()) 39 | { 40 | result.Add(createEntity(reader)); 41 | } 42 | } 43 | } 44 | 45 | return result; 46 | } 47 | 48 | internal static T QuerySingle( 49 | string sql, 50 | Func createEntity, 51 | T nullEntity) 52 | { 53 | return QuerySingle(sql, null, createEntity, nullEntity); 54 | } 55 | 56 | internal static T QuerySingle( 57 | string sql, 58 | SQLiteParameter[] parameters, 59 | Func createEntity, 60 | T nullEntity) 61 | { 62 | using (var connection = new SQLiteConnection(SQLiteHelper.ConnectionString)) 63 | using (var command = new SQLiteCommand(sql, connection)) 64 | { 65 | connection.Open(); 66 | if (parameters != null) 67 | { 68 | command.Parameters.AddRange(parameters); 69 | } 70 | using (var reader = command.ExecuteReader()) 71 | { 72 | while (reader.Read()) 73 | { 74 | return createEntity(reader); 75 | } 76 | } 77 | } 78 | 79 | return nullEntity; 80 | } 81 | 82 | internal static void Execute( 83 | string insert, 84 | string update, 85 | SQLiteParameter[] parameters) 86 | { 87 | using (var connection = new SQLiteConnection(SQLiteHelper.ConnectionString)) 88 | using (var command = new SQLiteCommand(update, connection)) 89 | { 90 | connection.Open(); 91 | if (parameters != null) 92 | { 93 | command.Parameters.AddRange(parameters); 94 | } 95 | 96 | if (command.ExecuteNonQuery() < 1) 97 | { 98 | command.CommandText = insert; 99 | command.ExecuteNonQuery(); 100 | } 101 | } 102 | } 103 | 104 | internal static void Execute( 105 | string sql, 106 | SQLiteParameter[] parameters) 107 | { 108 | using (var connection = new SQLiteConnection(SQLiteHelper.ConnectionString)) 109 | using (var command = new SQLiteCommand(sql, connection)) 110 | { 111 | connection.Open(); 112 | if (parameters != null) 113 | { 114 | command.Parameters.AddRange(parameters); 115 | } 116 | 117 | command.ExecuteNonQuery(); 118 | } 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /DDD.WinForm/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /DDD.Infrastructure/DDD.Infrastructure.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {6DE6357E-7563-4E71-AAF3-50334E3BE85D} 9 | Library 10 | Properties 11 | DDD.Infrastructure 12 | DDD.Infrastructure 13 | v4.7.2 14 | 512 15 | true 16 | 17 | 18 | 19 | 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | 28 | 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.dll 39 | 40 | 41 | ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.SqlServer.dll 42 | 43 | 44 | 45 | 46 | 47 | ..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.115.5\lib\net46\System.Data.SQLite.dll 48 | 49 | 50 | ..\packages\System.Data.SQLite.EF6.1.0.115.5\lib\net46\System.Data.SQLite.EF6.dll 51 | 52 | 53 | ..\packages\System.Data.SQLite.Linq.1.0.115.5\lib\net46\System.Data.SQLite.Linq.dll 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | {96953b4b-cf64-4c86-9474-2920a946c948} 71 | DDD.Domain 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | このプロジェクトは、このコンピューター上にない NuGet パッケージを参照しています。それらのパッケージをダウンロードするには、[NuGet パッケージの復元] を使用します。詳細については、http://go.microsoft.com/fwlink/?LinkID=322105 を参照してください。見つからないファイルは {0} です。 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /DDD.WinForm/Views/WeatherLatestView.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /DDD.WinForm/Views/WeatherListView.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /DDD.WinForm/Views/WeatherSaveView.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /DDDTest.Tests/DDDTest.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {60C84ACC-6124-449A-8C1F-F2E26E6EFE02} 9 | Library 10 | Properties 11 | DDDTest.Tests 12 | DDDTest.Tests 13 | v4.7.2 14 | 512 15 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 16 | 15.0 17 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 18 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 19 | False 20 | UnitTest 21 | 22 | 23 | 24 | 25 | true 26 | full 27 | false 28 | bin\Debug\ 29 | DEBUG;TRACE 30 | prompt 31 | 4 32 | 33 | 34 | pdbonly 35 | true 36 | bin\Release\ 37 | TRACE 38 | prompt 39 | 4 40 | 41 | 42 | 43 | ..\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll 44 | 45 | 46 | 47 | ..\packages\MSTest.TestFramework.2.2.7\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll 48 | 49 | 50 | ..\packages\MSTest.TestFramework.2.2.7\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll 51 | 52 | 53 | ..\packages\Moq.4.16.1\lib\net45\Moq.dll 54 | 55 | 56 | 57 | 58 | 59 | 60 | ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll 61 | 62 | 63 | ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | {96953b4b-cf64-4c86-9474-2920a946c948} 80 | DDD.Domain 81 | 82 | 83 | {6de6357e-7563-4e71-aaf3-50334e3be85d} 84 | DDD.Infrastructure 85 | 86 | 87 | {9a4ae28c-86ee-4540-a14d-8ed616abb499} 88 | DDD.WinForm 89 | 90 | 91 | 92 | 93 | 94 | 95 | このプロジェクトは、このコンピューター上にない NuGet パッケージを参照しています。それらのパッケージをダウンロードするには、[NuGet パッケージの復元] を使用します。詳細については、http://go.microsoft.com/fwlink/?LinkID=322105 を参照してください。見つからないファイルは {0} です。 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /DDD.WinForm/Views/WeatherSaveView.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace DDD.WinForm.Views 2 | { 3 | partial class WeatherSaveView 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.SaveButton = new System.Windows.Forms.Button(); 32 | this.label1 = new System.Windows.Forms.Label(); 33 | this.AreaIdComboBox = new System.Windows.Forms.ComboBox(); 34 | this.label2 = new System.Windows.Forms.Label(); 35 | this.label3 = new System.Windows.Forms.Label(); 36 | this.label4 = new System.Windows.Forms.Label(); 37 | this.DateTimeTextBox = new System.Windows.Forms.DateTimePicker(); 38 | this.ConditionComboBox = new System.Windows.Forms.ComboBox(); 39 | this.TemperatureTextBox = new System.Windows.Forms.TextBox(); 40 | this.UnitLabel = new System.Windows.Forms.Label(); 41 | this.SuspendLayout(); 42 | // 43 | // SaveButton 44 | // 45 | this.SaveButton.Location = new System.Drawing.Point(12, 12); 46 | this.SaveButton.Name = "SaveButton"; 47 | this.SaveButton.Size = new System.Drawing.Size(75, 23); 48 | this.SaveButton.TabIndex = 0; 49 | this.SaveButton.Text = "Save"; 50 | this.SaveButton.UseVisualStyleBackColor = true; 51 | // 52 | // label1 53 | // 54 | this.label1.AutoSize = true; 55 | this.label1.Location = new System.Drawing.Point(12, 62); 56 | this.label1.Name = "label1"; 57 | this.label1.Size = new System.Drawing.Size(29, 12); 58 | this.label1.TabIndex = 1; 59 | this.label1.Text = "地域"; 60 | // 61 | // AreaIdComboBox 62 | // 63 | this.AreaIdComboBox.FormattingEnabled = true; 64 | this.AreaIdComboBox.Location = new System.Drawing.Point(94, 54); 65 | this.AreaIdComboBox.Name = "AreaIdComboBox"; 66 | this.AreaIdComboBox.Size = new System.Drawing.Size(121, 20); 67 | this.AreaIdComboBox.TabIndex = 2; 68 | // 69 | // label2 70 | // 71 | this.label2.AutoSize = true; 72 | this.label2.Location = new System.Drawing.Point(12, 99); 73 | this.label2.Name = "label2"; 74 | this.label2.Size = new System.Drawing.Size(29, 12); 75 | this.label2.TabIndex = 3; 76 | this.label2.Text = "日時"; 77 | // 78 | // label3 79 | // 80 | this.label3.AutoSize = true; 81 | this.label3.Location = new System.Drawing.Point(12, 136); 82 | this.label3.Name = "label3"; 83 | this.label3.Size = new System.Drawing.Size(29, 12); 84 | this.label3.TabIndex = 4; 85 | this.label3.Text = "状態"; 86 | // 87 | // label4 88 | // 89 | this.label4.AutoSize = true; 90 | this.label4.Location = new System.Drawing.Point(12, 174); 91 | this.label4.Name = "label4"; 92 | this.label4.Size = new System.Drawing.Size(29, 12); 93 | this.label4.TabIndex = 5; 94 | this.label4.Text = "温度"; 95 | // 96 | // DateTimeTextBox 97 | // 98 | this.DateTimeTextBox.CustomFormat = "yyy/MM/dd HH:mm:ss"; 99 | this.DateTimeTextBox.Format = System.Windows.Forms.DateTimePickerFormat.Custom; 100 | this.DateTimeTextBox.Location = new System.Drawing.Point(94, 94); 101 | this.DateTimeTextBox.Name = "DateTimeTextBox"; 102 | this.DateTimeTextBox.Size = new System.Drawing.Size(200, 19); 103 | this.DateTimeTextBox.TabIndex = 6; 104 | // 105 | // ConditionComboBox 106 | // 107 | this.ConditionComboBox.FormattingEnabled = true; 108 | this.ConditionComboBox.Location = new System.Drawing.Point(94, 133); 109 | this.ConditionComboBox.Name = "ConditionComboBox"; 110 | this.ConditionComboBox.Size = new System.Drawing.Size(121, 20); 111 | this.ConditionComboBox.TabIndex = 7; 112 | // 113 | // TemperatureTextBox 114 | // 115 | this.TemperatureTextBox.Location = new System.Drawing.Point(94, 171); 116 | this.TemperatureTextBox.Name = "TemperatureTextBox"; 117 | this.TemperatureTextBox.Size = new System.Drawing.Size(100, 19); 118 | this.TemperatureTextBox.TabIndex = 8; 119 | // 120 | // UnitLabel 121 | // 122 | this.UnitLabel.AutoSize = true; 123 | this.UnitLabel.Location = new System.Drawing.Point(200, 174); 124 | this.UnitLabel.Name = "UnitLabel"; 125 | this.UnitLabel.Size = new System.Drawing.Size(19, 12); 126 | this.UnitLabel.TabIndex = 9; 127 | this.UnitLabel.Text = "XX"; 128 | // 129 | // WeatherSaveView 130 | // 131 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); 132 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 133 | this.ClientSize = new System.Drawing.Size(339, 298); 134 | this.Controls.Add(this.UnitLabel); 135 | this.Controls.Add(this.TemperatureTextBox); 136 | this.Controls.Add(this.ConditionComboBox); 137 | this.Controls.Add(this.DateTimeTextBox); 138 | this.Controls.Add(this.label4); 139 | this.Controls.Add(this.label3); 140 | this.Controls.Add(this.label2); 141 | this.Controls.Add(this.AreaIdComboBox); 142 | this.Controls.Add(this.label1); 143 | this.Controls.Add(this.SaveButton); 144 | this.Name = "WeatherSaveView"; 145 | this.Text = "WeatherSaveView"; 146 | this.ResumeLayout(false); 147 | this.PerformLayout(); 148 | 149 | } 150 | 151 | #endregion 152 | 153 | private System.Windows.Forms.Button SaveButton; 154 | private System.Windows.Forms.Label label1; 155 | private System.Windows.Forms.ComboBox AreaIdComboBox; 156 | private System.Windows.Forms.Label label2; 157 | private System.Windows.Forms.Label label3; 158 | private System.Windows.Forms.Label label4; 159 | private System.Windows.Forms.DateTimePicker DateTimeTextBox; 160 | private System.Windows.Forms.ComboBox ConditionComboBox; 161 | private System.Windows.Forms.TextBox TemperatureTextBox; 162 | private System.Windows.Forms.Label UnitLabel; 163 | } 164 | } -------------------------------------------------------------------------------- /DDD.WinForm/Views/WeatherLatestView.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace DDD.WinForm 2 | { 3 | partial class WeatherLatestView 4 | { 5 | /// 6 | /// 必要なデザイナー変数です。 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// 使用中のリソースをすべてクリーンアップします。 12 | /// 13 | /// マネージド リソースを破棄する場合は true を指定し、その他の場合は false を指定します。 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows フォーム デザイナーで生成されたコード 24 | 25 | /// 26 | /// デザイナー サポートに必要なメソッドです。このメソッドの内容を 27 | /// コード エディターで変更しないでください。 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.label1 = new System.Windows.Forms.Label(); 32 | this.label2 = new System.Windows.Forms.Label(); 33 | this.label3 = new System.Windows.Forms.Label(); 34 | this.label4 = new System.Windows.Forms.Label(); 35 | this.DataDateLabel = new System.Windows.Forms.Label(); 36 | this.ConditionLabel = new System.Windows.Forms.Label(); 37 | this.TemperatureLabel = new System.Windows.Forms.Label(); 38 | this.LatestButton = new System.Windows.Forms.Button(); 39 | this.AreasComboBox = new System.Windows.Forms.ComboBox(); 40 | this.button1 = new System.Windows.Forms.Button(); 41 | this.button2 = new System.Windows.Forms.Button(); 42 | this.SuspendLayout(); 43 | // 44 | // label1 45 | // 46 | this.label1.AutoSize = true; 47 | this.label1.Location = new System.Drawing.Point(12, 56); 48 | this.label1.Name = "label1"; 49 | this.label1.Size = new System.Drawing.Size(29, 12); 50 | this.label1.TabIndex = 0; 51 | this.label1.Text = "地域"; 52 | // 53 | // label2 54 | // 55 | this.label2.AutoSize = true; 56 | this.label2.Location = new System.Drawing.Point(12, 85); 57 | this.label2.Name = "label2"; 58 | this.label2.Size = new System.Drawing.Size(29, 12); 59 | this.label2.TabIndex = 1; 60 | this.label2.Text = "日時"; 61 | // 62 | // label3 63 | // 64 | this.label3.AutoSize = true; 65 | this.label3.Location = new System.Drawing.Point(12, 118); 66 | this.label3.Name = "label3"; 67 | this.label3.Size = new System.Drawing.Size(29, 12); 68 | this.label3.TabIndex = 2; 69 | this.label3.Text = "状態"; 70 | // 71 | // label4 72 | // 73 | this.label4.AutoSize = true; 74 | this.label4.Location = new System.Drawing.Point(12, 153); 75 | this.label4.Name = "label4"; 76 | this.label4.Size = new System.Drawing.Size(29, 12); 77 | this.label4.TabIndex = 3; 78 | this.label4.Text = "温度"; 79 | // 80 | // DataDateLabel 81 | // 82 | this.DataDateLabel.AutoSize = true; 83 | this.DataDateLabel.Location = new System.Drawing.Point(85, 85); 84 | this.DataDateLabel.Name = "DataDateLabel"; 85 | this.DataDateLabel.Size = new System.Drawing.Size(35, 12); 86 | this.DataDateLabel.TabIndex = 4; 87 | this.DataDateLabel.Text = "label5"; 88 | // 89 | // ConditionLabel 90 | // 91 | this.ConditionLabel.AutoSize = true; 92 | this.ConditionLabel.Location = new System.Drawing.Point(85, 118); 93 | this.ConditionLabel.Name = "ConditionLabel"; 94 | this.ConditionLabel.Size = new System.Drawing.Size(35, 12); 95 | this.ConditionLabel.TabIndex = 5; 96 | this.ConditionLabel.Text = "label6"; 97 | // 98 | // TemperatureLabel 99 | // 100 | this.TemperatureLabel.AutoSize = true; 101 | this.TemperatureLabel.Location = new System.Drawing.Point(85, 153); 102 | this.TemperatureLabel.Name = "TemperatureLabel"; 103 | this.TemperatureLabel.Size = new System.Drawing.Size(35, 12); 104 | this.TemperatureLabel.TabIndex = 6; 105 | this.TemperatureLabel.Text = "label7"; 106 | // 107 | // LatestButton 108 | // 109 | this.LatestButton.Location = new System.Drawing.Point(214, 53); 110 | this.LatestButton.Name = "LatestButton"; 111 | this.LatestButton.Size = new System.Drawing.Size(75, 23); 112 | this.LatestButton.TabIndex = 8; 113 | this.LatestButton.Text = "直近地"; 114 | this.LatestButton.UseVisualStyleBackColor = true; 115 | this.LatestButton.Click += new System.EventHandler(this.LatestButton_Click); 116 | // 117 | // AreasComboBox 118 | // 119 | this.AreasComboBox.FormattingEnabled = true; 120 | this.AreasComboBox.Location = new System.Drawing.Point(87, 53); 121 | this.AreasComboBox.Name = "AreasComboBox"; 122 | this.AreasComboBox.Size = new System.Drawing.Size(121, 20); 123 | this.AreasComboBox.TabIndex = 9; 124 | // 125 | // button1 126 | // 127 | this.button1.Location = new System.Drawing.Point(14, 10); 128 | this.button1.Name = "button1"; 129 | this.button1.Size = new System.Drawing.Size(106, 23); 130 | this.button1.TabIndex = 10; 131 | this.button1.Text = "List"; 132 | this.button1.UseVisualStyleBackColor = true; 133 | this.button1.Click += new System.EventHandler(this.button1_Click); 134 | // 135 | // button2 136 | // 137 | this.button2.Location = new System.Drawing.Point(126, 10); 138 | this.button2.Name = "button2"; 139 | this.button2.Size = new System.Drawing.Size(106, 23); 140 | this.button2.TabIndex = 11; 141 | this.button2.Text = "追加"; 142 | this.button2.UseVisualStyleBackColor = true; 143 | this.button2.Click += new System.EventHandler(this.button2_Click); 144 | // 145 | // WeatherLatestView 146 | // 147 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); 148 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 149 | this.ClientSize = new System.Drawing.Size(308, 261); 150 | this.Controls.Add(this.button2); 151 | this.Controls.Add(this.button1); 152 | this.Controls.Add(this.AreasComboBox); 153 | this.Controls.Add(this.LatestButton); 154 | this.Controls.Add(this.TemperatureLabel); 155 | this.Controls.Add(this.ConditionLabel); 156 | this.Controls.Add(this.DataDateLabel); 157 | this.Controls.Add(this.label4); 158 | this.Controls.Add(this.label3); 159 | this.Controls.Add(this.label2); 160 | this.Controls.Add(this.label1); 161 | this.Name = "WeatherLatestView"; 162 | this.Text = "WeatherLatestView"; 163 | this.ResumeLayout(false); 164 | this.PerformLayout(); 165 | 166 | } 167 | 168 | #endregion 169 | 170 | private System.Windows.Forms.Label label1; 171 | private System.Windows.Forms.Label label2; 172 | private System.Windows.Forms.Label label3; 173 | private System.Windows.Forms.Label label4; 174 | private System.Windows.Forms.Label DataDateLabel; 175 | private System.Windows.Forms.Label ConditionLabel; 176 | private System.Windows.Forms.Label TemperatureLabel; 177 | private System.Windows.Forms.Button LatestButton; 178 | private System.Windows.Forms.ComboBox AreasComboBox; 179 | private System.Windows.Forms.Button button1; 180 | private System.Windows.Forms.Button button2; 181 | } 182 | } 183 | 184 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # Tye 66 | .tye/ 67 | 68 | # ASP.NET Scaffolding 69 | ScaffoldingReadMe.txt 70 | 71 | # StyleCop 72 | StyleCopReport.xml 73 | 74 | # Files built by Visual Studio 75 | *_i.c 76 | *_p.c 77 | *_h.h 78 | *.ilk 79 | *.meta 80 | *.obj 81 | *.iobj 82 | *.pch 83 | *.pdb 84 | *.ipdb 85 | *.pgc 86 | *.pgd 87 | *.rsp 88 | *.sbr 89 | *.tlb 90 | *.tli 91 | *.tlh 92 | *.tmp 93 | *.tmp_proj 94 | *_wpftmp.csproj 95 | *.log 96 | *.vspscc 97 | *.vssscc 98 | .builds 99 | *.pidb 100 | *.svclog 101 | *.scc 102 | 103 | # Chutzpah Test files 104 | _Chutzpah* 105 | 106 | # Visual C++ cache files 107 | ipch/ 108 | *.aps 109 | *.ncb 110 | *.opendb 111 | *.opensdf 112 | *.sdf 113 | *.cachefile 114 | *.VC.db 115 | *.VC.VC.opendb 116 | 117 | # Visual Studio profiler 118 | *.psess 119 | *.vsp 120 | *.vspx 121 | *.sap 122 | 123 | # Visual Studio Trace Files 124 | *.e2e 125 | 126 | # TFS 2012 Local Workspace 127 | $tf/ 128 | 129 | # Guidance Automation Toolkit 130 | *.gpState 131 | 132 | # ReSharper is a .NET coding add-in 133 | _ReSharper*/ 134 | *.[Rr]e[Ss]harper 135 | *.DotSettings.user 136 | 137 | # TeamCity is a build add-in 138 | _TeamCity* 139 | 140 | # DotCover is a Code Coverage Tool 141 | *.dotCover 142 | 143 | # AxoCover is a Code Coverage Tool 144 | .axoCover/* 145 | !.axoCover/settings.json 146 | 147 | # Coverlet is a free, cross platform Code Coverage Tool 148 | coverage*.json 149 | coverage*.xml 150 | coverage*.info 151 | 152 | # Visual Studio code coverage results 153 | *.coverage 154 | *.coveragexml 155 | 156 | # NCrunch 157 | _NCrunch_* 158 | .*crunch*.local.xml 159 | nCrunchTemp_* 160 | 161 | # MightyMoose 162 | *.mm.* 163 | AutoTest.Net/ 164 | 165 | # Web workbench (sass) 166 | .sass-cache/ 167 | 168 | # Installshield output folder 169 | [Ee]xpress/ 170 | 171 | # DocProject is a documentation generator add-in 172 | DocProject/buildhelp/ 173 | DocProject/Help/*.HxT 174 | DocProject/Help/*.HxC 175 | DocProject/Help/*.hhc 176 | DocProject/Help/*.hhk 177 | DocProject/Help/*.hhp 178 | DocProject/Help/Html2 179 | DocProject/Help/html 180 | 181 | # Click-Once directory 182 | publish/ 183 | 184 | # Publish Web Output 185 | *.[Pp]ublish.xml 186 | *.azurePubxml 187 | # Note: Comment the next line if you want to checkin your web deploy settings, 188 | # but database connection strings (with potential passwords) will be unencrypted 189 | *.pubxml 190 | *.publishproj 191 | 192 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 193 | # checkin your Azure Web App publish settings, but sensitive information contained 194 | # in these scripts will be unencrypted 195 | PublishScripts/ 196 | 197 | # NuGet Packages 198 | *.nupkg 199 | # NuGet Symbol Packages 200 | *.snupkg 201 | # The packages folder can be ignored because of Package Restore 202 | **/[Pp]ackages/* 203 | # except build/, which is used as an MSBuild target. 204 | !**/[Pp]ackages/build/ 205 | # Uncomment if necessary however generally it will be regenerated when needed 206 | #!**/[Pp]ackages/repositories.config 207 | # NuGet v3's project.json files produces more ignorable files 208 | *.nuget.props 209 | *.nuget.targets 210 | 211 | # Microsoft Azure Build Output 212 | csx/ 213 | *.build.csdef 214 | 215 | # Microsoft Azure Emulator 216 | ecf/ 217 | rcf/ 218 | 219 | # Windows Store app package directories and files 220 | AppPackages/ 221 | BundleArtifacts/ 222 | Package.StoreAssociation.xml 223 | _pkginfo.txt 224 | *.appx 225 | *.appxbundle 226 | *.appxupload 227 | 228 | # Visual Studio cache files 229 | # files ending in .cache can be ignored 230 | *.[Cc]ache 231 | # but keep track of directories ending in .cache 232 | !?*.[Cc]ache/ 233 | 234 | # Others 235 | ClientBin/ 236 | ~$* 237 | *~ 238 | *.dbmdl 239 | *.dbproj.schemaview 240 | *.jfm 241 | *.pfx 242 | *.publishsettings 243 | orleans.codegen.cs 244 | 245 | # Including strong name files can present a security risk 246 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 247 | #*.snk 248 | 249 | # Since there are multiple workflows, uncomment next line to ignore bower_components 250 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 251 | #bower_components/ 252 | 253 | # RIA/Silverlight projects 254 | Generated_Code/ 255 | 256 | # Backup & report files from converting an old project file 257 | # to a newer Visual Studio version. Backup files are not needed, 258 | # because we have git ;-) 259 | _UpgradeReport_Files/ 260 | Backup*/ 261 | UpgradeLog*.XML 262 | UpgradeLog*.htm 263 | ServiceFabricBackup/ 264 | *.rptproj.bak 265 | 266 | # SQL Server files 267 | *.mdf 268 | *.ldf 269 | *.ndf 270 | 271 | # Business Intelligence projects 272 | *.rdl.data 273 | *.bim.layout 274 | *.bim_*.settings 275 | *.rptproj.rsuser 276 | *- [Bb]ackup.rdl 277 | *- [Bb]ackup ([0-9]).rdl 278 | *- [Bb]ackup ([0-9][0-9]).rdl 279 | 280 | # Microsoft Fakes 281 | FakesAssemblies/ 282 | 283 | # GhostDoc plugin setting file 284 | *.GhostDoc.xml 285 | 286 | # Node.js Tools for Visual Studio 287 | .ntvs_analysis.dat 288 | node_modules/ 289 | 290 | # Visual Studio 6 build log 291 | *.plg 292 | 293 | # Visual Studio 6 workspace options file 294 | *.opt 295 | 296 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 297 | *.vbw 298 | 299 | # Visual Studio LightSwitch build output 300 | **/*.HTMLClient/GeneratedArtifacts 301 | **/*.DesktopClient/GeneratedArtifacts 302 | **/*.DesktopClient/ModelManifest.xml 303 | **/*.Server/GeneratedArtifacts 304 | **/*.Server/ModelManifest.xml 305 | _Pvt_Extensions 306 | 307 | # Paket dependency manager 308 | .paket/paket.exe 309 | paket-files/ 310 | 311 | # FAKE - F# Make 312 | .fake/ 313 | 314 | # CodeRush personal settings 315 | .cr/personal 316 | 317 | # Python Tools for Visual Studio (PTVS) 318 | __pycache__/ 319 | *.pyc 320 | 321 | # Cake - Uncomment if you are using it 322 | # tools/** 323 | # !tools/packages.config 324 | 325 | # Tabs Studio 326 | *.tss 327 | 328 | # Telerik's JustMock configuration file 329 | *.jmconfig 330 | 331 | # BizTalk build output 332 | *.btp.cs 333 | *.btm.cs 334 | *.odx.cs 335 | *.xsd.cs 336 | 337 | # OpenCover UI analysis results 338 | OpenCover/ 339 | 340 | # Azure Stream Analytics local run output 341 | ASALocalRun/ 342 | 343 | # MSBuild Binary and Structured Log 344 | *.binlog 345 | 346 | # NVidia Nsight GPU debugger configuration file 347 | *.nvuser 348 | 349 | # MFractors (Xamarin productivity tool) working folder 350 | .mfractor/ 351 | 352 | # Local History for Visual Studio 353 | .localhistory/ 354 | 355 | # BeatPulse healthcheck temp database 356 | healthchecksdb 357 | 358 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 359 | MigrationBackup/ 360 | 361 | # Ionide (cross platform F# VS Code tools) working folder 362 | .ionide/ 363 | 364 | # Fody - auto-generated XML schema 365 | FodyWeavers.xsd 366 | 367 | ## 368 | ## Visual studio for Mac 369 | ## 370 | 371 | 372 | # globs 373 | Makefile.in 374 | *.userprefs 375 | *.usertasks 376 | config.make 377 | config.status 378 | aclocal.m4 379 | install-sh 380 | autom4te.cache/ 381 | *.tar.gz 382 | tarballs/ 383 | test-results/ 384 | 385 | # Mac bundle stuff 386 | *.dmg 387 | *.app 388 | 389 | # content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore 390 | # General 391 | .DS_Store 392 | .AppleDouble 393 | .LSOverride 394 | 395 | # Icon must end with two \r 396 | Icon 397 | 398 | 399 | # Thumbnails 400 | ._* 401 | 402 | # Files that might appear in the root of a volume 403 | .DocumentRevisions-V100 404 | .fseventsd 405 | .Spotlight-V100 406 | .TemporaryItems 407 | .Trashes 408 | .VolumeIcon.icns 409 | .com.apple.timemachine.donotpresent 410 | 411 | # Directories potentially created on remote AFP share 412 | .AppleDB 413 | .AppleDesktop 414 | Network Trash Folder 415 | Temporary Items 416 | .apdisk 417 | 418 | # content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore 419 | # Windows thumbnail cache files 420 | Thumbs.db 421 | ehthumbs.db 422 | ehthumbs_vista.db 423 | 424 | # Dump file 425 | *.stackdump 426 | 427 | # Folder config file 428 | [Dd]esktop.ini 429 | 430 | # Recycle Bin used on file shares 431 | $RECYCLE.BIN/ 432 | 433 | # Windows Installer files 434 | *.cab 435 | *.msi 436 | *.msix 437 | *.msm 438 | *.msp 439 | 440 | # Windows shortcuts 441 | *.lnk 442 | 443 | # JetBrains Rider 444 | .idea/ 445 | *.sln.iml 446 | 447 | ## 448 | ## Visual Studio Code 449 | ## 450 | .vscode/* 451 | !.vscode/settings.json 452 | !.vscode/tasks.json 453 | !.vscode/launch.json 454 | !.vscode/extensions.json 455 | -------------------------------------------------------------------------------- /DDD.WinForm/DDD.WinForm.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {9A4AE28C-86EE-4540-A14D-8ED616ABB499} 9 | WinExe 10 | DDD.WinForm 11 | DDD.WinForm 12 | v4.7.2 13 | 512 14 | true 15 | true 16 | 17 | 18 | 19 | 20 | AnyCPU 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | 29 | 30 | AnyCPU 31 | pdbonly 32 | true 33 | bin\Release\ 34 | TRACE 35 | prompt 36 | 4 37 | 38 | 39 | 40 | ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.dll 41 | 42 | 43 | ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.SqlServer.dll 44 | 45 | 46 | ..\packages\Microsoft.Data.Sqlite.Core.6.0.1\lib\netstandard2.0\Microsoft.Data.Sqlite.dll 47 | 48 | 49 | ..\packages\SQLitePCLRaw.core.2.0.6\lib\netstandard2.0\SQLitePCLRaw.core.dll 50 | 51 | 52 | 53 | ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll 54 | 55 | 56 | 57 | 58 | ..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.115.5\lib\net46\System.Data.SQLite.dll 59 | 60 | 61 | ..\packages\System.Data.SQLite.EF6.1.0.115.5\lib\net46\System.Data.SQLite.EF6.dll 62 | 63 | 64 | ..\packages\System.Data.SQLite.Linq.1.0.115.5\lib\net46\System.Data.SQLite.Linq.dll 65 | 66 | 67 | ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll 68 | 69 | 70 | 71 | ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll 72 | 73 | 74 | ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | Form 94 | 95 | 96 | WeatherLatestView.cs 97 | 98 | 99 | 100 | 101 | Form 102 | 103 | 104 | WeatherListView.cs 105 | 106 | 107 | Form 108 | 109 | 110 | WeatherSaveView.cs 111 | 112 | 113 | WeatherLatestView.cs 114 | 115 | 116 | ResXFileCodeGenerator 117 | Resources.Designer.cs 118 | Designer 119 | 120 | 121 | True 122 | Resources.resx 123 | 124 | 125 | WeatherListView.cs 126 | 127 | 128 | WeatherSaveView.cs 129 | 130 | 131 | 132 | SettingsSingleFileGenerator 133 | Settings.Designer.cs 134 | 135 | 136 | True 137 | Settings.settings 138 | True 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | {96953b4b-cf64-4c86-9474-2920a946c948} 147 | DDD.Domain 148 | 149 | 150 | {6de6357e-7563-4e71-aaf3-50334e3be85d} 151 | DDD.Infrastructure 152 | 153 | 154 | 155 | 156 | 157 | このプロジェクトは、このコンピューター上にない NuGet パッケージを参照しています。それらのパッケージをダウンロードするには、[NuGet パッケージの復元] を使用します。詳細については、http://go.microsoft.com/fwlink/?LinkID=322105 を参照してください。見つからないファイルは {0} です。 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /DDDTest.Tests/ChainingAssertion.MSTest.cs: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------------- 2 | * Chaining Assertion 3 | * ver 1.7.1.0 (Apr. 29th, 2013) 4 | * 5 | * created and maintained by neuecc 6 | * licensed under Microsoft Public License(Ms-PL) 7 | * http://chainingassertion.codeplex.com/ 8 | *--------------------------------------------------------------------------*/ 9 | 10 | /* -- Tutorial -- 11 | * | at first, include this file on MSTest Project. 12 | * 13 | * | three example, "Is" overloads. 14 | * 15 | * // This same as Assert.AreEqual(25, Math.Pow(5, 2)) 16 | * Math.Pow(5, 2).Is(25); 17 | * 18 | * // This same as Assert.IsTrue("foobar".StartsWith("foo") && "foobar".EndWith("bar")) 19 | * "foobar".Is(s => s.StartsWith("foo") && s.EndsWith("bar")); 20 | * 21 | * // This same as CollectionAssert.AreEqual(Enumerable.Range(1,5), new[]{1, 2, 3, 4, 5}) 22 | * Enumerable.Range(1, 5).Is(1, 2, 3, 4, 5); 23 | * 24 | * | CollectionAssert 25 | * | if you want to use CollectionAssert Methods then use Linq to Objects and Is 26 | * 27 | * var array = new[] { 1, 3, 7, 8 }; 28 | * array.Count().Is(4); 29 | * array.Contains(8).IsTrue(); // IsTrue() == Is(true) 30 | * array.All(i => i < 5).IsFalse(); // IsFalse() == Is(false) 31 | * array.Any().Is(true); 32 | * new int[] { }.Any().Is(false); // IsEmpty 33 | * array.OrderBy(x => x).Is(array); // IsOrdered 34 | * 35 | * | Other Assertions 36 | * 37 | * // Null Assertions 38 | * Object obj = null; 39 | * obj.IsNull(); // Assert.IsNull(obj) 40 | * new Object().IsNotNull(); // Assert.IsNotNull(obj) 41 | * 42 | * // Not Assertion 43 | * "foobar".IsNot("fooooooo"); // Assert.AreNotEqual 44 | * new[] { "a", "z", "x" }.IsNot("a", "x", "z"); /// CollectionAssert.AreNotEqual 45 | * 46 | * // ReferenceEqual Assertion 47 | * var tuple = Tuple.Create("foo"); 48 | * tuple.IsSameReferenceAs(tuple); // Assert.AreSame 49 | * tuple.IsNotSameReferenceAs(Tuple.Create("foo")); // Assert.AreNotSame 50 | * 51 | * // Type Assertion 52 | * "foobar".IsInstanceOf(); // Assert.IsInstanceOfType 53 | * (999).IsNotInstanceOf(); // Assert.IsNotInstanceOfType 54 | * 55 | * | Advanced Collection Assertion 56 | * 57 | * var lower = new[] { "a", "b", "c" }; 58 | * var upper = new[] { "A", "B", "C" }; 59 | * 60 | * // Comparer CollectionAssert, use IEqualityComparer or Func delegate 61 | * lower.Is(upper, StringComparer.InvariantCultureIgnoreCase); 62 | * lower.Is(upper, (x, y) => x.ToUpper() == y.ToUpper()); 63 | * 64 | * // or you can use Linq to Objects - SequenceEqual 65 | * lower.SequenceEqual(upper, StringComparer.InvariantCultureIgnoreCase).Is(true); 66 | * 67 | * | StructuralEqual 68 | * 69 | * class MyClass 70 | * { 71 | * public int IntProp { get; set; } 72 | * public string StrField; 73 | * } 74 | * 75 | * var mc1 = new MyClass() { IntProp = 10, StrField = "foo" }; 76 | * var mc2 = new MyClass() { IntProp = 10, StrField = "foo" }; 77 | * 78 | * mc1.IsStructuralEqual(mc2); // deep recursive value equality compare 79 | * 80 | * mc1.IntProp = 20; 81 | * mc1.IsNotStructuralEqual(mc2); 82 | * 83 | * | DynamicAccessor 84 | * 85 | * // AsDynamic convert to "dynamic" that can call private method/property/field/indexer. 86 | * 87 | * // a class and private field/property/method. 88 | * public class PrivateMock 89 | * { 90 | * private string privateField = "homu"; 91 | * 92 | * private string PrivateProperty 93 | * { 94 | * get { return privateField + privateField; } 95 | * set { privateField = value; } 96 | * } 97 | * 98 | * private string PrivateMethod(int count) 99 | * { 100 | * return string.Join("", Enumerable.Repeat(privateField, count)); 101 | * } 102 | * } 103 | * 104 | * // call private property. 105 | * var actual = new PrivateMock().AsDynamic().PrivateProperty; 106 | * Assert.AreEqual("homuhomu", actual); 107 | * 108 | * // dynamic can't invoke extension methods. 109 | * // if you want to invoke "Is" then cast type. 110 | * (new PrivateMock().AsDynamic().PrivateMethod(3) as string).Is("homuhomuhomu"); 111 | * 112 | * // set value 113 | * var mock = new PrivateMock().AsDynamic(); 114 | * mock.PrivateProperty = "mogumogu"; 115 | * (mock.privateField as string).Is("mogumogu"); 116 | * 117 | * | Exception Test 118 | * 119 | * // Exception Test(alternative of ExpectedExceptionAttribute) 120 | * // AssertEx.Throws does not allow derived type 121 | * // AssertEx.Catch allows derived type 122 | * // AssertEx.ThrowsContractException catch only Code Contract's ContractException 123 | * AssertEx.Throws(() => "foo".StartsWith(null)); 124 | * AssertEx.Catch(() => "foo".StartsWith(null)); 125 | * AssertEx.ThrowsContractException(() => // contract method //); 126 | * 127 | * // return value is occured exception 128 | * var ex = AssertEx.Throws(() => 129 | * { 130 | * throw new InvalidOperationException("foobar operation"); 131 | * }); 132 | * ex.Message.Is(s => s.Contains("foobar")); // additional exception assertion 133 | * 134 | * // must not throw any exceptions 135 | * AssertEx.DoesNotThrow(() => 136 | * { 137 | * // code 138 | * }); 139 | * 140 | * | Parameterized Test 141 | * | TestCase takes parameters and send to TestContext's Extension Method "Run". 142 | * 143 | * [TestClass] 144 | * public class UnitTest 145 | * { 146 | * public TestContext TestContext { get; set; } 147 | * 148 | * [TestMethod] 149 | * [TestCase(1, 2, 3)] 150 | * [TestCase(10, 20, 30)] 151 | * [TestCase(100, 200, 300)] 152 | * public void TestMethod2() 153 | * { 154 | * TestContext.Run((int x, int y, int z) => 155 | * { 156 | * (x + y).Is(z); 157 | * (x + y + z).Is(i => i < 1000); 158 | * }); 159 | * } 160 | * } 161 | * 162 | * | TestCaseSource 163 | * | TestCaseSource can take static field/property that types is only object[][]. 164 | * 165 | * [TestMethod] 166 | * [TestCaseSource("toaruSource")] 167 | * public void TestTestCaseSource() 168 | * { 169 | * TestContext.Run((int x, int y, string z) => 170 | * { 171 | * string.Concat(x, y).Is(z); 172 | * }); 173 | * } 174 | * 175 | * public static object[] toaruSource = new[] 176 | * { 177 | * new object[] {1, 1, "11"}, 178 | * new object[] {5, 3, "53"}, 179 | * new object[] {9, 4, "94"} 180 | * }; 181 | * 182 | * -- more details see project home --*/ 183 | 184 | using System; 185 | using System.Collections; 186 | using System.Collections.Generic; 187 | using System.Diagnostics.Contracts; 188 | using System.Dynamic; 189 | using System.Linq; 190 | using System.Linq.Expressions; 191 | using System.Reflection; 192 | 193 | namespace Microsoft.VisualStudio.TestTools.UnitTesting 194 | { 195 | #region Extensions 196 | 197 | [System.Diagnostics.DebuggerStepThroughAttribute] 198 | [ContractVerification(false)] 199 | public static partial class AssertEx 200 | { 201 | /// Assert.AreEqual, if T is IEnumerable then CollectionAssert.AreEqual 202 | public static void Is(this T actual, T expected, string message = "") 203 | { 204 | if (typeof(T) != typeof(String) && typeof(IEnumerable).IsAssignableFrom(typeof(T))) 205 | { 206 | ((IEnumerable)actual).Cast().Is(((IEnumerable)expected).Cast(), message); 207 | return; 208 | } 209 | 210 | Assert.AreEqual(expected, actual, message); 211 | } 212 | 213 | /// Assert.IsTrue(predicate(value)) 214 | public static void Is(this T value, Expression> predicate, string message = "") 215 | { 216 | var condition = predicate.Compile().Invoke(value); 217 | 218 | var paramName = predicate.Parameters.First().Name; 219 | string msg = ""; 220 | try 221 | { 222 | var dumper = new ExpressionDumper(value, predicate.Parameters.Single()); 223 | dumper.Visit(predicate); 224 | var dump = string.Join(", ", dumper.Members.Select(kvp => kvp.Key + " = " + kvp.Value)); 225 | msg = string.Format("\r\n{0} = {1}\r\n{2}\r\n{3}{4}", 226 | paramName, value, dump, predicate, 227 | string.IsNullOrEmpty(message) ? "" : ", " + message); 228 | } 229 | catch 230 | { 231 | msg = string.Format("{0} = {1}, {2}{3}", 232 | paramName, value, predicate, 233 | string.IsNullOrEmpty(message) ? "" : ", " + message); 234 | } 235 | 236 | Assert.IsTrue(condition, msg); 237 | } 238 | 239 | /// CollectionAssert.AreEqual 240 | public static void Is(this IEnumerable actual, params T[] expected) 241 | { 242 | Is(actual, expected.AsEnumerable()); 243 | } 244 | 245 | /// CollectionAssert.AreEqual 246 | public static void Is(this IEnumerable actual, IEnumerable expected, string message = "") 247 | { 248 | CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray(), message); 249 | } 250 | 251 | /// CollectionAssert.AreEqual 252 | public static void Is(this IEnumerable actual, IEnumerable expected, IEqualityComparer comparer, string message = "") 253 | { 254 | Is(actual, expected, comparer.Equals, message); 255 | } 256 | 257 | /// CollectionAssert.AreEqual 258 | public static void Is(this IEnumerable actual, IEnumerable expected, Func equalityComparison, string message = "") 259 | { 260 | CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray(), new ComparisonComparer(equalityComparison), message); 261 | } 262 | 263 | /// Assert.AreNotEqual, if T is IEnumerable then CollectionAssert.AreNotEqual 264 | public static void IsNot(this T actual, T notExpected, string message = "") 265 | { 266 | if (typeof(T) != typeof(String) && typeof(IEnumerable).IsAssignableFrom(typeof(T))) 267 | { 268 | ((IEnumerable)actual).Cast().IsNot(((IEnumerable)notExpected).Cast(), message); 269 | return; 270 | } 271 | 272 | Assert.AreNotEqual(notExpected, actual, message); 273 | } 274 | 275 | /// CollectionAssert.AreNotEqual 276 | public static void IsNot(this IEnumerable actual, params T[] notExpected) 277 | { 278 | IsNot(actual, notExpected.AsEnumerable()); 279 | } 280 | 281 | /// CollectionAssert.AreNotEqual 282 | public static void IsNot(this IEnumerable actual, IEnumerable notExpected, string message = "") 283 | { 284 | CollectionAssert.AreNotEqual(notExpected.ToArray(), actual.ToArray(), message); 285 | } 286 | 287 | /// CollectionAssert.AreNotEqual 288 | public static void IsNot(this IEnumerable actual, IEnumerable notExpected, IEqualityComparer comparer, string message = "") 289 | { 290 | IsNot(actual, notExpected, comparer.Equals, message); 291 | } 292 | 293 | /// CollectionAssert.AreNotEqual 294 | public static void IsNot(this IEnumerable actual, IEnumerable notExpected, Func equalityComparison, string message = "") 295 | { 296 | CollectionAssert.AreNotEqual(notExpected.ToArray(), actual.ToArray(), new ComparisonComparer(equalityComparison), message); 297 | } 298 | 299 | /// Assert.IsNull 300 | public static void IsNull(this T value, string message = "") 301 | { 302 | Assert.IsNull(value, message); 303 | } 304 | 305 | /// Assert.IsNotNull 306 | public static void IsNotNull(this T value, string message = "") 307 | { 308 | Assert.IsNotNull(value, message); 309 | } 310 | 311 | /// Is(true) 312 | public static void IsTrue(this bool value, string message = "") 313 | { 314 | value.Is(true, message); 315 | } 316 | 317 | /// Is(false) 318 | public static void IsFalse(this bool value, string message = "") 319 | { 320 | value.Is(false, message); 321 | } 322 | 323 | /// Assert.AreSame 324 | public static void IsSameReferenceAs(this T actual, T expected, string message = "") 325 | { 326 | Assert.AreSame(expected, actual, message); 327 | } 328 | 329 | /// Assert.AreNotSame 330 | public static void IsNotSameReferenceAs(this T actual, T notExpected, string message = "") 331 | { 332 | Assert.AreNotSame(notExpected, actual, message); 333 | } 334 | 335 | /// Assert.IsInstanceOfType 336 | public static TExpected IsInstanceOf(this object value, string message = "") 337 | { 338 | Assert.IsInstanceOfType(value, typeof(TExpected), message); 339 | return (TExpected)value; 340 | } 341 | 342 | /// Assert.IsNotInstanceOfType 343 | public static void IsNotInstanceOf(this object value, string message = "") 344 | { 345 | Assert.IsNotInstanceOfType(value, typeof(TWrong), message); 346 | } 347 | 348 | /// Alternative of ExpectedExceptionAttribute(allow derived type) 349 | public static T Catch(Action testCode, string message = "") where T : Exception 350 | { 351 | var exception = ExecuteCode(testCode); 352 | var headerMsg = "Failed Throws<" + typeof(T).Name + ">."; 353 | var additionalMsg = string.IsNullOrEmpty(message) ? "" : ", " + message; 354 | 355 | if (exception == null) 356 | { 357 | var formatted = headerMsg + " No exception was thrown" + additionalMsg; 358 | throw new AssertFailedException(formatted); 359 | } 360 | else if (!typeof(T).IsInstanceOfType(exception)) 361 | { 362 | var formatted = string.Format("{0} Catched:{1}{2}", headerMsg, exception.GetType().Name, additionalMsg); 363 | throw new AssertFailedException(formatted); 364 | } 365 | 366 | return (T)exception; 367 | } 368 | 369 | /// Alternative of ExpectedExceptionAttribute(not allow derived type) 370 | public static T Throws(Action testCode, string message = "") where T : Exception 371 | { 372 | var exception = Catch(testCode, message); 373 | 374 | if (!typeof(T).Equals(exception.GetType())) 375 | { 376 | var headerMsg = "Failed Throws<" + typeof(T).Name + ">."; 377 | var additionalMsg = string.IsNullOrEmpty(message) ? "" : ", " + message; 378 | var formatted = string.Format("{0} Catched:{1}{2}", headerMsg, exception.GetType().Name, additionalMsg); 379 | throw new AssertFailedException(formatted); 380 | } 381 | 382 | return (T)exception; 383 | } 384 | 385 | /// expected testCode throws ContractException 386 | /// ContractException 387 | public static Exception ThrowsContractException(Action testCode, string message = "") 388 | { 389 | var exception = AssertEx.Catch(testCode, message); 390 | var type = exception.GetType(); 391 | if (type.Namespace == "System.Diagnostics.Contracts" && type.Name == "ContractException") 392 | { 393 | return exception; 394 | } 395 | 396 | var additionalMsg = string.IsNullOrEmpty(message) ? "" : ", " + message; 397 | var formatted = string.Format("Throwed Exception is not ContractException. Catched:{0}{1}", 398 | exception.GetType().Name, additionalMsg); 399 | 400 | throw new AssertFailedException(formatted); 401 | } 402 | 403 | /// does not throw any exceptions 404 | public static void DoesNotThrow(Action testCode, string message = "") 405 | { 406 | var exception = ExecuteCode(testCode); 407 | if (exception != null) 408 | { 409 | var formatted = string.Format("Failed DoesNotThrow. Catched:{0}{1}", exception.GetType().Name, string.IsNullOrEmpty(message) ? "" : ", " + message); 410 | throw new AssertFailedException(formatted); 411 | } 412 | } 413 | 414 | /// execute action and return exception when catched otherwise return null 415 | private static Exception ExecuteCode(Action testCode) 416 | { 417 | try 418 | { 419 | testCode(); 420 | return null; 421 | } 422 | catch (Exception e) 423 | { 424 | return e; 425 | } 426 | } 427 | 428 | /// EqualityComparison to IComparer Converter for CollectionAssert 429 | private class ComparisonComparer : IComparer 430 | { 431 | readonly Func comparison; 432 | 433 | public ComparisonComparer(Func comparison) 434 | { 435 | this.comparison = comparison; 436 | } 437 | 438 | public int Compare(object x, object y) 439 | { 440 | return (comparison != null) 441 | ? comparison((T)x, (T)y) ? 0 : -1 442 | : object.Equals(x, y) ? 0 : -1; 443 | } 444 | } 445 | 446 | private class ReflectAccessor 447 | { 448 | public Func GetValue { get; private set; } 449 | public Action SetValue { get; private set; } 450 | 451 | public ReflectAccessor(T target, string name) 452 | { 453 | var field = typeof(T).GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 454 | if (field != null) 455 | { 456 | GetValue = () => field.GetValue(target); 457 | SetValue = value => field.SetValue(target, value); 458 | return; 459 | } 460 | 461 | var prop = typeof(T).GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 462 | if (prop != null) 463 | { 464 | GetValue = () => prop.GetValue(target, null); 465 | SetValue = value => prop.SetValue(target, value, null); 466 | return; 467 | } 468 | 469 | throw new ArgumentException(string.Format("\"{0}\" not found : Type <{1}>", name, typeof(T).Name)); 470 | } 471 | } 472 | 473 | #region StructuralEqual 474 | 475 | /// Assert by deep recursive value equality compare 476 | public static void IsStructuralEqual(this object actual, object expected, string message = "") 477 | { 478 | message = (string.IsNullOrEmpty(message) ? "" : ", " + message); 479 | if (object.ReferenceEquals(actual, expected)) return; 480 | 481 | if (actual == null) throw new AssertFailedException("actual is null" + message); 482 | if (expected == null) throw new AssertFailedException("actual is not null" + message); 483 | if (actual.GetType() != expected.GetType()) 484 | { 485 | var msg = string.Format("expected type is {0} but actual type is {1}{2}", 486 | expected.GetType().Name, actual.GetType().Name, message); 487 | throw new AssertFailedException(msg); 488 | } 489 | 490 | var r = StructuralEqual(actual, expected, new[] { actual.GetType().Name }); // root type 491 | if (!r.IsEquals) 492 | { 493 | var msg = string.Format("is not structural equal, failed at {0}, actual = {1} expected = {2}{3}", 494 | string.Join(".", r.Names), r.Left, r.Right, message); 495 | throw new AssertFailedException(msg); 496 | } 497 | } 498 | 499 | /// Assert by deep recursive value equality compare 500 | public static void IsNotStructuralEqual(this object actual, object expected, string message = "") 501 | { 502 | message = (string.IsNullOrEmpty(message) ? "" : ", " + message); 503 | if (object.ReferenceEquals(actual, expected)) throw new AssertFailedException("actual is same reference" + message); ; 504 | 505 | if (actual == null) return; 506 | if (expected == null) return; 507 | if (actual.GetType() != expected.GetType()) 508 | { 509 | return; 510 | } 511 | 512 | var r = StructuralEqual(actual, expected, new[] { actual.GetType().Name }); // root type 513 | if (r.IsEquals) 514 | { 515 | throw new AssertFailedException("is structural equal" + message); 516 | } 517 | } 518 | 519 | static EqualInfo SequenceEqual(IEnumerable leftEnumerable, IEnumerable rightEnumarable, IEnumerable names) 520 | { 521 | var le = leftEnumerable.GetEnumerator(); 522 | using (le as IDisposable) 523 | { 524 | var re = rightEnumarable.GetEnumerator(); 525 | 526 | using (re as IDisposable) 527 | { 528 | var index = 0; 529 | while (true) 530 | { 531 | object lValue = null; 532 | object rValue = null; 533 | var lMove = le.MoveNext(); 534 | var rMove = re.MoveNext(); 535 | if (lMove) lValue = le.Current; 536 | if (rMove) rValue = re.Current; 537 | 538 | if (lMove && rMove) 539 | { 540 | var result = StructuralEqual(lValue, rValue, names.Concat(new[] { "[" + index + "]" })); 541 | if (!result.IsEquals) 542 | { 543 | return result; 544 | } 545 | } 546 | 547 | if ((lMove == true && rMove == false) || (lMove == false && rMove == true)) 548 | { 549 | return new EqualInfo { IsEquals = false, Left = lValue, Right = rValue, Names = names.Concat(new[] { "[" + index + "]" }) }; 550 | } 551 | if (lMove == false && rMove == false) break; 552 | index++; 553 | } 554 | } 555 | } 556 | return new EqualInfo { IsEquals = true, Left = leftEnumerable, Right = rightEnumarable, Names = names }; 557 | } 558 | 559 | static EqualInfo StructuralEqual(object left, object right, IEnumerable names) 560 | { 561 | // type and basic checks 562 | if (object.ReferenceEquals(left, right)) return new EqualInfo { IsEquals = true, Left = left, Right = right, Names = names }; 563 | if (left == null || right == null) return new EqualInfo { IsEquals = false, Left = left, Right = right, Names = names }; 564 | var lType = left.GetType(); 565 | var rType = right.GetType(); 566 | if (lType != rType) return new EqualInfo { IsEquals = false, Left = left, Right = right, Names = names }; 567 | 568 | var type = left.GetType(); 569 | 570 | // not object(int, string, etc...) 571 | if (Type.GetTypeCode(type) != TypeCode.Object) 572 | { 573 | return new EqualInfo { IsEquals = left.Equals(right), Left = left, Right = right, Names = names }; 574 | } 575 | 576 | // is sequence 577 | if (typeof(IEnumerable).IsAssignableFrom(type)) 578 | { 579 | return SequenceEqual((IEnumerable)left, (IEnumerable)right, names); 580 | } 581 | 582 | // IEquatable 583 | var equatable = typeof(IEquatable<>).MakeGenericType(type); 584 | if (equatable.IsAssignableFrom(type)) 585 | { 586 | var result = (bool)equatable.GetMethod("Equals").Invoke(left, new[] { right }); 587 | return new EqualInfo { IsEquals = result, Left = left, Right = right, Names = names }; 588 | } 589 | 590 | // is object 591 | var fields = left.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public); 592 | var properties = left.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(x => x.GetGetMethod(false) != null); 593 | var members = fields.Cast().Concat(properties); 594 | 595 | foreach (dynamic mi in fields.Cast().Concat(properties)) 596 | { 597 | var concatNames = names.Concat(new[] { (string)mi.Name }); 598 | 599 | object lv = mi.GetValue(left); 600 | object rv = mi.GetValue(right); 601 | var result = StructuralEqual(lv, rv, concatNames); 602 | if (!result.IsEquals) 603 | { 604 | return result; 605 | } 606 | } 607 | 608 | return new EqualInfo { IsEquals = true, Left = left, Right = right, Names = names }; 609 | } 610 | 611 | private class EqualInfo 612 | { 613 | public object Left; 614 | public object Right; 615 | public bool IsEquals; 616 | public IEnumerable Names; 617 | } 618 | 619 | #endregion 620 | 621 | #region DynamicAccessor 622 | 623 | /// to DynamicAccessor that can call private method/field/property/indexer. 624 | public static dynamic AsDynamic(this T target) 625 | { 626 | return new DynamicAccessor(target); 627 | } 628 | 629 | private class DynamicAccessor : DynamicObject 630 | { 631 | private readonly T target; 632 | private static readonly BindingFlags TransparentFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; 633 | 634 | public DynamicAccessor(T target) 635 | { 636 | this.target = target; 637 | } 638 | 639 | public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) 640 | { 641 | try 642 | { 643 | typeof(T).InvokeMember("Item", TransparentFlags | BindingFlags.SetProperty, null, target, indexes.Concat(new[] { value }).ToArray()); 644 | return true; 645 | } 646 | catch (MissingMethodException) { throw new ArgumentException(string.Format("indexer not found : Type <{0}>", typeof(T).Name)); }; 647 | } 648 | 649 | public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) 650 | { 651 | try 652 | { 653 | result = typeof(T).InvokeMember("Item", TransparentFlags | BindingFlags.GetProperty, null, target, indexes); 654 | return true; 655 | } 656 | catch (MissingMethodException) { throw new ArgumentException(string.Format("indexer not found : Type <{0}>", typeof(T).Name)); }; 657 | } 658 | 659 | public override bool TrySetMember(SetMemberBinder binder, object value) 660 | { 661 | var accessor = new ReflectAccessor(target, binder.Name); 662 | accessor.SetValue(value); 663 | return true; 664 | } 665 | 666 | public override bool TryGetMember(GetMemberBinder binder, out object result) 667 | { 668 | var accessor = new ReflectAccessor(target, binder.Name); 669 | result = accessor.GetValue(); 670 | return true; 671 | } 672 | 673 | public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) 674 | { 675 | var csharpBinder = binder.GetType().GetInterface("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder"); 676 | if (csharpBinder == null) throw new ArgumentException("is not csharp code"); 677 | 678 | var typeArgs = (csharpBinder.GetProperty("TypeArguments").GetValue(binder, null) as IList).ToArray(); 679 | var parameterTypes = (binder.GetType().GetField("Cache", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(binder) as Dictionary) 680 | .First() 681 | .Key 682 | .GetGenericArguments() 683 | .Skip(2) 684 | .Take(args.Length) 685 | .ToArray(); 686 | 687 | var method = MatchMethod(binder.Name, args, typeArgs, parameterTypes); 688 | result = method.Invoke(target, args); 689 | 690 | return true; 691 | } 692 | 693 | private Type AssignableBoundType(Type left, Type right) 694 | { 695 | return (left == null || right == null) ? null 696 | : left.IsAssignableFrom(right) ? left 697 | : right.IsAssignableFrom(left) ? right 698 | : null; 699 | } 700 | 701 | private MethodInfo MatchMethod(string methodName, object[] args, Type[] typeArgs, Type[] parameterTypes) 702 | { 703 | // name match 704 | var nameMatched = typeof(T).GetMethods(TransparentFlags) 705 | .Where(mi => mi.Name == methodName) 706 | .ToArray(); 707 | if (!nameMatched.Any()) throw new ArgumentException(string.Format("\"{0}\" not found : Type <{1}>", methodName, typeof(T).Name)); 708 | 709 | // type inference 710 | var typedMethods = nameMatched 711 | .Select(mi => 712 | { 713 | var genericArguments = mi.GetGenericArguments(); 714 | 715 | if (!typeArgs.Any() && !genericArguments.Any()) // non generic method 716 | { 717 | return new 718 | { 719 | MethodInfo = mi, 720 | TypeParameters = default(Dictionary) 721 | }; 722 | } 723 | else if (!typeArgs.Any()) 724 | { 725 | var parameterGenericTypes = mi.GetParameters() 726 | .Select(pi => pi.ParameterType) 727 | .Zip(parameterTypes, Tuple.Create) 728 | .GroupBy(a => a.Item1, a => a.Item2) 729 | .Where(g => g.Key.IsGenericParameter) 730 | .Select(g => new { g.Key, Type = g.Aggregate(AssignableBoundType) }) 731 | .Where(a => a.Type != null); 732 | 733 | var typeParams = genericArguments 734 | .GroupJoin(parameterGenericTypes, x => x, x => x.Key, (_, Args) => Args) 735 | .ToArray(); 736 | if (!typeParams.All(xs => xs.Any())) return null; // types short 737 | 738 | return new 739 | { 740 | MethodInfo = mi, 741 | TypeParameters = typeParams 742 | .Select(xs => xs.First()) 743 | .ToDictionary(a => a.Key, a => a.Type) 744 | }; 745 | } 746 | else 747 | { 748 | if (genericArguments.Length != typeArgs.Length) return null; 749 | 750 | return new 751 | { 752 | MethodInfo = mi, 753 | TypeParameters = genericArguments 754 | .Zip(typeArgs, Tuple.Create) 755 | .ToDictionary(t => t.Item1, t => t.Item2) 756 | }; 757 | } 758 | }) 759 | .Where(a => a != null) 760 | .Where(a => a.MethodInfo 761 | .GetParameters() 762 | .Select(pi => pi.ParameterType) 763 | .SequenceEqual(parameterTypes, new EqualsComparer((x, y) => 764 | (x.IsGenericParameter) 765 | ? a.TypeParameters[x].IsAssignableFrom(y) 766 | : x.Equals(y))) 767 | ) 768 | .ToArray(); 769 | 770 | if (!typedMethods.Any()) throw new ArgumentException(string.Format("\"{0}\" not match arguments : Type <{1}>", methodName, typeof(T).Name)); 771 | 772 | // nongeneric 773 | var nongeneric = typedMethods.Where(a => a.TypeParameters == null).ToArray(); 774 | if (nongeneric.Length == 1) return nongeneric[0].MethodInfo; 775 | 776 | // generic-- 777 | var lessGeneric = typedMethods 778 | .Where(a => !a.MethodInfo.GetParameters().All(pi => pi.ParameterType.IsGenericParameter)) 779 | .ToArray(); 780 | 781 | // generic 782 | var generic = (typedMethods.Length == 1) 783 | ? typedMethods[0] 784 | : (lessGeneric.Length == 1 ? lessGeneric[0] : null); 785 | 786 | if (generic != null) return generic.MethodInfo.MakeGenericMethod(generic.TypeParameters.Select(kvp => kvp.Value).ToArray()); 787 | 788 | // ambiguous 789 | throw new ArgumentException(string.Format("\"{0}\" ambiguous arguments : Type <{1}>", methodName, typeof(T).Name)); 790 | } 791 | 792 | private class EqualsComparer : IEqualityComparer 793 | { 794 | private readonly Func equals; 795 | 796 | public EqualsComparer(Func equals) 797 | { 798 | this.equals = equals; 799 | } 800 | 801 | public bool Equals(TX x, TX y) 802 | { 803 | return equals(x, y); 804 | } 805 | 806 | public int GetHashCode(TX obj) 807 | { 808 | return 0; 809 | } 810 | } 811 | } 812 | 813 | #endregion 814 | 815 | #region ExpressionDumper 816 | 817 | private class ExpressionDumper : ExpressionVisitor 818 | { 819 | ParameterExpression param; 820 | T target; 821 | 822 | public Dictionary Members { get; private set; } 823 | 824 | public ExpressionDumper(T target, ParameterExpression param) 825 | { 826 | this.target = target; 827 | this.param = param; 828 | this.Members = new Dictionary(); 829 | } 830 | 831 | protected override System.Linq.Expressions.Expression VisitMember(MemberExpression node) 832 | { 833 | if (node.Expression == param && !Members.ContainsKey(node.Member.Name)) 834 | { 835 | var accessor = new ReflectAccessor(target, node.Member.Name); 836 | Members.Add(node.Member.Name, accessor.GetValue()); 837 | } 838 | 839 | return base.VisitMember(node); 840 | } 841 | } 842 | 843 | #endregion 844 | } 845 | 846 | #endregion 847 | 848 | #region TestCase 849 | 850 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] 851 | public class TestCaseAttribute : Attribute 852 | { 853 | public object[] Parameters { get; private set; } 854 | 855 | /// parameters provide to TestContext.Run. 856 | public TestCaseAttribute(params object[] parameters) 857 | { 858 | Parameters = parameters; 859 | } 860 | } 861 | 862 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] 863 | public class TestCaseSourceAttribute : Attribute 864 | { 865 | public string SourceName { get; private set; } 866 | 867 | /// point out static field/property name. source must be object[][]. 868 | public TestCaseSourceAttribute(string sourceName) 869 | { 870 | SourceName = sourceName; 871 | } 872 | } 873 | 874 | public static class TestContextExtensions 875 | { 876 | private static IEnumerable GetParameters(Type classType, string methodName) 877 | { 878 | var method = classType.GetMethod(methodName); 879 | 880 | var testCase = method 881 | .GetCustomAttributes(typeof(TestCaseAttribute), false) 882 | .Cast() 883 | .Select(x => x.Parameters); 884 | 885 | var testCaseSource = method 886 | .GetCustomAttributes(typeof(TestCaseSourceAttribute), false) 887 | .Cast() 888 | .SelectMany(x => 889 | { 890 | var p = classType.GetProperty(x.SourceName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); 891 | var val = (p != null) 892 | ? p.GetValue(null, null) 893 | : classType.GetField(x.SourceName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(null); 894 | 895 | return ((object[])val).Cast(); 896 | }); 897 | 898 | return testCase.Concat(testCaseSource); 899 | } 900 | 901 | /// Run Parameterized Test marked by TestCase Attribute. 902 | public static void Run(this TestContext context, Action assertion) 903 | { 904 | var type = Assembly.GetCallingAssembly().GetType(context.FullyQualifiedTestClassName); 905 | foreach (var parameters in GetParameters(type, context.TestName)) 906 | { 907 | assertion( 908 | (T1)parameters[0] 909 | ); 910 | } 911 | } 912 | 913 | /// Run Parameterized Test marked by TestCase Attribute. 914 | public static void Run(this TestContext context, Action assertion) 915 | { 916 | var type = Assembly.GetCallingAssembly().GetType(context.FullyQualifiedTestClassName); 917 | foreach (var parameters in GetParameters(type, context.TestName)) 918 | { 919 | assertion( 920 | (T1)parameters[0], 921 | (T2)parameters[1] 922 | ); 923 | } 924 | } 925 | 926 | /// Run Parameterized Test marked by TestCase Attribute. 927 | public static void Run(this TestContext context, Action assertion) 928 | { 929 | var type = Assembly.GetCallingAssembly().GetType(context.FullyQualifiedTestClassName); 930 | foreach (var parameters in GetParameters(type, context.TestName)) 931 | { 932 | assertion( 933 | (T1)parameters[0], 934 | (T2)parameters[1], 935 | (T3)parameters[2] 936 | ); 937 | } 938 | } 939 | 940 | /// Run Parameterized Test marked by TestCase Attribute. 941 | public static void Run(this TestContext context, Action assertion) 942 | { 943 | var type = Assembly.GetCallingAssembly().GetType(context.FullyQualifiedTestClassName); 944 | foreach (var parameters in GetParameters(type, context.TestName)) 945 | { 946 | assertion( 947 | (T1)parameters[0], 948 | (T2)parameters[1], 949 | (T3)parameters[2], 950 | (T4)parameters[3] 951 | ); 952 | } 953 | } 954 | 955 | /// Run Parameterized Test marked by TestCase Attribute. 956 | public static void Run(this TestContext context, Action assertion) 957 | { 958 | var type = Assembly.GetCallingAssembly().GetType(context.FullyQualifiedTestClassName); 959 | foreach (var parameters in GetParameters(type, context.TestName)) 960 | { 961 | assertion( 962 | (T1)parameters[0], 963 | (T2)parameters[1], 964 | (T3)parameters[2], 965 | (T4)parameters[3], 966 | (T5)parameters[4] 967 | ); 968 | } 969 | } 970 | 971 | /// Run Parameterized Test marked by TestCase Attribute. 972 | public static void Run(this TestContext context, Action assertion) 973 | { 974 | var type = Assembly.GetCallingAssembly().GetType(context.FullyQualifiedTestClassName); 975 | foreach (var parameters in GetParameters(type, context.TestName)) 976 | { 977 | assertion( 978 | (T1)parameters[0], 979 | (T2)parameters[1], 980 | (T3)parameters[2], 981 | (T4)parameters[3], 982 | (T5)parameters[4], 983 | (T6)parameters[5] 984 | ); 985 | } 986 | } 987 | 988 | /// Run Parameterized Test marked by TestCase Attribute. 989 | public static void Run(this TestContext context, Action assertion) 990 | { 991 | var type = Assembly.GetCallingAssembly().GetType(context.FullyQualifiedTestClassName); 992 | foreach (var parameters in GetParameters(type, context.TestName)) 993 | { 994 | assertion( 995 | (T1)parameters[0], 996 | (T2)parameters[1], 997 | (T3)parameters[2], 998 | (T4)parameters[3], 999 | (T5)parameters[4], 1000 | (T6)parameters[5], 1001 | (T7)parameters[6] 1002 | ); 1003 | } 1004 | } 1005 | 1006 | /// Run Parameterized Test marked by TestCase Attribute. 1007 | public static void Run(this TestContext context, Action assertion) 1008 | { 1009 | var type = Assembly.GetCallingAssembly().GetType(context.FullyQualifiedTestClassName); 1010 | foreach (var parameters in GetParameters(type, context.TestName)) 1011 | { 1012 | assertion( 1013 | (T1)parameters[0], 1014 | (T2)parameters[1], 1015 | (T3)parameters[2], 1016 | (T4)parameters[3], 1017 | (T5)parameters[4], 1018 | (T6)parameters[5], 1019 | (T7)parameters[6], 1020 | (T8)parameters[7] 1021 | ); 1022 | } 1023 | } 1024 | 1025 | /// Run Parameterized Test marked by TestCase Attribute. 1026 | public static void Run(this TestContext context, Action assertion) 1027 | { 1028 | var type = Assembly.GetCallingAssembly().GetType(context.FullyQualifiedTestClassName); 1029 | foreach (var parameters in GetParameters(type, context.TestName)) 1030 | { 1031 | assertion( 1032 | (T1)parameters[0], 1033 | (T2)parameters[1], 1034 | (T3)parameters[2], 1035 | (T4)parameters[3], 1036 | (T5)parameters[4], 1037 | (T6)parameters[5], 1038 | (T7)parameters[6], 1039 | (T8)parameters[7], 1040 | (T9)parameters[8] 1041 | ); 1042 | } 1043 | } 1044 | 1045 | /// Run Parameterized Test marked by TestCase Attribute. 1046 | public static void Run(this TestContext context, Action assertion) 1047 | { 1048 | var type = Assembly.GetCallingAssembly().GetType(context.FullyQualifiedTestClassName); 1049 | foreach (var parameters in GetParameters(type, context.TestName)) 1050 | { 1051 | assertion( 1052 | (T1)parameters[0], 1053 | (T2)parameters[1], 1054 | (T3)parameters[2], 1055 | (T4)parameters[3], 1056 | (T5)parameters[4], 1057 | (T6)parameters[5], 1058 | (T7)parameters[6], 1059 | (T8)parameters[7], 1060 | (T9)parameters[8], 1061 | (T10)parameters[9] 1062 | ); 1063 | } 1064 | } 1065 | 1066 | /// Run Parameterized Test marked by TestCase Attribute. 1067 | public static void Run(this TestContext context, Action assertion) 1068 | { 1069 | var type = Assembly.GetCallingAssembly().GetType(context.FullyQualifiedTestClassName); 1070 | foreach (var parameters in GetParameters(type, context.TestName)) 1071 | { 1072 | assertion( 1073 | (T1)parameters[0], 1074 | (T2)parameters[1], 1075 | (T3)parameters[2], 1076 | (T4)parameters[3], 1077 | (T5)parameters[4], 1078 | (T6)parameters[5], 1079 | (T7)parameters[6], 1080 | (T8)parameters[7], 1081 | (T9)parameters[8], 1082 | (T10)parameters[9], 1083 | (T11)parameters[10] 1084 | ); 1085 | } 1086 | } 1087 | 1088 | /// Run Parameterized Test marked by TestCase Attribute. 1089 | public static void Run(this TestContext context, Action assertion) 1090 | { 1091 | var type = Assembly.GetCallingAssembly().GetType(context.FullyQualifiedTestClassName); 1092 | foreach (var parameters in GetParameters(type, context.TestName)) 1093 | { 1094 | assertion( 1095 | (T1)parameters[0], 1096 | (T2)parameters[1], 1097 | (T3)parameters[2], 1098 | (T4)parameters[3], 1099 | (T5)parameters[4], 1100 | (T6)parameters[5], 1101 | (T7)parameters[6], 1102 | (T8)parameters[7], 1103 | (T9)parameters[8], 1104 | (T10)parameters[9], 1105 | (T11)parameters[10], 1106 | (T12)parameters[11] 1107 | ); 1108 | } 1109 | } 1110 | 1111 | /// Run Parameterized Test marked by TestCase Attribute. 1112 | public static void Run(this TestContext context, Action assertion) 1113 | { 1114 | var type = Assembly.GetCallingAssembly().GetType(context.FullyQualifiedTestClassName); 1115 | foreach (var parameters in GetParameters(type, context.TestName)) 1116 | { 1117 | assertion( 1118 | (T1)parameters[0], 1119 | (T2)parameters[1], 1120 | (T3)parameters[2], 1121 | (T4)parameters[3], 1122 | (T5)parameters[4], 1123 | (T6)parameters[5], 1124 | (T7)parameters[6], 1125 | (T8)parameters[7], 1126 | (T9)parameters[8], 1127 | (T10)parameters[9], 1128 | (T11)parameters[10], 1129 | (T12)parameters[11], 1130 | (T13)parameters[12] 1131 | ); 1132 | } 1133 | } 1134 | 1135 | /// Run Parameterized Test marked by TestCase Attribute. 1136 | public static void Run(this TestContext context, Action assertion) 1137 | { 1138 | var type = Assembly.GetCallingAssembly().GetType(context.FullyQualifiedTestClassName); 1139 | foreach (var parameters in GetParameters(type, context.TestName)) 1140 | { 1141 | assertion( 1142 | (T1)parameters[0], 1143 | (T2)parameters[1], 1144 | (T3)parameters[2], 1145 | (T4)parameters[3], 1146 | (T5)parameters[4], 1147 | (T6)parameters[5], 1148 | (T7)parameters[6], 1149 | (T8)parameters[7], 1150 | (T9)parameters[8], 1151 | (T10)parameters[9], 1152 | (T11)parameters[10], 1153 | (T12)parameters[11], 1154 | (T13)parameters[12], 1155 | (T14)parameters[13] 1156 | ); 1157 | } 1158 | } 1159 | 1160 | /// Run Parameterized Test marked by TestCase Attribute. 1161 | public static void Run(this TestContext context, Action assertion) 1162 | { 1163 | var type = Assembly.GetCallingAssembly().GetType(context.FullyQualifiedTestClassName); 1164 | foreach (var parameters in GetParameters(type, context.TestName)) 1165 | { 1166 | assertion( 1167 | (T1)parameters[0], 1168 | (T2)parameters[1], 1169 | (T3)parameters[2], 1170 | (T4)parameters[3], 1171 | (T5)parameters[4], 1172 | (T6)parameters[5], 1173 | (T7)parameters[6], 1174 | (T8)parameters[7], 1175 | (T9)parameters[8], 1176 | (T10)parameters[9], 1177 | (T11)parameters[10], 1178 | (T12)parameters[11], 1179 | (T13)parameters[12], 1180 | (T14)parameters[13], 1181 | (T15)parameters[14] 1182 | ); 1183 | } 1184 | } 1185 | 1186 | /// Run Parameterized Test marked by TestCase Attribute. 1187 | public static void Run(this TestContext context, Action assertion) 1188 | { 1189 | var type = Assembly.GetCallingAssembly().GetType(context.FullyQualifiedTestClassName); 1190 | foreach (var parameters in GetParameters(type, context.TestName)) 1191 | { 1192 | assertion( 1193 | (T1)parameters[0], 1194 | (T2)parameters[1], 1195 | (T3)parameters[2], 1196 | (T4)parameters[3], 1197 | (T5)parameters[4], 1198 | (T6)parameters[5], 1199 | (T7)parameters[6], 1200 | (T8)parameters[7], 1201 | (T9)parameters[8], 1202 | (T10)parameters[9], 1203 | (T11)parameters[10], 1204 | (T12)parameters[11], 1205 | (T13)parameters[12], 1206 | (T14)parameters[13], 1207 | (T15)parameters[14], 1208 | (T16)parameters[15] 1209 | ); 1210 | } 1211 | } 1212 | } 1213 | 1214 | #endregion 1215 | } --------------------------------------------------------------------------------