Skip to content

Commit 9e03ba6

Browse files
Docstrings
1 parent b31fe13 commit 9e03ba6

File tree

7 files changed

+202
-17
lines changed

7 files changed

+202
-17
lines changed

exercise.tests/Helpers/UserTestCases.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
namespace exercise.tests.Helpers
22
{
3+
/// <summary>
4+
/// Provides reusable user-centric <see cref="TestCaseData"/> scenarios for integration tests.
5+
/// </summary>
36
public static class UserTestCases
47
{
8+
/// <summary>
9+
/// Supplies registration payloads that should produce successful responses.
10+
/// </summary>
511
public static IEnumerable<TestCaseData> ValidRegisterCases()
612
{
713
yield return new TestCaseData("validuser", "[email protected]", "ValidPass1!");
814
yield return new TestCaseData("user-name", "[email protected]", "SecurePass9#");
915
yield return new TestCaseData("user1name", "[email protected]", "StrongPass$1");
1016
}
1117

18+
/// <summary>
19+
/// Supplies registration payloads that should fail validation.
20+
/// </summary>
1221
public static IEnumerable<TestCaseData> InvalidRegisterCases()
1322
{
1423
yield return new TestCaseData("validuser", "plainaddress", "ValidPass1!").SetName("Invalid: Invalid email format (register)");
@@ -19,6 +28,9 @@ public static IEnumerable<TestCaseData> InvalidRegisterCases()
1928
yield return new TestCaseData("validuser", "[email protected]", "NoSpecialChar1").SetName("Invalid: Missing special character (register)");
2029
}
2130

31+
/// <summary>
32+
/// Supplies credential pairs that represent successful login attempts.
33+
/// </summary>
2234
public static IEnumerable<TestCaseData> ValidLoginCases()
2335
{
2436
yield return new TestCaseData("[email protected]", "SuperHash!4");
@@ -27,6 +39,9 @@ public static IEnumerable<TestCaseData> ValidLoginCases()
2739
//yield return new TestCaseData("[email protected]", "ValidPass1!");
2840
}
2941

42+
/// <summary>
43+
/// Supplies credential pairs that should fail authentication.
44+
/// </summary>
3045
public static IEnumerable<TestCaseData> InvalidLoginCases()
3146
{
3247
yield return new TestCaseData("[email protected]", "short1!").SetName("Invalid: Password too short (login)");
@@ -37,4 +52,4 @@ public static IEnumerable<TestCaseData> InvalidLoginCases()
3752
yield return new TestCaseData("[email protected]", "ValidPass1!").SetName("Invalid: Invalid email domain (login)");
3853
}
3954
}
40-
}
55+
}

exercise.tests/Helpers/UsernameValidationCases.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,14 @@
22

