Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Unit Tests for GC and strings #209

Merged
merged 1 commit into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Tests/NFUnitTestGC/NFUnitTestGC.nfproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<Import Project="$(NanoFrameworkProjectSystemPath)NFProjectSystem.props" Condition="Exists('$(NanoFrameworkProjectSystemPath)NFProjectSystem.props')" />
<ItemGroup>
<Compile Include="TestGCWithByteArrays.cs" />
<Compile Include="TestGCWithStringArrays.cs" />
<Compile Include="TestGCWithTimeSpanArrays.cs" />
<Compile Include="TestGCWithDateTimeArrays.cs" />
<Compile Include="TestGCWithObjectArrays.cs" />
Expand Down
103 changes: 103 additions & 0 deletions Tests/NFUnitTestGC/TestGCWithStringArrays.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
//
// Copyright (c) .NET Foundation and Contributors
// Portions Copyright (c) Microsoft Corporation. All rights reserved.
// See LICENSE file in the project root for full license information.
//

using nanoFramework.TestFramework;
using System;

namespace NFUnitTestGC
{
[TestClass]
public class TestGCWithStringArrays
{
[TestMethod]
public void TestCompactionForNotFixedStringArray()
{
OutputHelper.WriteLine("Starting TestCompactionForNotFixedStringArray");

for (int loop = 0; loop < 10; loop++)
{
OutputHelper.WriteLine($"Starting iteration {loop}");

// First we create objects and holes that keeps some space that could be used by compaction.

// Small count so compaction does not happen.
HolderForString[] arrayOfStrings = new HolderForString[10];
RunStringAllocations(arrayOfStrings);

// This is the array that we expect to move in during compaction.
HolderForString[] testNativeBuffer = new HolderForString[100];
// Fill it, so it is not optimized out
for (int i = 0; i < testNativeBuffer.Length; i++)
{
testNativeBuffer[i] = new HolderForString(Guid.NewGuid().ToString());
}

OutputHelper.WriteLine("Large HolderForString array created");
OutputHelper.WriteLine("Forcing compaction to occurr");

// Causes compaction
InitiateStringCompaction();

OutputHelper.WriteLine("Compaction occurred");
OutputHelper.WriteLine("Checking arrays for corrupted data...");

int index = 0;

// Check that array content is not corrupted
foreach (HolderForString holder in testNativeBuffer)
{
Assert.AreEqual(
holder.StringHash,
holder.StringContent.GetHashCode(),
$"Array content comparison failed at position {index}. Expecting {holder.StringHash}, found {holder.StringContent.GetHashCode()}");

index++;
}

OutputHelper.WriteLine("No corruption detected in array");
}

OutputHelper.WriteLine("Completed TestCompactionForNotFixedArray");
}

// This function cause compaction to occur.
// It is not so trivial as it need to fragment heap with referenced objects.
void InitiateStringCompaction()
{
// Large count, so compaction happens during RunAllocations.
HolderForString[] arrayOfArrays = new HolderForString[400];
RunStringAllocations(arrayOfArrays);
}

private void RunStringAllocations(HolderForString[] arrObj)
{
for (int i = 1; i < arrObj.Length; i++)
{
// Creates referenced object, which stays in memory until InitiateCompaction exits
arrObj[i] = new HolderForString(Guid.NewGuid().ToString());

// Tries to create larger object that would be later hole
// This object could be garbage collected on each "i" cycle
HolderForString[] arr = new HolderForString[50 * i];

// Creates some usage for array elements, so it is not optimized out
arr[0] = new HolderForString(Guid.NewGuid().ToString());
}
}

private class HolderForString
{
public int StringHash { get; }
public string StringContent { get; }

public HolderForString(string value)
{
StringContent = value;
StringHash = value.GetHashCode();
}
}
}
}