Skip to content

Commit 77547e5

Browse files
committed
fix(tests): apply VSTest and test failure fixes from branch
Re-apply intentional fixes from commits 575eaa0..9eff1d4 on top of the clean NUnit conversion. Changes applied: - FieldWorksTests.cs: Use rooted temp paths for cross-platform compat - IVwCacheDaTests.cs: Add COM cleanup in OneTimeTearDown and TearDown - RespellingTests.cs: Use real Mediator instead of Mock (sealed class) - SCTextEnumTests.cs: Migrate from Rhino.Mocks to Moq - PUAInstallerTests.cs: Use DistFiles relative to SourceDirectory These fixes address test failures discovered during VSTest migration without reintroducing the swapped assertion arguments from the original buggy conversion.
1 parent c9f6dfe commit 77547e5

6 files changed

Lines changed: 196 additions & 82 deletions

File tree

Src/Common/FieldWorks/FieldWorksTests/FieldWorksTests.cs

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// (http://www.gnu.org/licenses/lgpl-2.1.html)
44

55
using System;
6+
using System.IO;
67
using NUnit.Framework;
78
using SIL.LCModel;
89
using SIL.LCModel.Utils;
@@ -17,6 +18,22 @@ namespace SIL.FieldWorks
1718
[TestFixture]
1819
public class FieldWorksTests
1920
{
21+
// Use rooted paths in tests to avoid FwDirectoryFinder.ProjectsDirectory registry lookup.
22+
// ProjectId.CleanUpNameForType only looks up ProjectsDirectory for non-rooted paths.
23+
// Use Path.Combine with temp path for cross-platform compatibility (Windows, Linux/Docker).
24+
private static readonly string TestProjectPath =
25+
Path.Combine(Path.GetTempPath(), "FwTests", "monkey", "monkey.fwdata");
26+
private static readonly string OtherProjectPath =
27+
Path.Combine(Path.GetTempPath(), "FwTests", "primate", "primate.fwdata");
28+
29+
/// <summary>
30+
/// Creates a ProjectId with a rooted path to avoid registry access.
31+
/// </summary>
32+
private static ProjectId CreateTestProjectId(string path)
33+
{
34+
return new ProjectId(BackendProviderType.kXML, path);
35+
}
36+
2037
#region GetProjectMatchStatus tests
2138
/// ------------------------------------------------------------------------------------
2239
/// <summary>
@@ -28,12 +45,11 @@ public void GetProjectMatchStatus_Match()
2845
{
2946
ReflectionHelper.SetField(typeof(FieldWorks), "s_fSingleProcessMode", false);
3047
ReflectionHelper.SetField(typeof(FieldWorks), "s_fWaitingForUserOrOtherFw", false);
31-
ReflectionHelper.SetField(typeof(FieldWorks), "s_projectId",
32-
new ProjectId(BackendProviderType.kXML, "monkey"));
48+
ReflectionHelper.SetField(typeof(FieldWorks), "s_projectId", CreateTestProjectId(TestProjectPath));
3349

3450
Assert.That(ReflectionHelper.GetResult(
3551
typeof(FieldWorks), "GetProjectMatchStatus",
36-
new ProjectId(BackendProviderType.kXML, "monkey")), Is.EqualTo(ProjectMatch.ItsMyProject));
52+
CreateTestProjectId(TestProjectPath)), Is.EqualTo(ProjectMatch.ItsMyProject));
3753
}
3854

3955
/// ------------------------------------------------------------------------------------
@@ -46,12 +62,11 @@ public void GetProjectMatchStatus_NotMatch()
4662
{
4763
ReflectionHelper.SetField(typeof(FieldWorks), "s_fSingleProcessMode", false);
4864
ReflectionHelper.SetField(typeof(FieldWorks), "s_fWaitingForUserOrOtherFw", false);
49-
ReflectionHelper.SetField(typeof(FieldWorks), "s_projectId",
50-
new ProjectId(BackendProviderType.kXML, "primate"));
65+
ReflectionHelper.SetField(typeof(FieldWorks), "s_projectId", CreateTestProjectId(OtherProjectPath));
5166

5267
Assert.That(ReflectionHelper.GetResult(
5368
typeof(FieldWorks), "GetProjectMatchStatus",
54-
new ProjectId(BackendProviderType.kXML, "monkey")), Is.EqualTo(ProjectMatch.ItsNotMyProject));
69+
CreateTestProjectId(TestProjectPath)), Is.EqualTo(ProjectMatch.ItsNotMyProject));
5570
}
5671

5772
/// ------------------------------------------------------------------------------------
@@ -69,7 +84,7 @@ public void GetProjectMatchStatus_DontKnow()
6984

