Docker, Ubuntu 20.04, .NET 6.0, Mono 6
VSharp console runner with special option --single-file
Steps to reproduce
Run command such as (for the source code below):
dotnet /usr/src/vsharp_runner/VSharp.Runner.dll --all-public-methods /usr/src/project/bin/Debug/net6.0/project.dll --render-tests --single-file
See generated tests contain wrong namespace indents.
See generated tests contain wrong namespace indents.
Source code
namespace Algorithms;
public static class Searches {
public static int BinarySearch(int value, int[] a)
{
var l = a.GetLowerBound(0);
var r = a.GetLength(0);
while (l < r)
{
var mid = (l + r) / 2;
int element = a[mid];
if (element == value)
return mid;
if (element < value)
r = mid - 1;
l = mid + 1;
}
return -1;
}
}
Generated test
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using NUnit.Framework;
using Algorithms;
namespace VSharp.TestExtensions
{
internal static class CartesianProductExtension
{
internal static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
{
IEnumerable<IEnumerable<T>> emptyProduct =
new[] { Enumerable.Empty<T>() };
return sequences.Aggregate(
emptyProduct,
(accumulator, sequence) =>
from accseq in accumulator
from item in sequence
select accseq.Concat(new[] {item}));
}
}
public static class Allocator
{
private static void FillFast<TElem>(Array? arr, TElem value)
{
if (arr != null)
{
ref var bytePtr = ref MemoryMarshal.GetArrayDataReference(arr);
ref var ptr = ref Unsafe.As<byte, TElem>(ref bytePtr);
var span = MemoryMarshal.CreateSpan(ref ptr, arr.Length);
span.Fill(value);
}
}
/// Fills zero-initialized array with value
public static void Fill(Array? arr, object? value)
{
if (value == null)
{
// Do nothing because arr is already filled with nulls
return;
}
var t = value.GetType();
if (arr != null && (!t.IsValueType || Nullable.GetUnderlyingType(t) != null ||
value != FormatterServices.GetUninitializedObject(t)))
{
var elementType = arr.GetType().GetElementType();
switch (value)
{
case int i when elementType == typeof(int):
FillFast(arr, i);
break;
case byte i when elementType == typeof(byte):
FillFast(arr, i);
break;
case char i when elementType == typeof(char):
FillFast(arr, i);
break;
case byte i when elementType == typeof(uint):
FillFast(arr, i);
break;
case byte i when elementType == typeof(Int64):
FillFast(arr, i);
break;
case byte i when elementType == typeof(UInt64):
FillFast(arr, i);
break;
case byte i when elementType == typeof(double):
FillFast(arr, i);
break;
case byte i when elementType == typeof(float):
FillFast(arr, i);
break;
case byte i when elementType == typeof(Int16):
FillFast(arr, i);
break;
case byte i when elementType == typeof(UInt16):
FillFast(arr, i);
break;
case byte i when elementType == typeof(sbyte):
FillFast(arr, i);
break;
default:
var rank = arr.Rank;
var indices =
Enumerable.Range(0, rank)
.Select(i => Enumerable.Range(arr.GetLowerBound(i), arr.GetLength(i)))
.CartesianProduct();
foreach (var i in indices)
{
arr.SetValue(value, i.ToArray());
}
break;
}
}
}
}
public class Allocator<T>
{
private readonly Type _objectType = typeof(T);
private readonly object _toAllocate;
public Allocator()
{
_toAllocate = FormatterServices.GetUninitializedObject(_objectType);
}
public Allocator(string typeName)
{
Type? notPublicType = Type.GetType(typeName);
_objectType = notPublicType ?? _objectType;
_toAllocate = FormatterServices.GetUninitializedObject(_objectType);
}
public Allocator(object? defaultValue, params int[] lengths)
{
Debug.Assert(_objectType.IsArray);
_toAllocate = Array.CreateInstance(_objectType.GetElementType()!, lengths);
Allocator.Fill(_toAllocate as Array, defaultValue);
}
public Allocator(object? defaultValue, int[] lengths, int[] lowerBounds)
{
Debug.Assert(_objectType.IsArray);
_toAllocate = Array.CreateInstance(_objectType.GetElementType()!, lengths, lowerBounds);
Allocator.Fill(_toAllocate as Array, defaultValue);
}
public Allocator(object allocated)
{
_toAllocate = allocated;
}
public Allocator(object allocated, object defaultValue)
{
Debug.Assert(_objectType.IsArray);
_toAllocate = allocated;
Allocator.Fill(_toAllocate as Array, defaultValue);
}
public object this[string fieldName]
{
set
{
var allBindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
var field = _objectType.GetField(fieldName, allBindingFlags);
var property = _objectType.GetField($"<{fieldName}>k__BackingField", allBindingFlags);
Debug.Assert(field != null || property != null);
field ??= property;
if (field != null)
field.SetValue(_toAllocate, value);
}
}
public object this[params int[] index]
{
set
{
Debug.Assert(_objectType.IsArray);
var array = _toAllocate as Array;
array?.SetValue(value, index);
}
}
public T Object => (T)_toAllocate;
}
public static class ObjectsComparer
{
private static bool StructurallyEqual(object? expected, object? got)
{
Debug.Assert(expected != null && got != null && expected.GetType() == got.GetType());
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
var fields = expected.GetType().GetFields(flags);
foreach (var field in fields)
{
if (!typeof(MulticastDelegate).IsAssignableFrom(field.FieldType) &&
!field.Name.Contains("threadid", StringComparison.OrdinalIgnoreCase) &&
!CompareObjects(field.GetValue(expected), field.GetValue(got)))
{
return false;
}
}
return true;
}
private static bool ContentwiseEqual(global::System.Array? expected, global::System.Array? got)
{
Debug.Assert(expected != null && got != null && expected.GetType() == got.GetType());
if (expected.Rank != got.Rank)
return false;
for (int i = 0; i < expected.Rank; ++i)
if (expected.GetLength(i) != got.GetLength(i) || expected.GetLowerBound(i) != got.GetLowerBound(i))
return false;
var enum1 = expected.GetEnumerator();
var enum2 = got.GetEnumerator();
while (enum1.MoveNext() && enum2.MoveNext())
{
if (!CompareObjects(enum1.Current, enum2.Current))
return false;
}
return true;
}
public static bool CompareObjects(object? expected, object? got)
{
if (expected == null)
return got == null;
if (got == null)
return false;
var type = expected.GetType();
if (type != got.GetType())
return false;
if (Object.ReferenceEquals(expected, got))
return true;
if (type == typeof(Pointer) || type.IsPrimitive || expected is string || type.IsEnum)
{
// TODO: compare double with epsilon?
return got.Equals(expected);
}
if (expected is global::System.Array array)
return ContentwiseEqual(array, got as global::System.Array);
return StructurallyEqual(expected, got);
}
}
}
namespace project.Tests
{
[TestFixture]
class SearchesTests
{
[Test, Category("Generated")]
public void BinarySearchError()
{
// act
Searches.BinarySearch(0, null!);
}
[Test, Category("Generated")]
public void BinarySearchTest()
{
// arrange
int[] a = new int[1];
// act
var result = Searches.BinarySearch(0, a);
// assert
Assert.AreEqual(0, result);
}
[Test, Category("Generated")]
public void BinarySearchTest1()
{
// arrange
int[] a = new int[0];
// act
var result = Searches.BinarySearch(0, a);
// assert
Assert.AreEqual(-1, result);
}
[Test, Category("Generated")]
public void BinarySearchTest2()
{
// arrange
int[] a = new int[1];
// act
var result = Searches.BinarySearch(1, a);
// assert
Assert.AreEqual(-1, result);
}
}}
Description
Test namespace indents are generated wrongly.
Environment
Docker, Ubuntu 20.04, .NET 6.0, Mono 6 VSharp console runner with special option
--single-file
Steps to reproduce
dotnet /usr/src/vsharp_runner/VSharp.Runner.dll --all-public-methods /usr/src/project/bin/Debug/net6.0/project.dll --render-tests --single-file
or
Source code
Generated test