Skip to content

Commit 7871032

Browse files
authored
Merge pull request #592 from xBimTeam/develop
Dec 2024 release - v6.0
2 parents 8c4bfb2 + d3fbb28 commit 7871032

31 files changed

+4491
-154
lines changed

README.md

+25-32
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,9 @@ _[**B**uilding **I**nformation **M**odelling](https://en.wikipedia.org/wiki/Buil
2020
the .NET platform. This library enables software developers to easily read, write, validate and interrogate data in
2121
the buildingSmart [IFC formats](https://en.wikipedia.org/wiki/Industry_Foundation_Classes), using any .NET language.
2222

23-
As of version 6.0 XbimEssentials includes support for `.netstandard2.0`, `.netstandard2.1`, `.net6.0` and `.net8.0`. Supporting `netstandard2.0` provides support .NET Framework 4.7.2 upwards.
24-
Earlier .NET Framewaork versions may work, but we can't provide any support for them.
25-
26-
23+
As of version 6.0 XbimEssentials includes support for `.netstandard2.0`, `.netstandard2.1`, `.net6.0` and `net8.0`.
24+
Supporting `netstandard2.0` provides support .NET Framework 4.7.2 upwards.
25+
Earlier .NET Framework versions may work, but we can't provide any support for them.
2726

2827
## Background / Motivation ##
2928

@@ -35,7 +34,9 @@ This library supports *STEP*, *IfcXml* and *IfcZip* formats, and enables you to
3534
[Ifc4 Addendum 2](http://www.buildingsmart-tech.org/specifications/ifc-releases/ifc4-add2)).
3635

3736
The wider XBIM toolkit contains additional repositories with libraries to read and write related Open BIM formats including
38-
[COBie](https://github.com/xBimTeam/XbimExchange) and BIM Collaboration Format ([BCF](https://github.com/xBimTeam/XbimBCF))
37+
[COBie](https://github.com/xBimTeam/XbimCobieExpress) and BIM Collaboration Format ([BCF](https://github.com/xBimTeam/XbimBCF))
38+
39+
xbim Toolkit also supports IFC model verification with IDS using our [IDS Library](https://github.com/xBimTeam/Xbim.IDS.Validator).
3940

4041
In order to visualise 3D Geometries you will need to include the [Xbim.Geometry](https://github.com/xBimTeam/XbimGeometry)
4142
package which provides full support for geometric, topological operations and visualisation.
@@ -50,14 +51,20 @@ of STEP/Express parsing, 3D graphics - enabling you to work at a higher level th
5051
Please see our [ChangeLog](CHANGELOG.md) for details on what's new and what you need to upgrade.
5152
In particular, please **note the following section copied here:**
5253

53-
> **BREAKING CHANGE**: V6 implements a new mechanism for discovering internal resources and uses standard (.net Dependency Injection patterns)[https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection] for managing services internally.
54-
> `Xbim.Common` now introduces an internal DI service that you can optionally integrate with your own DI implementation, for providing Logging services, and configuring xbim service behaviour. E.g. Invoking:
55-
> ` XbimServices.Current.ConfigureServices(s => s.AddXbimToolkit(opt => opt.UseMemoryModel().UseLoggerFactory(yourloggerFactory)));
56-
> registers the Toolkit internal dependencies, uses an In-memory model and inserts your configured ILoggerFactory into the service in place of our default one.
54+
> **BREAKING CHANGE**: xbim Toolkit V6 implements a new mechanism for registering internal resources and makes use of standard [.net Dependency Injection patterns](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection) for managing services internally.
55+
> `Xbim.Common` now introduces an internal DI service that you can optionally integrate with your own DI implementation,
56+
> for providing Logging services, and configuring xbim service behaviour such as the model provider to use. E.g. Invoking:
57+
>
58+
> `XbimServices.Current.ConfigureServices(s => s.AddXbimToolkit(opt => opt.UseMemoryModel().UseLoggerFactory(yourloggerFactory)));`
59+
>
60+
> registers the Toolkit internal dependencies, configures an In-memory model-provider and adds an existing ILoggerFactory into the service in place of our default one.
5761
> `IfcStore.ModelProviderFactory` has been deprecated as this is provided for by the above mechanism
58-
> The persistent EsentModel is now available automatically through IfcStore (on Windows) so there is no need for the `UseHeuristicModelProvider()` 'ceremony' to ensure Esent is used.
59-
> Note: The default Logging implementation has been removed from Toolkit to reduce the amount of dependencies. To enable is a simple matter of adding logging to the Xbim Services.
60-
> See (Example)[https://github.com/xBimTeam/XbimEssentials/blob/b3fce6f40a31fb87a75b24888a4e20740a378e31/Tests/DependencyInjectionTests.cs#L96]
62+
> The persistent **EsentModel** is now available automatically through IfcStore (on Windows) so there is no need for the `UseHeuristicModelProvider()` 'ceremony'
63+
> to ensure Esent is used although you can specify it explicitly with `XbimServices.Current.ConfigureServices(s => s.AddXbimToolkit(opt => opt.UseHeuristicModel())`
64+
>
65+
> Note: The default Logging implementation has been removed from Toolkit to reduce the amount of external dependencies.
66+
> To enable is a simple matter of adding your preferred logging implementation to the Xbim Services.
67+
> See [Example](https://github.com/xBimTeam/XbimEssentials/blob/b3fce6f40a31fb87a75b24888a4e20740a378e31/Tests/DependencyInjectionTests.cs#L96)
6168
6269

6370
## Code Examples
@@ -230,7 +237,7 @@ and an ability open sementic model data from a JSON structure.
230237

231238
You will need Visual Studio 2019 or newer to compile the Solution. Visual Studio 2022 is recommended.
232239
The [free VS 2022 Community Edition](https://visualstudio.microsoft.com/downloads/) should work fine.
233-
Other IDEs such as JetBrains Rider and VS Code should also be fine.
240+
Other IDEs such as JetBrains Rider and VS Code should work.
234241

235242
### Using the library
236243

@@ -248,7 +255,6 @@ dependent packages directly. (Which is necessary for .NET Core currently, as Ess
248255

249256
## Toolkit Overview
250257

251-
![XBIM Libraries - high level dependencies](docs/img/XBIM-Architecture-0_1.png)
252258

253259
### How to use it?
254260

@@ -278,15 +284,11 @@ the licence agreements.
278284

279285
The core XBIM library makes use of the following 3rd party software packages, under their associated licences:
280286

281-
* 'OpenCASCADE' Geometry Engine : http://www.opencascade.org/ - OPEN CASCADE Public License
282-
* 'Gardens Point Parser Generator' http://gppg.codeplex.com/ - New BSD Licence
283-
* Elements of '3D Tools' WPF library http://3dtools.codeplex.com/ - MS Permissive Licence
284-
* Log4net : http://logging.apache.org/log4net/ - Apache 2.0 Licence
285-
* NPOI : http://npoi.codeplex.com - Apache 2.0 Licence
286-
* NewtonSoft JSON : http://json.codeplex.com/ - MIT Licence
287+
* 'Gardens Point Parser Generator' https://github.com/KommuSoft/Gardens-Point-Parser-Generator - New BSD Licence
288+
* 'OpenCASCADE' Geometry Engine : http://www.opencascade.org/ - GNU Lesser General Public License (LGPL) version 2.1, with additional [exception](https://dev.opencascade.org/doc/overview/html/occt_public_license.html#occt_lgpl_exception)
287289

288-
All 3rd party licences are permissive-style licences. We actively avoid Copyleft/GPL style licences to retain
289-
compatibility with our CDDL licence - meaning you can use the XBIM Toolkit in a closed-source commercial software package.
290+
All 3rd party licences are permissive-style licences. We actively avoid Strong Copyleft/GPL style licences to retain
291+
compatibility with our CDDL licence - meaning you can use the XBIM Toolkit in a closed-source commercial software package.
290292

291293
## Support & Help
292294

@@ -299,16 +301,7 @@ For bugs, and improvements, please use the GitHub Issues of the relevant reposit
299301
If you have a question, or need some help, you may find the
300302
[Stackoverflow xbim](https://stackoverflow.com/questions/tagged/xbim) tag a good place to start.
301303

302-
## Acknowledgements
303-
While we do not qualify anymore for open source licenses of JetBrains, we would like to acknowledge the
304-
good work and thank [JetBrains](https://www.jetbrains.com/) for supporting the XbimToolkit project with
305-
free open source [Resharper](https://www.jetbrains.com/resharper/) licenses in the past.
306-
307-
[![ReSharper Logo](https://raw.githubusercontent.com/xBimTeam/XbimWindowsUI/master/ReadmeResources/icon_ReSharper.png)](https://www.jetbrains.com/resharper/)
308-
309-
Thanks also to Microsoft Azure DevOps for the use of [Azure Pipelines](https://azure.microsoft.com/en-us/services/devops/pipelines/)
310-
to automate our builds.
311304

312305
## Getting Involved
313306

314-
If you'd like to get involved and contribute to this project, please read the [CONTRIBUTING ](https://github.com/xBimTeam/XbimEssentials/blob/master/CONTRIBUTING.md) page or contact the Project Coordinators @CBenghi and @martin1cerny.
307+
If you'd like to get involved and contribute to this project, please read the [CONTRIBUTING](https://github.com/xBimTeam/XbimEssentials/blob/master/CONTRIBUTING.md) page or contact the Project Coordinators @CBenghi and @martin1cerny.

Tests/ChunkedDictionaryTests.cs

+219
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Xbim.Common.Collections;
4+
using Microsoft.VisualStudio.TestTools.UnitTesting;
5+
using System.Linq;
6+
7+
namespace Xbim.Essentials.Tests
8+
{
9+
[TestClass]
10+
public class ChunkedDictionaryTests
11+
{
12+
13+
[TestMethod]
14+
public void Init_ChunkSizeCanBeTotalSize()
15+
{
16+
var dictionary = new ChunkedDictionary<int, string>(2, 2);
17+
var chunks = dictionary.GetChunkCount();
18+
Assert.AreEqual(1, chunks, "Chunk count should be 1 when chunk size equals total size.");
19+
}
20+
21+
[TestMethod]
22+
public void Init_OnlyOneChunkInitializedAtTheBeginning()
23+
{
24+
var dictionary = new ChunkedDictionary<int, string>(20, 2);
25+
var chunks = dictionary.GetChunkCount();
26+
Assert.AreEqual(1, chunks, "Only one chunk should be initialized at the beginning.");
27+
}
28+
29+
[TestMethod]
30+
public void Add_SingleItem_ItemExists()
31+
{
32+
var dictionary = new ChunkedDictionary<int, string>(10);
33+
dictionary.Add(1, "One");
34+
35+
Assert.IsTrue(dictionary.ContainsKey(1), "Key should exist after adding.");
36+
Assert.AreEqual("One", dictionary[1], "Value should match the added value.");
37+
}
38+
39+
[TestMethod]
40+
public void Remove_ByKey_ItemRemoved()
41+
{
42+
var dictionary = new ChunkedDictionary<int, string>(10);
43+
dictionary.Add(1, "One");
44+
var removed = dictionary.Remove(1);
45+
46+
Assert.IsTrue(removed, "Item should be removed successfully.");
47+
Assert.IsFalse(dictionary.ContainsKey(1), "Key should not exist after removal.");
48+
}
49+
50+
[TestMethod]
51+
public void Remove_ByKeyValuePair_ItemRemoved()
52+
{
53+
var dictionary = new ChunkedDictionary<int, string>(10);
54+
dictionary.Add(1, "One");
55+
var removed = dictionary.Remove(new KeyValuePair<int, string>(1, "One"));
56+
57+
Assert.IsTrue(removed, "Item should be removed successfully.");
58+
Assert.IsFalse(dictionary.ContainsKey(1), "Key should not exist after removal.");
59+
}
60+
61+
[TestMethod]
62+
public void TryGetValue_ExistingItem_ReturnsTrueAndCorrectValue()
63+
{
64+
var dictionary = new ChunkedDictionary<int, string>(10);
65+
dictionary.Add(1, "One");
66+
67+
string value;
68+
var result = dictionary.TryGetValue(1, out value);
69+
70+
Assert.IsTrue(result, "TryGetValue should return true for existing key.");
71+
Assert.AreEqual("One", value, "Value should match the added value.");
72+
}
73+
74+
[TestMethod]
75+
public void Add_MultipleItems_ExceedChunkSize_DistributesAcrossChunks()
76+
{
77+
var chunkSize = 5;
78+
var dictionary = new ChunkedDictionary<int, string>(chunkSize);
79+
for (int i = 0; i < chunkSize * 2; i++)
80+
{
81+
dictionary.Add(i, $"Item{i}");
82+
}
83+
84+
Assert.AreEqual(chunkSize * 2, dictionary.Count, "Total items should match items added.");
85+
Assert.IsTrue(dictionary.Keys.Max() >= chunkSize, "Keys should be distributed across chunks.");
86+
}
87+
88+
[TestMethod]
89+
public void Add_MultipleItems_WithTotalSize_DistributesAcrossChunks()
90+
{
91+
var chunkSize = 5;
92+
var total = (chunkSize * 2) + 2; // +2 to ensure we need more than 2 chunks
93+
94+
var dictionary = new ChunkedDictionary<int, string>(total, chunkSize);
95+
for (int i = 0; i < total; i++)
96+
{
97+
dictionary.Add(i, $"Item{i}");
98+
}
99+
100+
Assert.AreEqual(total, dictionary.Count, "Total items should match items added.");
101+
Assert.IsTrue(dictionary.GetChunkCount() == 3, "We have 3 chunks.");
102+
}
103+
104+
[TestMethod]
105+
public void Add_MultipleItems_WithTotalSize_GrowsWhenAddingMoreItems()
106+
{
107+
var chunkSize = 5;
108+
var total = (chunkSize * 2) + 2;
109+
110+
var dictionary = new ChunkedDictionary<int, string>(total, chunkSize);
111+
for (int i = 0; i < total; i++)
112+
{
113+
dictionary.Add(i, $"Item{i}");
114+
}
115+
116+
dictionary.Add(total, $"Item{total}"); // Add one more item creating a new chunk
117+
118+
Assert.AreEqual(total + 1, dictionary.Count, "Total items should match items added.");
119+
Assert.IsTrue(dictionary.GetChunkCount() == 4, "We have 4 chunks.");
120+
121+
// Add more items to ensure we can grow further
122+
for (int i = 1; i < 6; i++)
123+
{
124+
dictionary.Add(total+i, $"Item{total+i}");
125+
}
126+
127+
Assert.AreEqual(total + 6, dictionary.Count, "Total items should match items added.");
128+
Assert.IsTrue(dictionary.GetChunkCount() == 5, "We have 5 chunks by now.");
129+
}
130+
131+
[TestMethod]
132+
public void KeysAndValues_AfterMutations_AccuratelyReflected()
133+
{
134+
var dictionary = new ChunkedDictionary<int, string>(10);
135+
dictionary.Add(1, "One");
136+
dictionary.Add(2, "Two");
137+
dictionary.Remove(1);
138+
139+
var keys = dictionary.Keys;
140+
var values = dictionary.Values;
141+
142+
Assert.IsTrue(keys.Contains(2) && keys.Count == 1, "Keys collection should accurately reflect current keys.");
143+
Assert.IsTrue(values.Contains("Two") && values.Count == 1, "Values collection should accurately reflect current values.");
144+
}
145+
146+
[TestMethod]
147+
public void Enumeration_YieldsAllItemsExactlyOnce()
148+
{
149+
var testData = new Dictionary<int, string>
150+
{
151+
{ 1, "One" }, { 2, "Two" }, { 3, "Three" },
152+
{ 4, "Four" }, { 5, "Five" }, { 6, "Six" }
153+
};
154+
var dictionary = new ChunkedDictionary<int, string>(testData.Count, 3);
155+
156+
foreach (var kvp in testData)
157+
{
158+
dictionary.Add(kvp.Key, kvp.Value);
159+
}
160+
161+
var enumeratedItems = new Dictionary<int, string>();
162+
foreach (var kvp in dictionary)
163+
{
164+
// Verify no duplicates during enumeration
165+
Assert.IsFalse(enumeratedItems.ContainsKey(kvp.Key), "Duplicate key found during enumeration.");
166+
enumeratedItems.Add(kvp.Key, kvp.Value);
167+
}
168+
169+
// Verify all items were enumerated
170+
Assert.AreEqual(testData.Count, enumeratedItems.Count, "Not all items were enumerated.");
171+
foreach (var kvp in testData)
172+
{
173+
Assert.IsTrue(enumeratedItems.ContainsKey(kvp.Key) && enumeratedItems[kvp.Key] == kvp.Value,
174+
"Missing or incorrect item in enumeration.");
175+
}
176+
}
177+
178+
[TestMethod]
179+
public void Add_ItemsExceedSingleChunkCapacity_ItemsDistributedAcrossMultipleChunks()
180+
{
181+
var chunkSize = 3;
182+
var itemCount = chunkSize * 2; // Ensure we need at least two chunks
183+
var dictionary = new ChunkedDictionary<int, string>(itemCount, chunkSize);
184+
185+
for (int i = 0; i < itemCount; i++)
186+
{
187+
dictionary.Add(i, $"Item{i}");
188+
}
189+
190+
var chunkCount = dictionary.GetChunkCount();
191+
Assert.IsTrue(chunkCount > 1, "Items should be distributed across more than one chunk.");
192+
}
193+
194+
[TestMethod]
195+
[ExpectedException(typeof(KeyNotFoundException))]
196+
public void Indexer_GetMissingKey_ThrowsKeyNotFoundException()
197+
{
198+
var dictionary = new ChunkedDictionary<int, string>(10);
199+
var value = dictionary[999]; // This should throw
200+
}
201+
202+
[TestMethod]
203+
[ExpectedException(typeof(ArgumentException))]
204+
public void Add_DuplicateKey_ThrowsArgumentException()
205+
{
206+
var dictionary = new ChunkedDictionary<int, string>(10);
207+
dictionary.Add(1, "One");
208+
dictionary.Add(1, "One again"); // This should throw
209+
}
210+
211+
[TestMethod]
212+
[ExpectedException(typeof(ArgumentException))]
213+
public void Init_InvalidChunkSize_ThrowsArgumentException()
214+
{
215+
var dictionary = new ChunkedDictionary<int, string>(10, 11);
216+
}
217+
218+
}
219+
}

0 commit comments

Comments
 (0)