7085
Assert.That(ReflectionHelper.GetResult(
7186
typeof(FieldWorks), "GetProjectMatchStatus",
72-
new ProjectId(BackendProviderType.kXML, "monkey")), Is.EqualTo(ProjectMatch.DontKnowYet));
87+
CreateTestProjectId(TestProjectPath)), Is.EqualTo(ProjectMatch.DontKnowYet));
7388
}
7489

7590
/// ------------------------------------------------------------------------------------
@@ -83,12 +98,11 @@ public void GetProjectMatchStatus_WaitingForFw()
8398
{
8499
ReflectionHelper.SetField(typeof(FieldWorks), "s_fSingleProcessMode", false);
85100
ReflectionHelper.SetField(typeof(FieldWorks), "s_fWaitingForUserOrOtherFw", true);
86-
ReflectionHelper.SetField(typeof(FieldWorks), "s_projectId",
87-
new ProjectId(BackendProviderType.kXML, "monkey"));
101+
ReflectionHelper.SetField(typeof(FieldWorks), "s_projectId", CreateTestProjectId(TestProjectPath));
88102

89103
Assert.That(ReflectionHelper.GetResult(
90104
typeof(FieldWorks), "GetProjectMatchStatus",
91-
new ProjectId(BackendProviderType.kXML, "monkey")), Is.EqualTo(ProjectMatch.WaitingForUserOrOtherFw));
105+
CreateTestProjectId(TestProjectPath)), Is.EqualTo(ProjectMatch.WaitingForUserOrOtherFw));
92106
}
93107

94108
/// ------------------------------------------------------------------------------------
@@ -101,12 +115,11 @@ public void GetProjectMatchStatus_SingleProcessMode()
101115
{
102116
ReflectionHelper.SetField(typeof(FieldWorks), "s_fSingleProcessMode", true);
103117
ReflectionHelper.SetField(typeof(FieldWorks), "s_fWaitingForUserOrOtherFw", true);
104-
ReflectionHelper.SetField(typeof(FieldWorks), "s_projectId",
105-
new ProjectId(BackendProviderType.kXML, "monkey"));
118+
ReflectionHelper.SetField(typeof(FieldWorks), "s_projectId", CreateTestProjectId(TestProjectPath));
106119

107120
Assert.That(ReflectionHelper.GetResult(
108121
typeof(FieldWorks), "GetProjectMatchStatus",
109-
new ProjectId(BackendProviderType.kXML, "monkey")), Is.EqualTo(ProjectMatch.SingleProcessMode));
122+
CreateTestProjectId(TestProjectPath)), Is.EqualTo(ProjectMatch.SingleProcessMode));
110123
}
111124

112125
#endregion

Src/Common/FwUtils/FwUtilsTests/IVwCacheDaTests.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,20 @@ public class IVwCacheDaCppTests
3131
/// <summary>The IVwCacheDa object</summary>
3232
protected IVwCacheDa m_IVwCacheDa;
3333

34+
/// <summary>
35+
/// One-time cleanup after all tests in this fixture complete.
36+
/// Forces GC to run and wait for finalizers to prevent crashes during VSTest cleanup.
37+
/// </summary>
38+
[OneTimeTearDown]
39+
public void FixtureTearDown()
40+
{
41+
// Force garbage collection and wait for finalizers to complete.
42+
// This ensures COM objects are released while native DLLs are still loaded.
43+
GC.Collect();
44+
GC.WaitForPendingFinalizers();
45+
GC.Collect();
46+
}
47+
3448
/// ------------------------------------------------------------------------------------
3549
/// <summary>
3650
/// Setup done before each test.
@@ -51,6 +65,19 @@ public void TestSetup()
5165
[TearDown]
5266
public void TestTeardown()
5367
{
68+
// Release COM objects to prevent access violations during VSTest cleanup.
69+
// The native VwCacheDa must be released before the process exits, otherwise
70+
// the CLR finalizer thread may try to release it after native DLLs are unloaded.
71+
if (m_IVwCacheDa != null)
72+
{
73+
// Clear any cached data first
74+
m_IVwCacheDa.ClearAllData();
75+
76+
// Release the COM object reference
77+
Marshal.ReleaseComObject(m_IVwCacheDa);
78+
m_IVwCacheDa = null;
79+
m_ISilDataAccess = null;
80+
}
5481
}
5582

5683
/// ------------------------------------------------------------------------------------

Src/LexText/Morphology/MorphologyEditorDllTests/RespellingTests.cs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ public void CanUndoChangeMultipleOccurrences_InSingleSegment()
105105
respellUndoaction.KeepAnalyses = true;
106106
respellUndoaction.UpdateLexicalEntries = true;
107107

