Skip to content

Commit 4e27ee6

Browse files
rmunnmyieye
andauthored
Prevent creating objects with duplicated GUIDs (#367)
* Check before creating an object; if an object with the same GUID exists, throw * Add tests * Fix exception message (the rule is global across all types) Fixes #365. This should not affect FW, since the FooFactory.Create(guid) method is not used in FieldWorks. FW Lite uses it, so that FW Lite can create LCM objects with GUIDs that match the GUIDs of objects that are being synchronized from other projects. And FW Lite will be changed to expect an InvalidOperationError to be thrown in case of a duplicated GUID being created, and handle the resulting merge conflict accordingly. --------- Co-authored-by: Tim Haasdyk <tim_haasdyk@sil.org>
1 parent 44fc874 commit 4e27ee6

2 files changed

Lines changed: 38 additions & 2 deletions

File tree

src/SIL.LCModel/LcmGenerate/factory.vm.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,19 @@ internal partial class ${className}$classSfx : I${className}$classSfx, ILcmFacto
6464
if (m_cache.ServiceLocator.GetInstance<I${className}Repository>().Singleton != null)
6565
throw new InvalidOperationException("Can not create more than one ${className}");
6666
#end
67-
if (guid == Guid.Empty) guid = Guid.NewGuid();
67+
if (guid == Guid.Empty)
68+
{
69+
guid = Guid.NewGuid();
70+
}
71+
else
72+
{
73+
if (m_cache.ServiceLocator.GetInstance<ICmObjectRepository>().IsValidObjectId(guid))
74+
{
75+
// IsValidObjectId returns true if the GUID exists, i.e. you could call GetObject and get something.
76+
// But here in Create(), it's an error if the GUID already exists: duplicate GUIDs are not allowed.
77+
throw new InvalidOperationException("Can not create more than one object with identical GUIDs");
78+
}
79+
}
6880
int hvo = m_cache.InternalServices.DataReader.GetNextRealHvo();
6981
var newby = new $className(m_cache, hvo, guid);
7082
#if ( $ownerStatus != "required")

tests/SIL.LCModel.Tests/DomainImpl/FactoryAdditionsTests.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
// Copyright (c) 2015 SIL International
1+
// Copyright (c) 2015 SIL International
22
// This software is licensed under the LGPL, version 2.1 or later
33
// (http://www.gnu.org/licenses/lgpl-2.1.html)
44

5+
using System;
56
using System.Collections.Generic;
67
using System.Linq;
78
using NUnit.Framework;
@@ -132,5 +133,28 @@ public void LexSenseFactoryCreate_NullGlossTss_DoesNotThrow()
132133
Assert.DoesNotThrow(() => sense = lexSenseFactory.Create(entry, msa, nullGloss));
133134
Assert.AreEqual(0, sense.Gloss.StringCount);
134135
}
136+
137+
[Test]
138+
public void Create_WithDuplicateGuid_SameType_Throws()
139+
{
140+
var guid = Guid.NewGuid();
141+
var factory = Cache.ServiceLocator.GetInstance<ILexEntryFactory>();
142+
factory.Create(guid);
143+
144+
Assert.That(() => factory.Create(guid),
145+
Throws.TypeOf<InvalidOperationException>().With.Message.Contains("identical GUIDs"));
146+
}
147+
148+
[Test]
149+
public void Create_WithDuplicateGuid_DifferentType_Throws()
150+
{
151+
var guid = Guid.NewGuid();
152+
var entryFactory = Cache.ServiceLocator.GetInstance<ILexEntryFactory>();
153+
entryFactory.Create(guid);
154+
155+
var pictureFactory = Cache.ServiceLocator.GetInstance<ICmPictureFactory>();
156+
Assert.That(() => pictureFactory.Create(guid),
157+
Throws.TypeOf<InvalidOperationException>().With.Message.Contains("identical GUIDs"));
158+
}
135159
}
136160
}

0 commit comments

Comments
 (0)