Skip to content

Commit 6363c30

Browse files
committed
[WordService] Add XML docs and tests
1 parent 72c914a commit 6363c30

File tree

2 files changed

+280
-12
lines changed

2 files changed

+280
-12
lines changed

Backend.Tests/Services/WordServiceTests.cs

Lines changed: 225 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,35 @@ public void Setup()
2424
_wordService = new WordService(_wordRepo);
2525
}
2626

27+
[Test]
28+
public void TestImportWordsDoesNotChangeTimestamps()
29+
{
30+
const string existingCreated = "existing-created";
31+
const string existingModified = "existing-modified";
32+
33+
var importedWords = _wordService.ImportWords([
34+
new Word { ProjectId = ProjId },
35+
new Word { ProjectId = ProjId, Created = existingCreated, Modified = existingModified },
36+
]).Result;
37+
38+
Assert.That(importedWords, Has.Count.EqualTo(2));
39+
Assert.That(importedWords[0].Created, Is.Not.Empty);
40+
Assert.That(importedWords[0].Modified, Is.Not.Empty);
41+
Assert.That(importedWords[1].Created, Is.EqualTo(existingCreated));
42+
Assert.That(importedWords[1].Modified, Is.EqualTo(existingModified));
43+
Assert.That(_wordRepo.GetAllFrontier(ProjId).Result, Has.Count.EqualTo(2));
44+
}
45+
46+
[Test]
47+
public void TestImportWordsEmptyInputReturnsEmptyAndDoesNotChangeRepo()
48+
{
49+
var importedWords = _wordService.ImportWords([]).Result;
50+
51+
Assert.That(importedWords, Is.Empty);
52+
Assert.That(_wordRepo.GetAllFrontier(ProjId).Result, Is.Empty);
53+
Assert.That(_wordRepo.GetAllWords(ProjId).Result, Is.Empty);
54+
}
55+
2756
[Test]
2857
public void TestCreateAddsUserId()
2958
{
@@ -39,6 +68,28 @@ public void TestCreateDoesNotAddDuplicateUserId()
3968
Assert.That(word.EditedBy, Has.Count.EqualTo(1));
4069
}
4170

71+
[Test]
72+
public void TestCreateBlankUserIdDoesNotAppendEditedBy()
73+
{
74+
var word = _wordService.Create("", new Word { EditedBy = ["other"] }).Result;
75+
76+
Assert.That(word.EditedBy, Has.Count.EqualTo(1));
77+
Assert.That(word.EditedBy.Last(), Is.EqualTo("other"));
78+
}
79+
80+
[Test]
81+
public void TestCreatePreservesCreatedAndUpdatesModified()
82+
{
83+
const string existingCreated = "existing-created";
84+
const string existingModified = "existing-modified";
85+
86+
var createdWord = _wordService.Create(UserId,
87+
new Word { ProjectId = ProjId, Created = existingCreated, Modified = existingModified }).Result;
88+
89+
Assert.That(createdWord.Created, Is.EqualTo(existingCreated));
90+
Assert.That(createdWord.Modified, Is.Not.EqualTo(existingModified));
91+
}
92+
4293
[Test]
4394
public void TestDeleteAudioBadInput()
4495
{
@@ -48,10 +99,8 @@ public void TestDeleteAudioBadInput()
4899
Assert.That(_wordService.DeleteAudio("non-proj-id", UserId, wordInFrontier.Id, fileName).Result, Is.Null);
49100
Assert.That(_wordService.DeleteAudio(ProjId, UserId, "non-word-id", fileName).Result, Is.Null);
50101

51-
var ex = Assert.Throws<AggregateException>(() =>
52-
{
53-
_ = _wordService.DeleteAudio(ProjId, UserId, wordInFrontier.Id, "non-file-name").Result;
54-
});
102+
var ex = Assert.Throws<AggregateException>(
103+
() => _wordService.DeleteAudio(ProjId, UserId, wordInFrontier.Id, "non-file-name").Wait());
55104
Assert.That(ex?.InnerException, Is.InstanceOf<ArgumentException>());
56105
}
57106

@@ -126,6 +175,22 @@ public void TestDeleteFrontierWordCopiesToWordsAndRemovesFrontier()
126175
Assert.That(_wordRepo.GetAllFrontier(ProjId).Result, Is.Empty);
127176
}
128177

178+
[Test]
179+
public void TestDeleteFrontierWordPreservesHistoryAndAppendsDeletedId()
180+
{
181+
var word = _wordRepo.Create(new Word { ProjectId = ProjId, History = ["older-1", "older-2"] }).Result;
182+
183+
var deletedId = _wordService.DeleteFrontierWord(ProjId, UserId, word.Id).Result;
184+
Assert.That(deletedId, Is.Not.Null);
185+
var deletedWord = _wordRepo.GetWord(ProjId, deletedId).Result;
186+
var expectedHistoryPrefix = new[] { "older-1", "older-2" };
187+
188+
Assert.That(deletedWord, Is.Not.Null);
189+
Assert.That(deletedWord.History, Has.Count.EqualTo(3));
190+
Assert.That(deletedWord.History.Take(2), Is.EqualTo(expectedHistoryPrefix));
191+
Assert.That(deletedWord.History.Last(), Is.EqualTo(word.Id));
192+
}
193+
129194
[Test]
130195
public void TestRestoreFrontierWordAlreadyInFrontierThrows()
131196
{
@@ -137,10 +202,20 @@ public void TestRestoreFrontierWordAlreadyInFrontierThrows()
137202
Throws.TypeOf<AggregateException>());
138203
}
139204