108-
Mediator mediator = MockRepository.GenerateStub<Mediator>();
109-
respellUndoaction.DoIt(mediator);
108+
// Use the real Mediator from TestSetup instead of mocking (Mediator is sealed)
109+
respellUndoaction.DoIt(m_mediator);
110110

111111
Assert.That(para.Contents.Text, Is.EqualTo(ksParaText.Replace(ksWordToReplace, ksNewWord)));
112112
Assert.That(m_actionHandler.UndoableSequenceCount, Is.EqualTo(2));
@@ -128,8 +128,8 @@ public void CanRespellShortenWord()
128128
respellUndoaction.KeepAnalyses = true;
129129
respellUndoaction.UpdateLexicalEntries = true;
130130

131-
Mediator mediator = MockRepository.GenerateStub<Mediator>();
132-
respellUndoaction.DoIt(mediator);
131+
// Use the real Mediator from TestSetup instead of mocking (Mediator is sealed)
132+
respellUndoaction.DoIt(m_mediator);
133133

134134
Assert.That(para.Contents.Text, Is.EqualTo(ksParaText.Replace(ksWordToReplace, ksNewWord)));
135135
Assert.That(m_actionHandler.UndoableSequenceCount, Is.EqualTo(2));
@@ -155,8 +155,8 @@ public void CanRespellMultiMorphemicWordAndKeepUsages()
155155
respellUndoaction.CopyAnalyses = true; // in the dialog this is always true?
156156
respellUndoaction.UpdateLexicalEntries = true;
157157

158-
Mediator mediator = MockRepository.GenerateStub<Mediator>();
159-
respellUndoaction.DoIt(mediator);
158+
// Use the real Mediator from TestSetup instead of mocking (Mediator is sealed)
159+
respellUndoaction.DoIt(m_mediator);
160160

161161
Assert.That(para.SegmentsOS[0].AnalysesRS[2].Analysis.MorphBundlesOS.Count, Is.EqualTo(0), "Unexpected morph bundle contents for 'be'");
162162
Assert.That(para.SegmentsOS[0].AnalysesRS[3].Analysis.MorphBundlesOS.Count, Is.EqualTo(2), "Wrong morph bundle count for 'multimorphemic'");
@@ -187,8 +187,8 @@ public void CanUndoChangeMultipleOccurrences_InMultipleSegmentsInPara()
187187
respellUndoaction.KeepAnalyses = true;
188188
respellUndoaction.UpdateLexicalEntries = true;
189189

190-
Mediator mediator = MockRepository.GenerateStub<Mediator>();
191-
respellUndoaction.DoIt(mediator);
190+
// Use the real Mediator from TestSetup instead of mocking (Mediator is sealed)
191+
respellUndoaction.DoIt(m_mediator);
192192

193193
Assert.That(para.Contents.Text, Is.EqualTo(ksParaText.Replace(ksWordToReplace, ksNewWord)));
194194
Assert.That(m_actionHandler.UndoableSequenceCount, Is.EqualTo(2));
@@ -216,8 +216,8 @@ public void CanUndoChangeMultipleOccurrences_InSingleSegment_Glosses()
216216
respellUndoaction.KeepAnalyses = true;
217217
respellUndoaction.UpdateLexicalEntries = true;
218218

219-
Mediator mediator = MockRepository.GenerateStub<Mediator>();
220-
respellUndoaction.DoIt(mediator);
219+
// Use the real Mediator from TestSetup instead of mocking (Mediator is sealed)
220+
respellUndoaction.DoIt(m_mediator);
221221

222222
Assert.That(para.Contents.Text, Is.EqualTo(ksParaText.Replace(ksWordToReplace, ksNewWord)));
223223
Assert.That(para.SegmentsOS[0].AnalysesRS[0] is IWfiGloss, Is.True);
@@ -256,8 +256,8 @@ public void CanUndoChangeMultipleOccurrences_InMultipleSegmentsInPara_Glosses()
256256
respellUndoaction.KeepAnalyses = true;
257257
respellUndoaction.UpdateLexicalEntries = true;
258258

259-
Mediator mediator = MockRepository.GenerateStub<Mediator>();
260-
respellUndoaction.DoIt(mediator);
259+
// Use the real Mediator from TestSetup instead of mocking (Mediator is sealed)
260+
respellUndoaction.DoIt(m_mediator);
261261