33
namespace exercise.tests.Helpers
44
{
5+
/// <summary>
6+
/// Centralises username validation scenarios for reuse across integration tests.
7+
/// </summary>
58
public static class UsernameValidationTestData
69
{
10+
/// <summary>
11+
/// Yields username samples alongside the expected message outcome for each endpoint.
12+
/// </summary>
713
public static IEnumerable<TestCaseData> UsernameValidationMessageCases()
814
{
915
string[] endpoints = new string[]
@@ -53,6 +59,9 @@ public static IEnumerable<TestCaseData> UsernameValidationMessageCases()
5359
}
5460

5561
}
62+
/// <summary>
63+
/// Yields username samples alongside the expected status code for each endpoint.
64+
/// </summary>
5665
public static IEnumerable<TestCaseData> UsernameValidationStatusCases()
5766
{
5867
string[] endpoints = new string[]

exercise.tests/IntegrationTests/EndpointStatusTest.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
namespace exercise.tests.IntegrationTests
88
{
9+
/// <summary>
10+
/// Integration smoke tests that ensure unexpected endpoints return consistent error responses.
11+
/// </summary>
912
[TestFixture]
1013
public class EndpointStatusTest
1114
{
@@ -27,6 +30,9 @@ public void TearDown()
2730
_factory.Dispose();
2831
}
2932

33+
/// <summary>
34+
/// Verifies POST requests to unknown routes return a 404 with the canonical payload.
35+
/// </summary>
3036
[Test]
3137
public async Task PostCheckInvalidEndpoint()
3238
{
@@ -57,6 +63,9 @@ public async Task PostCheckInvalidEndpoint()
5763
Assert.That(message?["message"]?.GetValue<string>(), Is.EqualTo("Endpoint not found"));
5864
}
5965

66+
/// <summary>
67+
/// Verifies GET requests to unknown routes return a 404 with the canonical payload.
68+
/// </summary>
6069
[Test]
6170
public async Task GetCheckInvalidEndpoint()
6271
{

exercise.tests/IntegrationTests/PostTests.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

88
namespace exercise.tests.IntegrationTests
99
{
10+
/// <summary>
11+
/// Integration tests covering the lifecycle of posts via the public API endpoints.
12+
/// </summary>
1013
[TestFixture]
1114
public class PostTests
1215
{
@@ -28,6 +31,9 @@ public void TearDown()
2831
_factory.Dispose();
2932
}
3033

34+
/// <summary>
35+
/// Ensures GET /posts returns a successful response and the expected payload structure.
36+
/// </summary>
3137
[Test]
3238
public async Task GetAllPosts()
3339
{
@@ -77,6 +83,9 @@ public async Task GetAllPosts()
7783
}
7884
}
7985

86+
/// <summary>
87+
/// Confirms creating a post with valid data yields an HTTP 201 Created status.
88+
/// </summary>
8089
[Test]
8190
public async Task SuccessfulCreatePostStatus()
8291
{
@@ -106,6 +115,9 @@ public async Task SuccessfulCreatePostStatus()
106115
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.Created));
107116
}
108117

118+
/// <summary>
119+
/// Validates the create post response body mirrors the request payload and contracts.
120+
/// </summary>
109121
[Test]
110122
public async Task SuccessfulCreatePostMessage()
111123
{
@@ -156,6 +168,12 @@ public async Task SuccessfulCreatePostMessage()
156168
Assert.That(data["createdAt"], Is.Not.Null);
157169
}
158170

171+
/// <summary>
172+
/// Checks that invalid create post requests surface the correct HTTP status codes.
173+
/// </summary>
174+
/// <param name="userid">The author identifier to include in the payload.</param>
175+
/// <param name="content">The post body content being validated.</param>
176+
/// <param name="expected">The status code the API should return.</param>
159177
[TestCase(9999999, "somecontent", HttpStatusCode.NotFound)]
160178
[TestCase(5, "", HttpStatusCode.BadRequest)]
161179
[TestCase(5, " ", HttpStatusCode.BadRequest)]
@@ -186,6 +204,12 @@ public async Task FailedlCreatePostStatus(int userid, string content, HttpStatus
186204
Assert.That(response.StatusCode, Is.EqualTo(expected));
187205
}
188206

207+
/// <summary>
208+
/// Ensures the validation error message matches expectations for rejected create post attempts.
209+
/// </summary>
210+
/// <param name="userid">The author identifier placed in the request.</param>
211+
/// <param name="content">The invalid content variation under test.</param>
212+
/// <param name="expectedmessage">The message the API should return.</param>
189213
[TestCase(9999999, "somecontent", "Invalid userID")]
190214
[TestCase(5, "", "Content cannot be empty")]
191215
[TestCase(5, " ", "Content cannot be empty")]
@@ -219,6 +243,9 @@ public async Task FailedCreatePostMessage(int userid, string content, string exp
219243
Assert.That(message["data"], Is.Null);
220244
Assert.That(message["timestamp"], Is.Not.Null);
221245
}
246+
/// <summary>
247+
/// Validates that deleting an existing post succeeds and a second deletion reports not found.
248+
/// </summary>
222249
[Test]
223250
public async Task DeletePostById_SuccessAndNotFound()
224251
{
@@ -257,6 +284,12 @@ public async Task DeletePostById_SuccessAndNotFound()
257284

258285

259286

287+
/// <summary>
288+
/// Exercises the PATCH /posts/{id} endpoint across happy path and error scenarios.
289+
/// </summary>
290+
/// <param name="postId">The identifier of the post to update.</param>
291+
/// <param name="newContent">The updated content supplied.</param>
292+
/// <param name="expected">The anticipated HTTP status code.</param>
260293
[TestCase(5, "Updated content", HttpStatusCode.OK)]
261294
[TestCase(9999999, "Updated content", HttpStatusCode.NotFound)]
262295
[TestCase(5, "", HttpStatusCode.BadRequest)]

exercise.tests/IntegrationTests/UserTests.cs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99

1010
namespace exercise.tests.IntegrationTests
1111
{
12+
/// <summary>
13+
/// Integration tests exercising the user management endpoints end-to-end via the API surface.
14+
/// </summary>
1215
[TestFixture]
1316
public class UserTests
1417
{
@@ -30,7 +33,13 @@ public void TearDown()
3033
_factory.Dispose();
3134
}
3235

33-
// ad test cases for approved usernames, emails
36+
/// <summary>
37+
/// Confirms that valid registration payloads yield an HTTP 201 Created response.
38+
/// </summary>
39+
/// <remarks>Test cases come from <see cref="UserTestCases.ValidRegisterCases"/> and are uniquified at runtime to avoid clashes.</remarks>
40+
/// <param name="username">The base username supplied by the data source.</param>
41+
/// <param name="email">The base email supplied by the data source.</param>
42+
/// <param name="password">The password candidate to register with.</param>
3443
[Test, TestCaseSource(typeof(UserTestCases), nameof(UserTestCases.ValidRegisterCases))]
3544
public async Task Register_success(string username, string email, string password)
3645
{
@@ -62,6 +71,13 @@ public async Task Register_success(string username, string email, string passwor
6271
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.Created));
6372
}
6473

74+
/// <summary>
75+
/// Verifies the registration endpoint rejects malformed payloads with non-Created responses.
76+
/// </summary>
77+
/// <remarks>Inputs are provided by <see cref="UserTestCases.InvalidRegisterCases"/>.</remarks>
78+
/// <param name="username">The attempted username for registration.</param>
79+
/// <param name="email">The attempted email for registration.</param>
80+
/// <param name="password">The password candidate under test.</param>
6581
[Test, TestCaseSource(typeof(UserTestCases), nameof(UserTestCases.InvalidRegisterCases))]
6682
public async Task Register_Failure(string username, string email, string password)
6783
{
@@ -96,6 +112,12 @@ public async Task Register_Failure(string username, string email, string passwor
96112
}
97113

98114

115+
/// <summary>
116+
/// Ensures valid credentials receive an HTTP 200 response and a token payload.
117+
/// </summary>
118+
/// <remarks>Credentials are sourced from <see cref="UserTestCases.ValidLoginCases"/>.</remarks>
119+
/// <param name="email">The email address to authenticate with.</param>
120+
/// <param name="password">The password paired with the supplied email.</param>
99121
[Test, TestCaseSource(typeof(UserTestCases), nameof(UserTestCases.ValidLoginCases))]
100122
public async Task Login_success(string email, string password)
101123
{
@@ -127,6 +149,12 @@ public async Task Login_success(string email, string password)
127149
Assert.That(message["data"]["token"], Is.Not.Null);
128150
}
129151

152+
/// <summary>
153+
/// Asserts that invalid login attempts fail with the expected HTTP status and message.
154+
/// </summary>
155+
/// <remarks>Negative credential combinations come from <see cref="UserTestCases.InvalidLoginCases"/>.</remarks>
156+
/// <param name="email">The incorrect email supplied to the login endpoint.</param>
157+
/// <param name="password">The incorrect password paired with the email.</param>
130158
[Test, TestCaseSource(typeof(UserTestCases), nameof(UserTestCases.InvalidLoginCases))]
131159
public async Task Login_failure(string email, string password)
132160
{
@@ -161,6 +189,9 @@ public async Task Login_failure(string email, string password)
161189

162190
}
163191

192+
/// <summary>
193+
/// Validates that a PATCH with complete, valid fields updates an existing user successfully.
194+
/// </summary>
164195
[Test]
165196
public async Task UpdateUserSuccess()
166197
{
@@ -181,6 +212,9 @@ public async Task UpdateUserSuccess()
181212
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
182213
}
183214

215+
/// <summary>
216+
/// Ensures PATCH requests with no mutable fields return a bad request response.
217+
/// </summary>
184218
[Test]
185219
public async Task UpdateUserNullFieldsOnly()
186220
{
@@ -195,6 +229,9 @@ public async Task UpdateUserNullFieldsOnly()
195229
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
196230
}
197231

232+
/// <summary>
233+
/// Confirms the API rejects usernames that violate allowed formatting rules.
234+
/// </summary>
198235
[Test]
199236
public async Task UpdateUserInvalidUsername()
200237
{
@@ -212,6 +249,9 @@ public async Task UpdateUserInvalidUsername()
212249
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
213250
}
214251

252+
/// <summary>
253+
/// Confirms GitHub username updates honor the same validation rules as the standalone validator.
254+
/// </summary>
215255
[Test]
216256
public async Task UpdateUserInvalidGitHubUsername()
217257
{
@@ -229,6 +269,9 @@ public async Task UpdateUserInvalidGitHubUsername()
229269
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
230270
}
231271

272+
/// <summary>
273+
/// Verifies email updates are blocked when the address fails format validation.
274+
/// </summary>
232275
[Test]
233276
public async Task UpdateUserInvalidEmail()
234277
{
@@ -246,6 +289,9 @@ public async Task UpdateUserInvalidEmail()
246289
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
247290
}
248291

292+
/// <summary>
293+
/// Confirms passwords that do not meet the complexity requirements are rejected on update.
294+
/// </summary>
249295
[Test]
250296
public async Task UpdateUserInvalidPassword()
251297
{
@@ -263,6 +309,9 @@ public async Task UpdateUserInvalidPassword()
263309
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
264310
}
265311

312+
/// <summary>
313+
/// Ensures role updates outside the defined enum range produce a bad request.
314+
/// </summary>
266315
[Test]
267316
public async Task UpdateUserInvalidRole()
268317
{
@@ -280,6 +329,9 @@ public async Task UpdateUserInvalidRole()
280329
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
281330
}
282331

332+
/// <summary>
333+
/// Verifies the API prevents changing a username to one that is already in use.
334+
/// </summary>
283335
[Test]
284336
public async Task UpdateUserUsernameExists()
285337
{
@@ -297,6 +349,9 @@ public async Task UpdateUserUsernameExists()
297349
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
298350
}
299351

352+
/// <summary>
353+
/// Verifies the API prevents reusing an existing GitHub username value.
354+
/// </summary>
300355
[Test]
301356
public async Task UpdateUserGitHubUsernameExists()
302357
{
@@ -314,6 +369,9 @@ public async Task UpdateUserGitHubUsernameExists()
314369
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
315370
}
316371

372+
/// <summary>
373+
/// Verifies the API prevents reusing an existing email address value.
374+
/// </summary>
317375
[Test]
318376
public async Task UpdateUserEmailExists()
319377
{
@@ -331,6 +389,11 @@ public async Task UpdateUserEmailExists()
331389
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
332390
}
333391

392+
/// <summary>
393+
/// Ensures retrieving users by id returns 200 for known users and 404 for missing ones.
394+
/// </summary>
395+
/// <param name="id">The user id sent to the endpoint.</param>
396+
/// <param name="responseStatus">The expected HTTP status code.</param>
334397
[TestCase("1", HttpStatusCode.OK)]
335398
[TestCase("10000000", HttpStatusCode.NotFound)]
336399
public async Task GetUserByIdTest(string id, HttpStatusCode responseStatus)

0 commit comments

Comments
 (0)