205+
[Test]
206+
public void TestRestoreFrontierWordDeletedWordThrows()
207+
{
208+
var deletedWord = _wordRepo.Add(new Word { ProjectId = ProjId, Accessibility = Status.Deleted }).Result;
209+
210+
var ex = Assert.Throws<AggregateException>(
211+
() => _wordService.RestoreFrontierWord(ProjId, deletedWord.Id).Wait());
212+
Assert.That(ex?.InnerException, Is.InstanceOf<ArgumentException>());
213+
}
214+
140215
[Test]
141216
public void TestRestoreFrontierWordMissingWordReturnsFalse()
142217
{
143-
var word = _wordRepo.Add(new Word { ProjectId = ProjId }).Result;
218+
_wordRepo.Add(new Word { ProjectId = ProjId }).Wait();
144219

145220
var result = _wordService.RestoreFrontierWord(ProjId, "NotAnId").Result;
146221

@@ -206,6 +281,19 @@ public void TestUpdateUsingCitationForm()
206281
Assert.That(vernUpdate.UsingCitationForm, Is.False);
207282
}
208283

284+
[Test]
285+
public void TestUpdateDoesNotDuplicateExistingHistoryId()
286+
{
287+
var word = _wordRepo.Create(new Word { ProjectId = ProjId }).Result;
288+
var oldId = word.Id;
289+
word.History.Add(oldId);
290+
291+
var updatedWord = _wordService.Update(UserId, word).Result;
292+
293+
Assert.That(updatedWord, Is.Not.Null);
294+
Assert.That(updatedWord.History.Count(id => id == oldId), Is.EqualTo(1));
295+
}
296+
209297
[Test]
210298
public void TestFindContainingWordNoFrontier()
211299
{
@@ -291,5 +379,137 @@ public void TestFindContainingWordSameVernEmptySensesSameDoms()
291379
var dupId = _wordService.FindContainingWord(newWord).Result;
292380
Assert.That(dupId, Is.EqualTo(oldWord.Id));
293381
}
382+
383+
[Test]
384+
public void TestFindContainingWordIgnoresWordsNotInFrontier()
385+
{
386+
var oldWordInWordsOnly = Util.RandomWord(ProjId);
387+
oldWordInWordsOnly = _wordRepo.Add(oldWordInWordsOnly).Result;
388+
389+
var newWord = Util.RandomWord(ProjId);
390+
newWord.Vernacular = oldWordInWordsOnly.Vernacular;
391+
newWord.Senses = oldWordInWordsOnly.Senses.Select(s => s.Clone()).ToList();
392+
393+
var dupId = _wordService.FindContainingWord(newWord).Result;
394+
395+
Assert.That(dupId, Is.Null);
396+
}
397+
398+
[Test]
399+
public void TestMergeReplaceFrontierUpdatesAndDeletes()
400+
{
401+
var childToReplace = _wordRepo.Create(Util.RandomWord(ProjId)).Result;
402+
var childToDelete = _wordRepo.Create(Util.RandomWord(ProjId)).Result;
403+
var parent = Util.RandomWord(ProjId);
404+
parent.Id = childToReplace.Id;
405+
parent.Vernacular = "merged-vern";
406+
407+
var mergedParents = _wordService
408+
.MergeReplaceFrontier(ProjId, UserId, [parent], [childToReplace.Id, childToDelete.Id]).Result;
409+
410+
Assert.That(mergedParents, Is.Not.Null);
411+
Assert.That(mergedParents, Has.Count.EqualTo(1));
412+
413+
var mergedParent = mergedParents.Single();
414+
Assert.That(mergedParent.Id, Is.Not.EqualTo(childToReplace.Id));
415+
Assert.That(mergedParent.History.Last(), Is.EqualTo(childToReplace.Id));
416+
Assert.That(mergedParent.EditedBy.Last(), Is.EqualTo(UserId));
417+
418+
var frontier = _wordRepo.GetAllFrontier(ProjId).Result;
419+
Assert.That(frontier, Has.Count.EqualTo(1));
420+
Assert.That(frontier.Single().Id, Is.EqualTo(mergedParent.Id));
421+
422+
var deletedCopy = _wordRepo.GetAllWords(ProjId).Result
423+
.Find(w => w.Accessibility == Status.Deleted && w.History.Contains(childToDelete.Id));
424+
Assert.That(deletedCopy, Is.Not.Null);
425+
Assert.That(deletedCopy.EditedBy.Last(), Is.EqualTo(UserId));
426+
}
427+
428+
[Test]
429+
public void TestMergeReplaceFrontierWrongProjectThrows()
430+
{
431+
var parent = Util.RandomWord("other-project");
432+
433+
var ex = Assert.Throws<AggregateException>(
434+
() => _wordService.MergeReplaceFrontier(ProjId, UserId, [parent], []).Wait());
435+
Assert.That(ex?.InnerException, Is.InstanceOf<ArgumentException>());
436+
}
437+
438+
[Test]
439+
public void TestMergeReplaceFrontierDeleteOnlyReturnsEmpty()
440+
{
441+
var kid1 = _wordRepo.Create(new Word { ProjectId = ProjId }).Result;
442+
var kid2 = _wordRepo.Create(new Word { ProjectId = ProjId }).Result;
443+
444+
var mergedParents = _wordService.MergeReplaceFrontier(ProjId, UserId, [], [kid1.Id, kid2.Id]).Result;
445+
446+
Assert.That(mergedParents, Is.Not.Null);
447+
Assert.That(mergedParents, Is.Empty);
448+
Assert.That(_wordRepo.GetAllFrontier(ProjId).Result, Is.Empty);
449+
450+
var allWords = _wordRepo.GetAllWords(ProjId).Result;
451+
Assert.That(allWords.Any(w => w.Accessibility == Status.Deleted && w.History.Contains(kid1.Id)), Is.True);
452+
Assert.That(allWords.Any(w => w.Accessibility == Status.Deleted && w.History.Contains(kid2.Id)), Is.True);
453+
}
454+
455+
[Test]
456+
public void TestRevertMergeReplaceFrontierDeletesAndRestores()
457+
{
458+
var wordToRestore = _wordRepo.Add(new Word { ProjectId = ProjId }).Result;
459+
var frontierWordToDelete = _wordRepo.Create(new Word { ProjectId = ProjId }).Result;
460+
461+
var result = _wordService.RevertMergeReplaceFrontier(
462+
ProjId, UserId, [wordToRestore.Id], [frontierWordToDelete.Id]).Result;
463+
464+
Assert.That(result, Is.True);
465+
Assert.That(_wordRepo.IsInFrontier(ProjId, wordToRestore.Id).Result, Is.True);
466+
Assert.That(_wordRepo.IsInFrontier(ProjId, frontierWordToDelete.Id).Result, Is.False);
467+
468+
var deletedCopy = _wordRepo.GetAllWords(ProjId).Result
469+
.Find(w => w.Accessibility == Status.Deleted && w.History.Contains(frontierWordToDelete.Id));
470+
Assert.That(deletedCopy, Is.Not.Null);
471+
Assert.That(deletedCopy.EditedBy.Last(), Is.EqualTo(UserId));
472+
}
473+
474+
[Test]
475+
public void TestRevertMergeReplaceFrontierMissingRestoreReturnsFalse()
476+
{
477+
var frontierWordToDelete = _wordRepo.Create(new Word { ProjectId = ProjId }).Result;
478+
479+
var result = _wordService.RevertMergeReplaceFrontier(
480+
ProjId, UserId, ["missing-id"], [frontierWordToDelete.Id]).Result;
481+
482+
Assert.That(result, Is.False);
483+
Assert.That(_wordRepo.IsInFrontier(ProjId, frontierWordToDelete.Id).Result, Is.False);
484+
}
485+
486+
[Test]
487+
public void TestRevertMergeReplaceFrontierOverlappingIdsThrows()
488+
{
489+
var word = _wordRepo.Create(new Word { ProjectId = ProjId }).Result;
490+
491+
var ex = Assert.Throws<AggregateException>(
492+
() => _wordService.RevertMergeReplaceFrontier(ProjId, UserId, [word.Id], [word.Id]).Wait());
493+
Assert.That(ex?.InnerException, Is.InstanceOf<ArgumentException>());
494+
}
495+
496+
[Test]
497+
public void TestRevertMergeReplaceFrontierNoOpReturnsTrueAndLeavesStateUnchanged()
498+
{
499+
_wordRepo.Create(new Word { ProjectId = ProjId }).Wait();
500+
_wordRepo.Add(new Word { ProjectId = ProjId }).Wait();
501+
502+
var wordsBefore = _wordRepo.GetAllWords(ProjId).Result.Select(w => w.Id).OrderBy(id => id).ToList();
503+
var frontierBefore = _wordRepo.GetAllFrontier(ProjId).Result.Select(w => w.Id).OrderBy(id => id).ToList();
504+
505+
var result = _wordService.RevertMergeReplaceFrontier(ProjId, UserId, [], []).Result;
506+
507+
var wordsAfter = _wordRepo.GetAllWords(ProjId).Result.Select(w => w.Id).OrderBy(id => id).ToList();
508+
var frontierAfter = _wordRepo.GetAllFrontier(ProjId).Result.Select(w => w.Id).OrderBy(id => id).ToList();
509+
510+
Assert.That(result, Is.True);
511+
Assert.That(wordsAfter, Is.EqualTo(wordsBefore));
512+
Assert.That(frontierAfter, Is.EqualTo(frontierBefore));
513+
}
294514
}
295515
}

0 commit comments

Comments
 (0)