262262
Assert.That(para.Contents.Text, Is.EqualTo(ksParaText.Replace(ksWordToReplace, ksNewWord)));
263263
Assert.That(para.SegmentsOS[0].AnalysesRS[0] is IWfiGloss, Is.True);
@@ -310,8 +310,8 @@ public void CanUndoChangeSingleOccurrence_InSingleSegment()
310310
respellUndoaction.PreserveCase = true;
311311
respellUndoaction.UpdateLexicalEntries = true;
312312

313-
Mediator mediator = MockRepository.GenerateStub<Mediator>();
314-
respellUndoaction.DoIt(mediator);
313+
// Use the real Mediator from TestSetup instead of mocking (Mediator is sealed)
314+
respellUndoaction.DoIt(m_mediator);
315315

316316
Assert.That(para.Contents.Text, Is.EqualTo(ksParaText.Replace(ksWordToReplace, ksNewWord)));
317317
Assert.That(m_actionHandler.UndoableSequenceCount, Is.EqualTo(2));

Src/ParatextImport/ParatextImportTests/SCTextEnumTests.cs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
using System.Collections;
1010
using System.Collections.Generic;
1111
using NUnit.Framework;
12-
using Rhino.Mocks;
12+
using Moq;
1313
using SIL.LCModel.Core.Scripture;
1414
using SIL.LCModel;
1515
using SIL.LCModel.Utils;
@@ -1052,8 +1052,9 @@ public void ConvertingTextSegments_MainImportDomain()
10521052
// Save settings before enumerating, which will get the styles hooked up in the mapping list
10531053
m_settings.SaveSettings();
10541054

1055-
m_converters = MockRepository.GenerateStub<IEncConverters>();
1056-
m_converters.Stub(x => x["UPPERCASE"]).Return(new DummyEncConverter());
1055+
var mockConverters = new Mock<IEncConverters>();
1056+
mockConverters.Setup(x => x["UPPERCASE"]).Returns(new DummyEncConverter());
1057+
m_converters = mockConverters.Object;
10571058
ISCTextEnum textEnum = GetTextEnum(ImportDomain.Main,
10581059
new ScrReference(40, 0, 0, ScrVers.English),
10591060
new ScrReference(40, 1, 2, ScrVers.English));
@@ -1168,8 +1169,9 @@ public void ConvertingTextSegments_InterleavedBt()
11681169
// Save settings before enumerating, which will get the styles hooked up in the mapping list
11691170
m_settings.SaveSettings();
11701171

1171-
m_converters = MockRepository.GenerateStub<IEncConverters>();
1172-
m_converters.Stub(x => x["UPPERCASE"]).Return(new DummyEncConverter());
1172+
var mockConverters = new Mock<IEncConverters>();
1173+
mockConverters.Setup(x => x["UPPERCASE"]).Returns(new DummyEncConverter());
1174+
m_converters = mockConverters.Object;
11731175
ISCTextEnum textEnum = GetTextEnum(ImportDomain.Main,
11741176
new ScrReference(40, 0, 0, ScrVers.English),
11751177
new ScrReference(40, 1, 2, ScrVers.English));
@@ -1236,8 +1238,9 @@ public void ConvertingTextSegments_BTImportDomain()
12361238
// Save settings before enumerating, which will get the styles hooked up in the mapping list
12371239
m_settings.SaveSettings();
12381240

1239-
m_converters = MockRepository.GenerateStub<IEncConverters>();
1240-
m_converters.Stub(x => x["UPPERCASE"]).Return(new DummyEncConverter());
1241+
var mockConverters = new Mock<IEncConverters>();
1242+
mockConverters.Setup(x => x["UPPERCASE"]).Returns(new DummyEncConverter());
1243+
m_converters = mockConverters.Object;
12411244
ISCTextEnum textEnum = GetTextEnum(ImportDomain.BackTrans,
12421245
new ScrReference(40, 0, 0, ScrVers.English),
12431246
new ScrReference(40, 1, 2, ScrVers.English));

Src/UnicodeCharEditor/UnicodeCharEditorTests/PUAInstallerTests.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,9 @@ private static bool InitializeIcuData()
300300
{
301301
try
302302
{
303-
var baseDir = FwDirectoryFinder.DataDirectory;
303+
// Use DistFiles relative to source directory for worktree/dev builds,
304+
// not the installed DataDirectory which may point to a different repo.
305+
var baseDir = Path.Combine(Path.GetDirectoryName(FwDirectoryFinder.SourceDirectory), "DistFiles");
304306
zipIn = new ZipInputStream(File.OpenRead(Path.Combine(baseDir, string.Format("Icu{0}.zip", CustomIcu.Version))));
305307
}
306308
catch (Exception e1)

0 commit comments

Comments
 (0)