aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2019-11-18 19:29:37 +0800
committercrupest <crupest@outlook.com>2019-11-18 19:29:37 +0800
commit06a5d9aae4a348ff93aeaa40ac3d3ae2e7354f0f (patch)
tree047960f05911f7c841223f7b6528fe30b8e52088
parent59c10650fc36e8c79c1def088240fd90a5151250 (diff)
downloadtimeline-06a5d9aae4a348ff93aeaa40ac3d3ae2e7354f0f.tar.gz
timeline-06a5d9aae4a348ff93aeaa40ac3d3ae2e7354f0f.tar.bz2
timeline-06a5d9aae4a348ff93aeaa40ac3d3ae2e7354f0f.zip
Write tests and fix bugs found via tests.
-rw-r--r--Timeline.Tests/Controllers/PersonalTimelineControllerTest.cs2
-rw-r--r--Timeline.Tests/Helpers/ResponseAssertions.cs2
-rw-r--r--Timeline.Tests/IntegratedTests/PersonalTimelineTest.cs135
-rw-r--r--Timeline/Entities/TimelineEntity.cs17
-rw-r--r--Timeline/Models/Timeline.cs18
-rw-r--r--Timeline/Resources/Services/Exception.Designer.cs2
-rw-r--r--Timeline/Resources/Services/Exception.resx2
-rw-r--r--Timeline/Services/TimelineService.cs2
8 files changed, 157 insertions, 23 deletions
diff --git a/Timeline.Tests/Controllers/PersonalTimelineControllerTest.cs b/Timeline.Tests/Controllers/PersonalTimelineControllerTest.cs
index a7cbb37e..819017c2 100644
--- a/Timeline.Tests/Controllers/PersonalTimelineControllerTest.cs
+++ b/Timeline.Tests/Controllers/PersonalTimelineControllerTest.cs
@@ -309,7 +309,7 @@ namespace Timeline.Tests.Controllers
var req = new TimelinePropertyChangeRequest
{
Description = "",
- Visibility = Entities.TimelineVisibility.Private
+ Visibility = TimelineVisibility.Private
};
_service.Setup(s => s.ChangeProperty(username, req)).Returns(Task.CompletedTask);
var result = await _controller.TimelineChangeProperty(username, req);
diff --git a/Timeline.Tests/Helpers/ResponseAssertions.cs b/Timeline.Tests/Helpers/ResponseAssertions.cs
index 0e6f215b..6d764c68 100644
--- a/Timeline.Tests/Helpers/ResponseAssertions.cs
+++ b/Timeline.Tests/Helpers/ResponseAssertions.cs
@@ -88,7 +88,7 @@ namespace Timeline.Tests.Helpers
return new AndWhichConstraint<HttpResponseMessageAssertions, T>(this, null);
}
- var result = JsonConvert.DeserializeObject<T>(body);
+ var result = JsonConvert.DeserializeObject<T>(body); // TODO! catch and throw on bad format
return new AndWhichConstraint<HttpResponseMessageAssertions, T>(this, result);
}
}
diff --git a/Timeline.Tests/IntegratedTests/PersonalTimelineTest.cs b/Timeline.Tests/IntegratedTests/PersonalTimelineTest.cs
index 9629fc0a..aaa6215c 100644
--- a/Timeline.Tests/IntegratedTests/PersonalTimelineTest.cs
+++ b/Timeline.Tests/IntegratedTests/PersonalTimelineTest.cs
@@ -7,6 +7,7 @@ using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
+using Timeline.Models;
using Timeline.Models.Http;
using Timeline.Tests.Helpers;
using Timeline.Tests.Helpers.Authentication;
@@ -22,6 +23,64 @@ namespace Timeline.Tests.IntegratedTests
}
+ [Fact]
+ public async Task Member_Should_Work()
+ {
+ const string getUrl = "users/user/timeline";
+ const string changeUrl = "users/user/timeline/op/member";
+ using var client = await Factory.CreateClientAsUser();
+
+ async Task AssertMembers(IList<string> members)
+ {
+ var res = await client.GetAsync(getUrl);
+ res.Should().HaveStatusCode(200)
+ .And.HaveJsonBody<BaseTimelineInfo>()
+ .Which.Members.Should().NotBeNull().And.BeEquivalentTo(members);
+ }
+
+ async Task AssertEmptyMembers()
+ {
+ var res = await client.GetAsync(getUrl);
+ res.Should().HaveStatusCode(200)
+ .And.HaveJsonBody<BaseTimelineInfo>()
+ .Which.Members.Should().NotBeNull().And.BeEmpty();
+ }
+
+ await AssertEmptyMembers();
+ {
+ var res = await client.PostAsJsonAsync(changeUrl,
+ new TimelineMemberChangeRequest { Add = new List<string> { "admin", "usernotexist" } });
+ res.Should().HaveStatusCode(400)
+ .And.HaveCommonBody()
+ .Which.Code.Should().Be(ErrorCodes.Http.Timeline.ChangeMemberUserNotExist);
+ }
+ {
+ var res = await client.PostAsJsonAsync(changeUrl,
+ new TimelineMemberChangeRequest { Remove = new List<string> { "admin", "usernotexist" } });
+ res.Should().HaveStatusCode(400)
+ .And.HaveCommonBody()
+ .Which.Code.Should().Be(ErrorCodes.Http.Timeline.ChangeMemberUserNotExist);
+ }
+ {
+ var res = await client.PostAsJsonAsync(changeUrl,
+ new TimelineMemberChangeRequest { Add = new List<string> { "admin" }, Remove = new List<string> { "admin" } });
+ res.Should().HaveStatusCode(200);
+ await AssertEmptyMembers();
+ }
+ {
+ var res = await client.PostAsJsonAsync(changeUrl,
+ new TimelineMemberChangeRequest { Add = new List<string> { "admin" } });
+ res.Should().HaveStatusCode(200);
+ await AssertMembers(new List<string> { "admin" });
+ }
+ {
+ var res = await client.PostAsJsonAsync(changeUrl,
+ new TimelineMemberChangeRequest { Remove = new List<string> { "admin" } });
+ res.Should().HaveStatusCode(200);
+ await AssertEmptyMembers();
+ }
+ }
+
[Theory]
[InlineData(AuthType.None, 200, 401, 401, 401, 401)]
[InlineData(AuthType.User, 200, 200, 403, 200, 403)]
@@ -58,5 +117,81 @@ namespace Timeline.Tests.IntegratedTests
res.Should().HaveStatusCode(opMemberAdmin);
}
}
+
+ [Fact]
+ public async Task Permission_GetPost()
+ {
+ const string userUrl = "users/user/timeline/posts";
+ const string adminUrl = "users/admin/timeline/posts";
+ { // default visibility is registered
+ {
+ using var client = Factory.CreateDefaultClient();
+ var res = await client.GetAsync(userUrl);
+ res.Should().HaveStatusCode(403);
+ }
+
+ {
+ using var client = await Factory.CreateClientAsUser();
+ var res = await client.GetAsync(adminUrl);
+ res.Should().HaveStatusCode(200);
+ }
+ }
+
+ { // change visibility to public
+ {
+ using var client = await Factory.CreateClientAsUser();
+ var res = await client.PostAsJsonAsync("users/user/timeline/op/property",
+ new TimelinePropertyChangeRequest { Visibility = TimelineVisibility.Public });
+ res.Should().HaveStatusCode(200);
+ }
+ {
+ using var client = Factory.CreateDefaultClient();
+ var res = await client.GetAsync(userUrl);
+ res.Should().HaveStatusCode(200);
+ }
+ }
+
+ { // change visibility to private
+ {
+ using var client = await Factory.CreateClientAsAdmin();
+ {
+ var res = await client.PostAsJsonAsync("users/user/timeline/op/property",
+ new TimelinePropertyChangeRequest { Visibility = TimelineVisibility.Private });
+ res.Should().HaveStatusCode(200);
+ }
+ {
+ var res = await client.PostAsJsonAsync("users/admin/timeline/op/property",
+ new TimelinePropertyChangeRequest { Visibility = TimelineVisibility.Private });
+ res.Should().HaveStatusCode(200);
+ }
+ }
+ {
+ using var client = Factory.CreateDefaultClient();
+ var res = await client.GetAsync(userUrl);
+ res.Should().HaveStatusCode(403);
+ }
+ { // user can't read admin's
+ using var client = await Factory.CreateClientAsUser();
+ var res = await client.GetAsync(adminUrl);
+ res.Should().HaveStatusCode(403);
+ }
+ { // admin can read user's
+ using var client = await Factory.CreateClientAsAdmin();
+ var res = await client.GetAsync(userUrl);
+ res.Should().HaveStatusCode(200);
+ }
+ { // add member
+ using var client = await Factory.CreateClientAsAdmin();
+ var res = await client.PostAsJsonAsync("users/admin/timeline/op/member",
+ new TimelineMemberChangeRequest { Add = new List<string> { "user" } });
+ res.Should().HaveStatusCode(200);
+ }
+ { // now user can read admin's
+ using var client = await Factory.CreateClientAsUser();
+ var res = await client.GetAsync(adminUrl);
+ res.Should().HaveStatusCode(200);
+ }
+ }
+ }
}
}
diff --git a/Timeline/Entities/TimelineEntity.cs b/Timeline/Entities/TimelineEntity.cs
index f5e22a54..9cacfcae 100644
--- a/Timeline/Entities/TimelineEntity.cs
+++ b/Timeline/Entities/TimelineEntity.cs
@@ -2,25 +2,10 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
+using Timeline.Models;
namespace Timeline.Entities
{
- public enum TimelineVisibility
- {
- /// <summary>
- /// All people including those without accounts.
- /// </summary>
- Public,
- /// <summary>
- /// Only people signed in.
- /// </summary>
- Register,
- /// <summary>
- /// Only member.
- /// </summary>
- Private
- }
-
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "This is entity object.")]
[Table("timelines")]
public class TimelineEntity
diff --git a/Timeline/Models/Timeline.cs b/Timeline/Models/Timeline.cs
index 26012878..85fefff5 100644
--- a/Timeline/Models/Timeline.cs
+++ b/Timeline/Models/Timeline.cs
@@ -1,11 +1,25 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
using Timeline.Entities;
namespace Timeline.Models
{
+ public enum TimelineVisibility
+ {
+ /// <summary>
+ /// All people including those without accounts.
+ /// </summary>
+ Public,
+ /// <summary>
+ /// Only people signed in.
+ /// </summary>
+ Register,
+ /// <summary>
+ /// Only member.
+ /// </summary>
+ Private
+ }
+
public class TimelinePostInfo
{
public long Id { get; set; }
diff --git a/Timeline/Resources/Services/Exception.Designer.cs b/Timeline/Resources/Services/Exception.Designer.cs
index 970c306d..1b46f9e9 100644
--- a/Timeline/Resources/Services/Exception.Designer.cs
+++ b/Timeline/Resources/Services/Exception.Designer.cs
@@ -286,7 +286,7 @@ namespace Timeline.Resources.Services {
}
/// <summary>
- /// Looks up a localized string similar to An exception happened when do operation {} on the {} member on timeline..
+ /// Looks up a localized string similar to An exception happened when do operation {0} on the {1} member on timeline..
/// </summary>
internal static string TimelineMemberOperationExceptionDetail {
get {
diff --git a/Timeline/Resources/Services/Exception.resx b/Timeline/Resources/Services/Exception.resx
index c8f6676a..1d9c0037 100644
--- a/Timeline/Resources/Services/Exception.resx
+++ b/Timeline/Resources/Services/Exception.resx
@@ -193,7 +193,7 @@
<value>An exception happened when add or remove member on timeline.</value>
</data>
<data name="TimelineMemberOperationExceptionDetail" xml:space="preserve">
- <value>An exception happened when do operation {} on the {} member on timeline.</value>
+ <value>An exception happened when do operation {0} on the {1} member on timeline.</value>
</data>
<data name="TimelineNameBadFormatException" xml:space="preserve">
<value>Timeline name is of bad format. If this is a personal timeline, it means the username is of bad format and inner exception should be a UsernameBadFormatException.</value>
diff --git a/Timeline/Services/TimelineService.cs b/Timeline/Services/TimelineService.cs
index 494beb11..1d199aae 100644
--- a/Timeline/Services/TimelineService.cs
+++ b/Timeline/Services/TimelineService.cs
@@ -458,7 +458,7 @@ namespace Timeline.Services
if (list != null)
{
Dictionary<string, int> result = new Dictionary<string, int>();
- var count = 0;
+ var count = list.Count;
for (var index = 0; index < count; index++)
{
var username = list[index];