Skip to content

Commit 24d6223

Browse files
authored
Merge pull request #136 from ivaylokenov/development
Version 1.0.0-preview
2 parents ffc331c + ef5b5ee commit 24d6223

File tree

130 files changed

+39262
-407
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

130 files changed

+39262
-407
lines changed

MyTested.AspNetCore.Mvc.sln

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MyTested.AspNetCore.Mvc.Dat
6060
EndProject
6161
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MyTested.AspNetCore.Mvc.DataAnnotations.Test", "test\MyTested.AspNetCore.Mvc.DataAnnotations.Test\MyTested.AspNetCore.Mvc.DataAnnotations.Test.xproj", "{BAAAAB60-49AE-4BFE-B176-408C86746474}"
6262
EndProject
63+
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MyTested.AspNetCore.Mvc.EntityFrameworkCore", "src\MyTested.AspNetCore.Mvc.EntityFrameworkCore\MyTested.AspNetCore.Mvc.EntityFrameworkCore.xproj", "{0BE034FD-B68B-4D52-A0C5-29BCDBF543DC}"
64+
EndProject
65+
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MyTested.AspNetCore.Mvc.EntityFrameworkCore.Test", "test\MyTested.AspNetCore.Mvc.EntityFrameworkCore.Test\MyTested.AspNetCore.Mvc.EntityFrameworkCore.Test.xproj", "{285E08F2-2E5A-4226-B867-FD3DF7C52053}"
66+
EndProject
67+
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MyTested.AspNetCore.Mvc.Options", "src\MyTested.AspNetCore.Mvc.Options\MyTested.AspNetCore.Mvc.Options.xproj", "{ACE92892-8F86-44B1-8F78-3B1F8DDE7DD4}"
68+
EndProject
69+
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MyTested.AspNetCore.Mvc.Options.Test", "test\MyTested.AspNetCore.Mvc.Options.Test\MyTested.AspNetCore.Mvc.Options.Test.xproj", "{1309FBA5-F93D-4F4B-9819-63D298B837FF}"
70+
EndProject
6371
Global
6472
GlobalSection(SolutionConfigurationPlatforms) = preSolution
6573
Debug|Any CPU = Debug|Any CPU
@@ -150,6 +158,22 @@ Global
150158
{BAAAAB60-49AE-4BFE-B176-408C86746474}.Debug|Any CPU.Build.0 = Debug|Any CPU
151159
{BAAAAB60-49AE-4BFE-B176-408C86746474}.Release|Any CPU.ActiveCfg = Release|Any CPU
152160
{BAAAAB60-49AE-4BFE-B176-408C86746474}.Release|Any CPU.Build.0 = Release|Any CPU
161+
{0BE034FD-B68B-4D52-A0C5-29BCDBF543DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
162+
{0BE034FD-B68B-4D52-A0C5-29BCDBF543DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
163+
{0BE034FD-B68B-4D52-A0C5-29BCDBF543DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
164+
{0BE034FD-B68B-4D52-A0C5-29BCDBF543DC}.Release|Any CPU.Build.0 = Release|Any CPU
165+
{285E08F2-2E5A-4226-B867-FD3DF7C52053}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
166+
{285E08F2-2E5A-4226-B867-FD3DF7C52053}.Debug|Any CPU.Build.0 = Debug|Any CPU
167+
{285E08F2-2E5A-4226-B867-FD3DF7C52053}.Release|Any CPU.ActiveCfg = Release|Any CPU
168+
{285E08F2-2E5A-4226-B867-FD3DF7C52053}.Release|Any CPU.Build.0 = Release|Any CPU
169+
{ACE92892-8F86-44B1-8F78-3B1F8DDE7DD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
170+
{ACE92892-8F86-44B1-8F78-3B1F8DDE7DD4}.Debug|Any CPU.Build.0 = Debug|Any CPU
171+
{ACE92892-8F86-44B1-8F78-3B1F8DDE7DD4}.Release|Any CPU.ActiveCfg = Release|Any CPU
172+
{ACE92892-8F86-44B1-8F78-3B1F8DDE7DD4}.Release|Any CPU.Build.0 = Release|Any CPU
173+
{1309FBA5-F93D-4F4B-9819-63D298B837FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
174+
{1309FBA5-F93D-4F4B-9819-63D298B837FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
175+
{1309FBA5-F93D-4F4B-9819-63D298B837FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
176+
{1309FBA5-F93D-4F4B-9819-63D298B837FF}.Release|Any CPU.Build.0 = Release|Any CPU
153177
EndGlobalSection
154178
GlobalSection(SolutionProperties) = preSolution
155179
HideSolutionNode = FALSE
@@ -178,5 +202,9 @@ Global
178202
{1C8F2E0F-811A-42E4-B35A-FAAD19D8257A} = {D140FA14-A6C2-4279-8A41-35BC55279DA8}
179203
{2C375C22-4710-438F-A4C2-325C7D091710} = {09353A03-2B0C-496B-8EB1-2CB6A22D758B}
180204
{BAAAAB60-49AE-4BFE-B176-408C86746474} = {D140FA14-A6C2-4279-8A41-35BC55279DA8}
205+
{0BE034FD-B68B-4D52-A0C5-29BCDBF543DC} = {09353A03-2B0C-496B-8EB1-2CB6A22D758B}
206+
{285E08F2-2E5A-4226-B867-FD3DF7C52053} = {D140FA14-A6C2-4279-8A41-35BC55279DA8}
207+
{ACE92892-8F86-44B1-8F78-3B1F8DDE7DD4} = {09353A03-2B0C-496B-8EB1-2CB6A22D758B}
208+
{1309FBA5-F93D-4F4B-9819-63D298B837FF} = {D140FA14-A6C2-4279-8A41-35BC55279DA8}
181209
EndGlobalSection
182210
EndGlobal

README.md

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ namespace MyApp.Tests
4545
{
4646
base.ConfigureServices(services);
4747

48-
services.Replace<IRepository, MockedRepository>();
48+
services.Replace<IService, MockedService>();
4949
}
5050
}
5151
}
@@ -90,6 +90,8 @@ MyMvc
9090
.ShouldMap(request => request
9191
.WithLocation("/My/Action/1")
9292
.WithMethod(HttpMethod.Post)
93+
.WithAuthenticatedUser()
94+
.WithAntiForgeryToken()
9395
.WithJsonBody(new
9496
{
9597
Integer = 1,
@@ -125,6 +127,31 @@ MyMvc
125127
Assert.AreEqual(1, m.Id);
126128
Assert.AreEqual("Some property value", m.SomeProperty);
127129
});
130+
131+
// instantiates controller with the registered services
132+
// and sets options for the current test
133+
// and sets session for the current test
134+
// and sets DbContext for the current test
135+
// and tests for added cache entry by the action
136+
// and tests model from view result
137+
MyMvc
138+
.Controller<MvcController>()
139+
.WithOptions(options => options
140+
.For<AppSettings>(settings => settings.Cache = true))
141+
.WithSession(session => session
142+
.WithEntry("Session", "SessionValue"))
143+
.WithDbContext(db => db.WithEntities(entities => entities
144+
.AddRange(SampleDataProvider.GetModels())))
145+
.Calling(c => c.SomeAction())
146+
.ShouldHave()
147+
.MemoryCache(cache => cache
148+
.ContainingEntry(entry => entry
149+
.WithKey("CacheEntry")
150+
.WithSlidingExpiration(TimeSpan.FromMinutes(10))))
151+
.AndAlso()
152+
.ShouldReturn()
153+
.View()
154+
.WithModelOfType<ResponseModel>();
128155

129156
// tests whether the action is declared with filters
130157
MyMvc
@@ -167,7 +194,7 @@ Code by Ivaylo Kenov. Copyright 2015 Ivaylo Kenov ([http://mytestedasp.net](http
167194

168195
**Currently MyTested.AspNetCore.Mvc is in alpha version and it is not advised to use it in production environments. The testing framework is fully tested and working correctly but the fluent APIs may change in the final production-ready build.**
169196

170-
MyTested.AspNetCore.Mvc source code is available under GNU Affero General Public License/FOSS License Exception. The free version of the library allows up to 500 assertions (around 100 test cases) per test project. Additionally, full-featured licenses can be requested for free by individuals, startups and educational institutions. Commercial licensing with private support will also be available with the final release.
197+
MyTested.AspNetCore.Mvc source code is available under GNU Affero General Public License/FOSS License Exception. The free version of the library allows up to 500 assertions (around 100 test cases) per test project. Additionally, full-featured licenses can be requested for free by individuals, open-source projects, startups and educational institutions. Commercial licensing with private support will also be available with the final release.
171198

172199
See the [LICENSE](https://github.com/ivaylokenov/MyTested.AspNetCore.Mvc/blob/master/LICENSE) for detailed information.
173200

samples/ApplicationParts/ApplicationParts.Test/project.lock.json

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4055,13 +4055,15 @@
40554055
"netcoreapp1.0/ApplicationParts.Web.dll": {}
40564056
}
40574057
},
4058-
"MyTested.AspNetCore.Mvc/1.0.0-alpha": {
4058+
"MyTested.AspNetCore.Mvc/1.0.0-preview": {
40594059
"type": "project",
40604060
"framework": ".NETStandard,Version=v1.5",
40614061
"dependencies": {
40624062
"Microsoft.AspNetCore.Mvc": "1.0.0",
40634063
"MyTested.AspNetCore.Mvc.Caching": "1.0.0",
40644064
"MyTested.AspNetCore.Mvc.Core": "1.0.0",
4065+
"MyTested.AspNetCore.Mvc.EntityFrameworkCore": "1.0.0",
4066+
"MyTested.AspNetCore.Mvc.Options": "1.0.0",
40654067
"MyTested.AspNetCore.Mvc.Session": "1.0.0",
40664068
"MyTested.AspNetCore.Mvc.ViewFeatures": "1.0.0"
40674069
},
@@ -4072,7 +4074,7 @@
40724074
"netstandard1.5/MyTested.AspNetCore.Mvc.dll": {}
40734075
}
40744076
},
4075-
"MyTested.AspNetCore.Mvc.Caching/1.0.0-alpha": {
4077+
"MyTested.AspNetCore.Mvc.Caching/1.0.0-preview": {
40764078
"type": "project",
40774079
"framework": ".NETStandard,Version=v1.5",
40784080
"dependencies": {
@@ -4086,7 +4088,7 @@
40864088
"netstandard1.5/MyTested.AspNetCore.Mvc.Caching.dll": {}
40874089
}
40884090
},
4089-
"MyTested.AspNetCore.Mvc.Core/1.0.0-alpha": {
4091+
"MyTested.AspNetCore.Mvc.Core/1.0.0-preview": {
40904092
"type": "project",
40914093
"framework": ".NETStandard,Version=v1.5",
40924094
"dependencies": {
@@ -4104,7 +4106,7 @@
41044106
"netstandard1.5/MyTested.AspNetCore.Mvc.Core.dll": {}
41054107
}
41064108
},
4107-
"MyTested.AspNetCore.Mvc.DataAnnotations/1.0.0-alpha": {
4109+
"MyTested.AspNetCore.Mvc.DataAnnotations/1.0.0-preview": {
41084110
"type": "project",
41094111
"framework": ".NETStandard,Version=v1.5",
41104112
"dependencies": {
@@ -4118,7 +4120,21 @@
41184120
"netstandard1.5/MyTested.AspNetCore.Mvc.DataAnnotations.dll": {}
41194121
}
41204122
},
4121-
"MyTested.AspNetCore.Mvc.Licensing/1.0.0-alpha": {
4123+
"MyTested.AspNetCore.Mvc.EntityFrameworkCore/1.0.0-preview": {
4124+
"type": "project",
4125+
"framework": ".NETStandard,Version=v1.5",
4126+
"dependencies": {
4127+
"Microsoft.EntityFrameworkCore.InMemory": "1.0.0",
4128+
"MyTested.AspNetCore.Mvc.Core": "1.0.0"
4129+
},
4130+
"compile": {
4131+
"netstandard1.5/MyTested.AspNetCore.Mvc.EntityFrameworkCore.dll": {}
4132+
},
4133+
"runtime": {
4134+
"netstandard1.5/MyTested.AspNetCore.Mvc.EntityFrameworkCore.dll": {}
4135+
}
4136+
},
4137+
"MyTested.AspNetCore.Mvc.Licensing/1.0.0-preview": {
41224138
"type": "project",
41234139
"framework": ".NETStandard,Version=v1.4",
41244140
"dependencies": {
@@ -4132,7 +4148,21 @@
41324148
"netstandard1.4/MyTested.AspNetCore.Mvc.Licensing.dll": {}
41334149
}
41344150
},
4135-
"MyTested.AspNetCore.Mvc.Session/1.0.0-alpha": {
4151+
"MyTested.AspNetCore.Mvc.Options/1.0.0-preview": {
4152+
"type": "project",
4153+
"framework": ".NETStandard,Version=v1.5",
4154+
"dependencies": {
4155+
"Microsoft.Extensions.Options": "1.0.0",
4156+
"MyTested.AspNetCore.Mvc.Core": "1.0.0"
4157+
},
4158+
"compile": {
4159+
"netstandard1.5/MyTested.AspNetCore.Mvc.Options.dll": {}
4160+
},
4161+
"runtime": {
4162+
"netstandard1.5/MyTested.AspNetCore.Mvc.Options.dll": {}
4163+
}
4164+
},
4165+
"MyTested.AspNetCore.Mvc.Session/1.0.0-preview": {
41364166
"type": "project",
41374167
"framework": ".NETStandard,Version=v1.5",
41384168
"dependencies": {
@@ -4146,7 +4176,7 @@
41464176
"netstandard1.5/MyTested.AspNetCore.Mvc.Session.dll": {}
41474177
}
41484178
},
4149-
"MyTested.AspNetCore.Mvc.ViewFeatures/1.0.0-beta": {
4179+
"MyTested.AspNetCore.Mvc.ViewFeatures/1.0.0-preview": {
41504180
"type": "project",
41514181
"framework": ".NETStandard,Version=v1.5",
41524182
"dependencies": {
@@ -10372,37 +10402,47 @@
1037210402
"path": "../ApplicationParts.Web/project.json",
1037310403
"msbuildProject": "../ApplicationParts.Web/ApplicationParts.Web.xproj"
1037410404
},
10375-
"MyTested.AspNetCore.Mvc/1.0.0-alpha": {
10405+
"MyTested.AspNetCore.Mvc/1.0.0-preview": {
1037610406
"type": "project",
1037710407
"path": "../../../src/MyTested.AspNetCore.Mvc/project.json",
1037810408
"msbuildProject": "../../../src/MyTested.AspNetCore.Mvc/MyTested.AspNetCore.Mvc.xproj"
1037910409
},
10380-
"MyTested.AspNetCore.Mvc.Caching/1.0.0-alpha": {
10410+
"MyTested.AspNetCore.Mvc.Caching/1.0.0-preview": {
1038110411
"type": "project",
1038210412
"path": "../../../src/MyTested.AspNetCore.Mvc.Caching/project.json",
1038310413
"msbuildProject": "../../../src/MyTested.AspNetCore.Mvc.Caching/MyTested.AspNetCore.Mvc.Caching.xproj"
1038410414
},
10385-
"MyTested.AspNetCore.Mvc.Core/1.0.0-alpha": {
10415+
"MyTested.AspNetCore.Mvc.Core/1.0.0-preview": {
1038610416
"type": "project",
1038710417
"path": "../../../src/MyTested.AspNetCore.Mvc.Core/project.json",
1038810418
"msbuildProject": "../../../src/MyTested.AspNetCore.Mvc.Core/MyTested.AspNetCore.Mvc.Core.xproj"
1038910419
},
10390-
"MyTested.AspNetCore.Mvc.DataAnnotations/1.0.0-alpha": {
10420+
"MyTested.AspNetCore.Mvc.DataAnnotations/1.0.0-preview": {
1039110421
"type": "project",
1039210422
"path": "../../../src/MyTested.AspNetCore.Mvc.DataAnnotations/project.json",
1039310423
"msbuildProject": "../../../src/MyTested.AspNetCore.Mvc.DataAnnotations/MyTested.AspNetCore.Mvc.DataAnnotations.xproj"
1039410424
},
10395-
"MyTested.AspNetCore.Mvc.Licensing/1.0.0-alpha": {
10425+
"MyTested.AspNetCore.Mvc.EntityFrameworkCore/1.0.0-preview": {
10426+
"type": "project",
10427+
"path": "../../../src/MyTested.AspNetCore.Mvc.EntityFrameworkCore/project.json",
10428+
"msbuildProject": "../../../src/MyTested.AspNetCore.Mvc.EntityFrameworkCore/MyTested.AspNetCore.Mvc.EntityFrameworkCore.xproj"
10429+
},
10430+
"MyTested.AspNetCore.Mvc.Licensing/1.0.0-preview": {
1039610431
"type": "project",
1039710432
"path": "../../../src/MyTested.AspNetCore.Mvc.Licensing/project.json",
1039810433
"msbuildProject": "../../../src/MyTested.AspNetCore.Mvc.Licensing/MyTested.AspNetCore.Mvc.Licensing.xproj"
1039910434
},
10400-
"MyTested.AspNetCore.Mvc.Session/1.0.0-alpha": {
10435+
"MyTested.AspNetCore.Mvc.Options/1.0.0-preview": {
10436+
"type": "project",
10437+
"path": "../../../src/MyTested.AspNetCore.Mvc.Options/project.json",
10438+
"msbuildProject": "../../../src/MyTested.AspNetCore.Mvc.Options/MyTested.AspNetCore.Mvc.Options.xproj"
10439+
},
10440+
"MyTested.AspNetCore.Mvc.Session/1.0.0-preview": {
1040110441
"type": "project",
1040210442
"path": "../../../src/MyTested.AspNetCore.Mvc.Session/project.json",
1040310443
"msbuildProject": "../../../src/MyTested.AspNetCore.Mvc.Session/MyTested.AspNetCore.Mvc.Session.xproj"
1040410444
},
10405-
"MyTested.AspNetCore.Mvc.ViewFeatures/1.0.0-beta": {
10445+
"MyTested.AspNetCore.Mvc.ViewFeatures/1.0.0-preview": {
1040610446
"type": "project",
1040710447
"path": "../../../src/MyTested.AspNetCore.Mvc.ViewFeatures/project.json",
1040810448
"msbuildProject": "../../../src/MyTested.AspNetCore.Mvc.ViewFeatures/MyTested.AspNetCore.Mvc.ViewFeatures.xproj"

samples/MusicStore/MusicStore.Test/Controllers/CheckoutControllerTest.cs

Lines changed: 76 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
namespace MusicStore.Test.Controllers
22
{
33
using System.Threading;
4+
using System.Linq;
45
using Models;
56
using MusicStore.Controllers;
67
using MyTested.AspNetCore.Mvc;
@@ -51,6 +52,40 @@ public void PostAddressAndPaymentShouldHaveValidAttributes()
5152
.View(With.Default<Order>());
5253
}
5354

55+
[Fact]
56+
public void PostAddressAndPaymentShouldRedirectToCompleteWhenSuccessful()
57+
{
58+
int orderId = 10;
59+
string cartId = "CartId_A";
60+
61+
MyMvc
62+
.Controller<CheckoutController>()
63+
.WithHttpRequest(request => request
64+
.WithFormField("PromoCode", "FREE"))
65+
.WithSession(session => session
66+
.WithEntry("Session", cartId))
67+
.WithAuthenticatedUser()
68+
.WithRouteData()
69+
.WithDbContext(db => db
70+
.WithEntities<MusicStoreContext>(entities =>
71+
{
72+
var cartItems = CreateTestCartItems(
73+
cartId,
74+
itemPrice: 10,
75+
numberOfItem: 1);
76+
77+
entities.AddRange(cartItems.Select(n => n.Album).Distinct());
78+
entities.AddRange(cartItems);
79+
}))
80+
.Calling(c => c.AddressAndPayment(
81+
From.Services<MusicStoreContext>(),
82+
new Order { OrderId = orderId },
83+
CancellationToken.None))
84+
.ShouldReturn()
85+
.Redirect()
86+
.To<CheckoutController>(c => c.Complete(With.No<MusicStoreContext>(), orderId));
87+
}
88+
5489
[Fact]
5590
public void PostAddressAndPaymentShouldReturnViewWithInvalidPromoCode()
5691
{
@@ -66,46 +101,72 @@ public void PostAddressAndPaymentShouldReturnViewWithInvalidPromoCode()
66101
.View(With.Default<Order>());
67102
}
68103

104+
[Fact]
105+
public void PostAddressAndPaymentShouldReturnViewWithTheOrderIfRequestIsCancelled()
106+
{
107+
MyMvc
108+
.Controller<CheckoutController>()
109+
.Calling(c => c.AddressAndPayment(
110+
From.Services<MusicStoreContext>(),
111+
With.Default<Order>(),
112+
new CancellationToken(true)))
113+
.ShouldReturn()
114+
.View(With.Default<Order>());
115+
}
116+
69117
[Fact]
70118
public void CompleteShouldReturnViewWithCorrectIdWithCorrectOrder()
71119
{
72120
MyMvc
73121
.Controller<CheckoutController>()
74122
.WithAuthenticatedUser(user => user.WithUsername("TestUser"))
75-
.WithServiceSetupFor<MusicStoreContext>(ms =>
76-
{
77-
ms.Orders.Add(new Order
123+
.WithDbContext(dbContext =>
124+
dbContext.WithSet<MusicStoreContext, Order>(o => o.Add(new Order
78125
{
79126
OrderId = 1,
80127
Username = "TestUser"
81-
});
82-
83-
ms.SaveChanges();
84-
})
128+
})))
85129
.Calling(c => c.Complete(From.Services<MusicStoreContext>(), 1))
86130
.ShouldReturn()
87131
.View(1);
88132
}
89-
133+
90134
[Fact]
91135
public void CompleteShouldReturnViewWithErrorWithIncorrectOrder()
92136
{
93137
MyMvc
94138
.Controller<CheckoutController>()
95139
.WithAuthenticatedUser(user => user.WithUsername("TestUser"))
96-
.WithServiceSetupFor<MusicStoreContext>(ms =>
97-
{
98-
ms.Orders.Add(new Order
140+
.WithDbContext(dbContext =>
141+
dbContext.WithSet<MusicStoreContext, Order>(o => o.Add(new Order
99142
{
100143
OrderId = 1,
101144
Username = "AnotherUser"
102-
});
103-
104-
ms.SaveChanges();
105-
})
145+
})))
106146
.Calling(c => c.Complete(From.Services<MusicStoreContext>(), 1))
107147
.ShouldReturn()
108148
.View("Error");
109149
}
150+
151+
private static CartItem[] CreateTestCartItems(string cartId, decimal itemPrice, int numberOfItem)
152+
{
153+
var albums = Enumerable.Range(1, 10).Select(n =>
154+
new Album()
155+
{
156+
AlbumId = n,
157+
Price = itemPrice,
158+
}).ToArray();
159+
160+
var cartItems = Enumerable.Range(1, numberOfItem).Select(n =>
161+
new CartItem()
162+
{
163+
Count = 1,
164+
CartId = cartId,
165+
AlbumId = n % 10,
166+
Album = albums[n % 10],
167+
}).ToArray();
168+
169+
return cartItems;
170+
}
110171
}
111172
}

0 commit comments

Comments
 (0)