diff --git a/utbot-rd/src/main/rdgen/org/utbot/rd/models/CSharpModel.kt b/utbot-rd/src/main/rdgen/org/utbot/rd/models/CSharpModel.kt index f784e4365c..309293be6e 100644 --- a/utbot-rd/src/main/rdgen/org/utbot/rd/models/CSharpModel.kt +++ b/utbot-rd/src/main/rdgen/org/utbot/rd/models/CSharpModel.kt @@ -6,18 +6,25 @@ import com.jetbrains.rd.generator.nova.* object CSharpRoot: Root() object VSharpModel: Ext(CSharpRoot) { + val methodDescriptor = structdef { + field("methodName", PredefinedType.string) + field("typeName", PredefinedType.string) + } + val generateArguments = structdef { field("assemblyPath", PredefinedType.string) field("projectCsprojPath", PredefinedType.string) field("solutionFilePath", PredefinedType.string) - field("moduleFqnName", PredefinedType.string) - field("methodToken", PredefinedType.int) + field("method", methodDescriptor) field("generationTimeoutInSeconds", PredefinedType.int) + field("targetFramework", PredefinedType.string.nullable) } val generateResults = structdef { + field("isGenerated", PredefinedType.bool) field("generatedProjectPath", PredefinedType.string) field("generatedFilesPaths", array(PredefinedType.string)) + field("exceptionMessage", PredefinedType.string.nullable) } init { diff --git a/utbot-rider/src/dotnet/UtBot/UtBot.Rd/Generated/CSharpRoot.Generated.cs b/utbot-rider/src/dotnet/UtBot/UtBot.Rd/Generated/CSharpRoot.Generated.cs index 345f8ab29f..3048e3b7af 100644 --- a/utbot-rider/src/dotnet/UtBot/UtBot.Rd/Generated/CSharpRoot.Generated.cs +++ b/utbot-rider/src/dotnet/UtBot/UtBot.Rd/Generated/CSharpRoot.Generated.cs @@ -36,7 +36,7 @@ namespace UtBot.Rd.Generated /// - ///

Generated from: CSharpModel.kt:5

+ ///

Generated from: CSharpModel.kt:6

///
public class CSharpRoot : RdExtBase { diff --git a/utbot-rider/src/dotnet/UtBot/UtBot.Rd/Generated/VSharpModel.Generated.cs b/utbot-rider/src/dotnet/UtBot/UtBot.Rd/Generated/VSharpModel.Generated.cs index 4e749c92ee..be44a137a9 100644 --- a/utbot-rider/src/dotnet/UtBot/UtBot.Rd/Generated/VSharpModel.Generated.cs +++ b/utbot-rider/src/dotnet/UtBot/UtBot.Rd/Generated/VSharpModel.Generated.cs @@ -36,7 +36,7 @@ namespace UtBot.Rd.Generated /// - ///

Generated from: CSharpModel.kt:7

+ ///

Generated from: CSharpModel.kt:8

///
public class VSharpModel : RdExtBase { @@ -76,7 +76,7 @@ private VSharpModel ( - protected override long SerializationHash => -3661028246701070338L; + protected override long SerializationHash => -2362293640438957269L; protected override Action Register => RegisterDeclaredTypesSerializers; public static void RegisterDeclaredTypesSerializers(ISerializers serializers) @@ -118,7 +118,7 @@ public override string ToString() /// - ///

Generated from: CSharpModel.kt:8

+ ///

Generated from: CSharpModel.kt:14

///
public sealed class GenerateArguments : IPrintable, IEquatable { @@ -127,9 +127,9 @@ public sealed class GenerateArguments : IPrintable, IEquatable ReadStringNullable = JetBrains.Rd.Impl.Serializers.ReadString.NullableClass(); public static CtxWriteDelegate Write = (ctx, writer, value) => { writer.Write(value.AssemblyPath); writer.Write(value.ProjectCsprojPath); writer.Write(value.SolutionFilePath); - writer.Write(value.ModuleFqnName); - writer.Write(value.MethodToken); + MethodDescriptor.Write(ctx, writer, value.Method); writer.Write(value.GenerationTimeoutInSeconds); + WriteStringNullable(ctx, writer, value.TargetFramework); }; + public static CtxWriteDelegate WriteStringNullable = JetBrains.Rd.Impl.Serializers.WriteString.NullableClass(); //constants @@ -205,7 +207,7 @@ public bool Equals(GenerateArguments other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; - return AssemblyPath == other.AssemblyPath && ProjectCsprojPath == other.ProjectCsprojPath && SolutionFilePath == other.SolutionFilePath && ModuleFqnName == other.ModuleFqnName && MethodToken == other.MethodToken && GenerationTimeoutInSeconds == other.GenerationTimeoutInSeconds; + return AssemblyPath == other.AssemblyPath && ProjectCsprojPath == other.ProjectCsprojPath && SolutionFilePath == other.SolutionFilePath && Equals(Method, other.Method) && GenerationTimeoutInSeconds == other.GenerationTimeoutInSeconds && Equals(TargetFramework, other.TargetFramework); } //hash code trait public override int GetHashCode() @@ -215,9 +217,9 @@ public override int GetHashCode() hash = hash * 31 + AssemblyPath.GetHashCode(); hash = hash * 31 + ProjectCsprojPath.GetHashCode(); hash = hash * 31 + SolutionFilePath.GetHashCode(); - hash = hash * 31 + ModuleFqnName.GetHashCode(); - hash = hash * 31 + MethodToken.GetHashCode(); + hash = hash * 31 + Method.GetHashCode(); hash = hash * 31 + GenerationTimeoutInSeconds.GetHashCode(); + hash = hash * 31 + (TargetFramework != null ? TargetFramework.GetHashCode() : 0); return hash; } } @@ -229,9 +231,9 @@ public void Print(PrettyPrinter printer) printer.Print("assemblyPath = "); AssemblyPath.PrintEx(printer); printer.Println(); printer.Print("projectCsprojPath = "); ProjectCsprojPath.PrintEx(printer); printer.Println(); printer.Print("solutionFilePath = "); SolutionFilePath.PrintEx(printer); printer.Println(); - printer.Print("moduleFqnName = "); ModuleFqnName.PrintEx(printer); printer.Println(); - printer.Print("methodToken = "); MethodToken.PrintEx(printer); printer.Println(); + printer.Print("method = "); Method.PrintEx(printer); printer.Println(); printer.Print("generationTimeoutInSeconds = "); GenerationTimeoutInSeconds.PrintEx(printer); printer.Println(); + printer.Print("targetFramework = "); TargetFramework.PrintEx(printer); printer.Println(); } printer.Print(")"); } @@ -246,52 +248,66 @@ public override string ToString() /// - ///

Generated from: CSharpModel.kt:17

+ ///

Generated from: CSharpModel.kt:23

///
public sealed class GenerateResults : IPrintable, IEquatable { //fields //public fields + public bool IsGenerated {get; private set;} [NotNull] public string GeneratedProjectPath {get; private set;} [NotNull] public string[] GeneratedFilesPaths {get; private set;} + [CanBeNull] public string ExceptionMessage {get; private set;} //private fields //primary constructor public GenerateResults( + bool isGenerated, [NotNull] string generatedProjectPath, - [NotNull] string[] generatedFilesPaths + [NotNull] string[] generatedFilesPaths, + [CanBeNull] string exceptionMessage ) { if (generatedProjectPath == null) throw new ArgumentNullException("generatedProjectPath"); if (generatedFilesPaths == null) throw new ArgumentNullException("generatedFilesPaths"); + IsGenerated = isGenerated; GeneratedProjectPath = generatedProjectPath; GeneratedFilesPaths = generatedFilesPaths; + ExceptionMessage = exceptionMessage; } //secondary constructor //deconstruct trait - public void Deconstruct([NotNull] out string generatedProjectPath, [NotNull] out string[] generatedFilesPaths) + public void Deconstruct(out bool isGenerated, [NotNull] out string generatedProjectPath, [NotNull] out string[] generatedFilesPaths, [CanBeNull] out string exceptionMessage) { + isGenerated = IsGenerated; generatedProjectPath = GeneratedProjectPath; generatedFilesPaths = GeneratedFilesPaths; + exceptionMessage = ExceptionMessage; } //statics public static CtxReadDelegate Read = (ctx, reader) => { + var isGenerated = reader.ReadBool(); var generatedProjectPath = reader.ReadString(); var generatedFilesPaths = ReadStringArray(ctx, reader); - var _result = new GenerateResults(generatedProjectPath, generatedFilesPaths); + var exceptionMessage = ReadStringNullable(ctx, reader); + var _result = new GenerateResults(isGenerated, generatedProjectPath, generatedFilesPaths, exceptionMessage); return _result; }; public static CtxReadDelegate ReadStringArray = JetBrains.Rd.Impl.Serializers.ReadString.Array(); + public static CtxReadDelegate ReadStringNullable = JetBrains.Rd.Impl.Serializers.ReadString.NullableClass(); public static CtxWriteDelegate Write = (ctx, writer, value) => { + writer.Write(value.IsGenerated); writer.Write(value.GeneratedProjectPath); WriteStringArray(ctx, writer, value.GeneratedFilesPaths); + WriteStringNullable(ctx, writer, value.ExceptionMessage); }; public static CtxWriteDelegate WriteStringArray = JetBrains.Rd.Impl.Serializers.WriteString.Array(); + public static CtxWriteDelegate WriteStringNullable = JetBrains.Rd.Impl.Serializers.WriteString.NullableClass(); //constants @@ -309,15 +325,17 @@ public bool Equals(GenerateResults other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; - return GeneratedProjectPath == other.GeneratedProjectPath && GeneratedFilesPaths.SequenceEqual(other.GeneratedFilesPaths); + return IsGenerated == other.IsGenerated && GeneratedProjectPath == other.GeneratedProjectPath && GeneratedFilesPaths.SequenceEqual(other.GeneratedFilesPaths) && Equals(ExceptionMessage, other.ExceptionMessage); } //hash code trait public override int GetHashCode() { unchecked { var hash = 0; + hash = hash * 31 + IsGenerated.GetHashCode(); hash = hash * 31 + GeneratedProjectPath.GetHashCode(); hash = hash * 31 + GeneratedFilesPaths.ContentHashCode(); + hash = hash * 31 + (ExceptionMessage != null ? ExceptionMessage.GetHashCode() : 0); return hash; } } @@ -326,8 +344,104 @@ public void Print(PrettyPrinter printer) { printer.Println("GenerateResults ("); using (printer.IndentCookie()) { + printer.Print("isGenerated = "); IsGenerated.PrintEx(printer); printer.Println(); printer.Print("generatedProjectPath = "); GeneratedProjectPath.PrintEx(printer); printer.Println(); printer.Print("generatedFilesPaths = "); GeneratedFilesPaths.PrintEx(printer); printer.Println(); + printer.Print("exceptionMessage = "); ExceptionMessage.PrintEx(printer); printer.Println(); + } + printer.Print(")"); + } + //toString + public override string ToString() + { + var printer = new SingleLinePrettyPrinter(); + Print(printer); + return printer.ToString(); + } + } + + + /// + ///

Generated from: CSharpModel.kt:9

+ ///
+ public sealed class MethodDescriptor : IPrintable, IEquatable + { + //fields + //public fields + [NotNull] public string MethodName {get; private set;} + [NotNull] public string TypeName {get; private set;} + + //private fields + //primary constructor + public MethodDescriptor( + [NotNull] string methodName, + [NotNull] string typeName + ) + { + if (methodName == null) throw new ArgumentNullException("methodName"); + if (typeName == null) throw new ArgumentNullException("typeName"); + + MethodName = methodName; + TypeName = typeName; + } + //secondary constructor + //deconstruct trait + public void Deconstruct([NotNull] out string methodName, [NotNull] out string typeName) + { + methodName = MethodName; + typeName = TypeName; + } + //statics + + public static CtxReadDelegate Read = (ctx, reader) => + { + var methodName = reader.ReadString(); + var typeName = reader.ReadString(); + var _result = new MethodDescriptor(methodName, typeName); + return _result; + }; + + public static CtxWriteDelegate Write = (ctx, writer, value) => + { + writer.Write(value.MethodName); + writer.Write(value.TypeName); + }; + + //constants + + //custom body + //methods + //equals trait + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((MethodDescriptor) obj); + } + public bool Equals(MethodDescriptor other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return MethodName == other.MethodName && TypeName == other.TypeName; + } + //hash code trait + public override int GetHashCode() + { + unchecked { + var hash = 0; + hash = hash * 31 + MethodName.GetHashCode(); + hash = hash * 31 + TypeName.GetHashCode(); + return hash; + } + } + //pretty print + public void Print(PrettyPrinter printer) + { + printer.Println("MethodDescriptor ("); + using (printer.IndentCookie()) { + printer.Print("methodName = "); MethodName.PrintEx(printer); printer.Println(); + printer.Print("typeName = "); TypeName.PrintEx(printer); printer.Println(); } printer.Print(")"); } diff --git a/utbot-rider/src/dotnet/UtBot/UtBot.Rd/RdUtil.cs b/utbot-rider/src/dotnet/UtBot/UtBot.Rd/RdUtil.cs index 560e60808f..d069e66524 100644 --- a/utbot-rider/src/dotnet/UtBot/UtBot.Rd/RdUtil.cs +++ b/utbot-rider/src/dotnet/UtBot/UtBot.Rd/RdUtil.cs @@ -3,4 +3,5 @@ namespace UtBot.Rd; public static class RdUtil { public static readonly string MainProcessName = "UtBot"; + public static readonly string DefaultTestProjectTarget = "net6.0"; } \ No newline at end of file diff --git a/utbot-rider/src/dotnet/UtBot/UtBot.VSharp/UtBot.VSharp.csproj b/utbot-rider/src/dotnet/UtBot/UtBot.VSharp/UtBot.VSharp.csproj index 6db4a5386b..01a27c9a35 100644 --- a/utbot-rider/src/dotnet/UtBot/UtBot.VSharp/UtBot.VSharp.csproj +++ b/utbot-rider/src/dotnet/UtBot/UtBot.VSharp/UtBot.VSharp.csproj @@ -12,6 +12,6 @@ - + diff --git a/utbot-rider/src/dotnet/UtBot/UtBot.VSharp/VSharpMain.cs b/utbot-rider/src/dotnet/UtBot/UtBot.VSharp/VSharpMain.cs index 54c91bdca3..fefd4f483b 100644 --- a/utbot-rider/src/dotnet/UtBot/UtBot.VSharp/VSharpMain.cs +++ b/utbot-rider/src/dotnet/UtBot/UtBot.VSharp/VSharpMain.cs @@ -2,23 +2,55 @@ using System.Collections.Concurrent; using System.Diagnostics; using System.IO; -using System.Linq; +using System.Reflection; using System.Runtime.Loader; using JetBrains.Collections.Viewable; using JetBrains.Lifetimes; using JetBrains.Rd; using JetBrains.Rd.Impl; using JetBrains.Rd.Tasks; +using JetBrains.Util; using UtBot.Rd; using UtBot.Rd.Generated; using VSharp; +using VSharp.System; using VSharp.TestRenderer; +using Thread = System.Threading.Thread; namespace UtBot.VSharp; public static class VSharpMain { public static readonly string VSharpProcessName = "VSharp"; + + private static GenerateResults GenerateImpl(GenerateArguments arguments) + { + var (assemblyPath, projectCsprojPath, solutionFilePath, + descriptor, generationTimeout, targetFramework) = arguments; + var assemblyLoadContext = new AssemblyLoadContext(VSharpProcessName); + using var fs = File.OpenRead(assemblyPath); + var ass = assemblyLoadContext.LoadFromStream(fs); + var type = ass.GetType(descriptor.TypeName, throwOnError: false); + if (type?.Name != descriptor.TypeName) + throw new InvalidDataException($"cannot find type - {descriptor.TypeName}"); + var methodInfo = type.GetMethod(descriptor.MethodName, + BindingFlags.Instance + | BindingFlags.Static + | BindingFlags.Public); + if (methodInfo?.Name != descriptor.MethodName) + throw new InvalidDataException( + $"cannot find method - ${descriptor.MethodName} for type - ${descriptor.TypeName}"); + var stat = TestGenerator.Cover(methodInfo, generationTimeout); + var targetProject = new FileInfo(projectCsprojPath); + var solution = new FileInfo(solutionFilePath); + var declaringType = methodInfo.DeclaringType; + Debug.Assert(declaringType != null); + var (generatedProject, renderedFiles) = + Renderer.Render(stat.Results(), targetProject, declaringType, assemblyLoadContext, solution, targetFramework); + return new GenerateResults(true, generatedProject.FullName, renderedFiles.ToArray(), null); + ; + } + public static void Main(string[] args) { using var blockingQueue = new BlockingCollection(1); @@ -35,25 +67,18 @@ public static void Main(string[] args) var vSharpModel = new VSharpModel(ldef.Lifetime, protocol); vSharpModel.Generate.Set((_, arguments) => { - var (assemblyPath, projectCsprojPath, solutionFilePath, - moduleFqnName, methodToken, generationTimeout) = arguments; - var assemblyLoadContext = new AssemblyLoadContext(VSharpProcessName); - var fs = File.OpenRead(assemblyPath); - var ass = assemblyLoadContext.LoadFromStream(fs); - fs.Close(); - fs.Dispose(); - var methodBase = ass.GetModules().Single(module => module.FullyQualifiedName == moduleFqnName).ResolveMethod(methodToken); - Debug.Assert(methodBase != null); - var stat = TestGenerator.Cover(methodBase, generationTimeout); - var targetProject = new FileInfo(projectCsprojPath); - var solution = new FileInfo(solutionFilePath); - var declaringType = methodBase.DeclaringType; - Debug.Assert(declaringType != null); - var (generatedProject, renderedFiles) = - Renderer.Render(stat.Results(), targetProject, declaringType, assemblyLoadContext, solution); - var result = new GenerateResults(generatedProject.FullName, renderedFiles.ToArray()); - blockingQueue.Add("End"); - return result; + try + { + return GenerateImpl(arguments); + } + catch (Exception e) + { + return new GenerateResults(false, "", EmptyArray.Instance, e.ToString()); + } + finally + { + scheduler.Queue(() => { blockingQueue.Add("End"); }); + } }); vSharpModel.Ping.Advise(ldef.Lifetime, s => { @@ -65,6 +90,8 @@ public static void Main(string[] args) }); }); blockingQueue.Take(); + // todo check if queueing take as next action is enough + // Thread.Sleep(1000); ldef.Terminate(); } -} +} \ No newline at end of file diff --git a/utbot-rider/src/dotnet/UtBot/UtBot/GenerateUnitTestElementProvider.cs b/utbot-rider/src/dotnet/UtBot/UtBot/GenerateUnitTestElementProvider.cs index 2218aa8073..1d00072e7e 100644 --- a/utbot-rider/src/dotnet/UtBot/UtBot/GenerateUnitTestElementProvider.cs +++ b/utbot-rider/src/dotnet/UtBot/UtBot/GenerateUnitTestElementProvider.cs @@ -13,6 +13,9 @@ public class GenerateUnitTestElementProvider : GeneratorProviderBase(method, substitution); context.ProvidedElements.Add(element); context.InputElements.Add(element); } + } } protected virtual bool MethodFilter([NotNull] IMethod method, ISubstitution substitution, diff --git a/utbot-rider/src/dotnet/UtBot/UtBot/UnitTestBuilder.cs b/utbot-rider/src/dotnet/UtBot/UtBot/UnitTestBuilder.cs index eaf80f0a74..a3f2d381c4 100644 --- a/utbot-rider/src/dotnet/UtBot/UtBot/UnitTestBuilder.cs +++ b/utbot-rider/src/dotnet/UtBot/UtBot/UnitTestBuilder.cs @@ -1,11 +1,7 @@ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.IO; using System.Linq; using System.Reflection; -using System.Runtime.Loader; -using System.Threading; using JetBrains.Application.Progress; using JetBrains.Application.Threading; using JetBrains.Application.Threading.Tasks; @@ -21,16 +17,11 @@ using JetBrains.ReSharper.Feature.Services.Generate; using JetBrains.ReSharper.Psi; using JetBrains.ReSharper.Psi.CSharp; -using JetBrains.ReSharper.UnitTestFramework; -using JetBrains.ReSharper.UnitTestFramework.Criteria; -using JetBrains.ReSharper.UnitTestFramework.Execution.Hosting; -using JetBrains.ReSharper.UnitTestFramework.Exploration.Artifacts; using JetBrains.Rider.Model; using JetBrains.Util; using JetBrains.Util.Dotnet.TargetFrameworkIds; using UtBot.Rd.Generated; using UtBot.VSharp; -using Thread = System.Threading.Thread; namespace UtBot; @@ -42,25 +33,19 @@ internal sealed class UnitTestBuilder : GeneratorBuilderBase(); + var descriptors = new List(); foreach (var inputElement in context.InputElements.WithProgress(progress, "Generating Unit tests") .OfType>()) - descriptors.Add(new UnitTestMethodDescriptor - { MethodName = inputElement.DeclaredElement.ShortName, TypeName = typeElement.ShortName }); + descriptors.Add(new MethodDescriptor(inputElement.DeclaredElement.ShortName, typeElement.ShortName)); var progressLifetimeDef = _lifetime.CreateNested(); var indicator = @@ -96,10 +80,18 @@ protected override void Process(CSharpGeneratorContext context, IProgressIndicat } private void Generate(IBackgroundProgressIndicator progressIndicator, IProject project, - VirtualFileSystemPath assemblyPath, List descriptors, TargetFrameworkId tfm) + VirtualFileSystemPath assemblyPath, List descriptors, TargetFrameworkId tfm) { + var solution = project.GetSolution(); + var solutionMark = solution.GetSolutionMark(); + if (solutionMark == null) return; + + var solutionFilePath = solutionMark.Location.FullPath; + _logger.Verbose($"Solution path: {solutionFilePath}"); + + project.Locks.AssertNonMainThread(); + SolutionBuilderRequest buildRequest; - var contextUnloaded = false; using (_shellLocks.UsingReadLock()) { if (!project.IsValid()) return; @@ -114,126 +106,90 @@ private void Generate(IBackgroundProgressIndicator progressIndicator, IProject p buildRequest.State.WaitForValue(_lifetime, state => state.HasFlag(BuildRunState.Completed)); - var assemblyLoadContext = new AssemblyLoadContext("UnitTestGeneration"); - //var renderer = new NunitTestRenderer(assemblyLoadContext); - try + var pluginPath = FileSystemPath.Parse(Assembly.GetExecutingAssembly().Location).Parent; + var vsharpRunner = pluginPath.Combine("UtBot.VSharp.dll"); + + foreach (var descriptor in descriptors) { - var fs = File.OpenRead(assemblyPath.FullPath); - var ass = assemblyLoadContext.LoadFromStream(fs); - fs.Close(); - fs.Dispose(); - var solution = project.GetSolution(); - var solutionMark = solution.GetSolutionMark(); - if (solutionMark == null) return; - string unitTestProjectLocation = null; - foreach (var descriptor in descriptors) - foreach (var type in ass.GetTypes()) + var currentGeneratedItem = $"{descriptor.TypeName}.{descriptor.MethodName}"; + _logger.Verbose($"Start Generation for {currentGeneratedItem}"); + progressIndicator.Lifetime.ThrowIfNotAlive(); + progressIndicator.Header.SetValue(currentGeneratedItem); + + _logger.Catch(() => { - if (type.Name != descriptor.TypeName) continue; - foreach (var methodInfo in type.GetMethods()) + var port = NetworkUtil.GetFreePort(); + var proc = new ProcessWithRdServer(VSharpMain.VSharpProcessName, port, vsharpRunner.FullPath, + project.Locks, + _lifetime); + var projectCsprojPath = project.ProjectFileLocation.FullPath; + var vsharpProjectTarget = calculateTestProjectTarget(tfm); + var args = new GenerateArguments(assemblyPath.FullPath, projectCsprojPath, solutionFilePath, descriptor, + GenerationTimeout, vsharpProjectTarget); + var result = proc.VSharpModel.Generate.Sync(args, RpcTimeouts.Maximal); + _logger.Info("Result acquired"); + if (result.IsGenerated) { - if (methodInfo.Name != descriptor.MethodName) continue; - progressIndicator.Header.SetValue($"{descriptor.TypeName}.{descriptor.MethodName}"); - var solutionFilePath = solutionMark.Location.FullPath; - _logger.Verbose($"Solution path: {solutionFilePath}"); - _logger.Verbose("Start Generation"); - _logger.Catch(() => + _shellLocks.ExecuteOrQueue(_lifetime, "UnitTestBuilder::Generate", () => { - project.Locks.AssertNonMainThread(); - var pluginPath = FileSystemPath.Parse(Assembly.GetExecutingAssembly().Location) - .Parent; - var vsharpRunner = pluginPath.Combine("UtBot.VSharp.dll"); - var port = NetworkUtil.GetFreePort(); - var proc = new ProcessWithRdServer(VSharpMain.VSharpProcessName, port, vsharpRunner.FullPath, project.Locks, _lifetime); - var projectCsprojPath = project.ProjectFileLocation.FullPath; - var moduleFqnName = methodInfo.Module.FullyQualifiedName; - var methodToken = methodInfo.MetadataToken; - var args = new GenerateArguments(assemblyPath.FullPath, projectCsprojPath, solutionFilePath, - moduleFqnName, methodToken, _generationTimeout); - var result = proc.VSharpModel.Generate.Sync(args, RpcTimeouts.Maximal); - unitTestProjectLocation = result?.GeneratedProjectPath ?? ""; - _shellLocks.ExecuteOrQueue(_lifetime, "UnitTestBuilder::Generate", () => + if (solution.IsValid()) { - if (solution.IsValid()) - { - solution.GetProtocolSolution().GetFileSystemModel().RefreshPaths - .Start(_lifetime, new RdFsRefreshRequest(new List { unitTestProjectLocation }, true)); - } - }); + solution.GetProtocolSolution().GetFileSystemModel().RefreshPaths + .Start(_lifetime, + new RdFsRefreshRequest(new List { result.GeneratedProjectPath }, true)); + } }); - _logger.Verbose("Generation finished"); } - } - - //assemblyLoadContext.Unload(); - contextUnloaded = true; - _shellLocks.ExecuteOrQueue(_lifetime, "UnitTestBuilder::Generate", () => - { - if (project.IsValid()) - solution.GetProtocolSolution().GetFileSystemModel().RefreshPaths - .Start(_lifetime, - new RdFsRefreshRequest(new List { solutionMark.Location.FullPath }, true)); - }); - if (unitTestProjectLocation == null) return; - IProject unitTestProject = null; - var manualResetEvent = new ManualResetEvent(false); - var unitTestProjectPath = VirtualFileSystemPath.Parse(unitTestProjectLocation, InteractionContext.Local); - - while (unitTestProject == null && _lifetime.IsAlive && project.IsValid()) - { - _shellLocks.ExecuteOrQueueReadLock(_lifetime, "UnitTestBuilder::WaitingForProject", - () => - { - _logger.Warn("Try to get project"); - unitTestProject = TryToFindProject(solution, unitTestProjectPath); - manualResetEvent.Set(); - }); - if (!manualResetEvent.WaitOne(TimeSpan.FromSeconds(10))) + else { - _logger.Warn("Exit by timeout"); - return; + _logger.Info( + $"Could not generate tests for ${currentGeneratedItem}, exception - ${result.ExceptionMessage}"); } + }); - manualResetEvent.Reset(); - Thread.Sleep(1000); - } - - if (unitTestProject != null && unitTestProject.IsValid()) - { - using (_shellLocks.UsingReadLock()) - { - if (!unitTestProject.IsValid()) return; - buildRequest = _solutionBuilder.CreateBuildRequest(BuildSessionTarget.Build, - new[] { unitTestProject }, - SolutionBuilderRequestSilentMode.Silent, - new SolutionBuilderRequestAdvancedSettings(null, - false, verbosityLevel: LoggerVerbosityLevel.Normal, isRestoreRequest: true)); - - _solutionBuilder.ExecuteBuildRequest(buildRequest); - } - - buildRequest.State.WaitForValue(_lifetime, state => state.HasFlag(BuildRunState.Completed)); - - _unitTestArtifactExplorationProcess.ExploreProject(project).ContinueWith(_ => - { - _unitTestingFacade - .Run(new ProjectCriterion(unitTestProject)) - .Using(UnitTestHost.Instance.GetProvider("Cover")) - .In.CurrentOrNewSession(); - }, _lifetime.ToCancellationToken()); - } + _logger.Verbose($"Generation finished for {currentGeneratedItem}"); } - finally + + _shellLocks.ExecuteOrQueue(_lifetime, "UnitTestBuilder::Generate", () => { - if (!contextUnloaded) - { - //assemblyLoadContext.Unload(); - } - } + if (project.IsValid()) + solution.GetProtocolSolution().GetFileSystemModel().RefreshPaths + .Start(_lifetime, + new RdFsRefreshRequest(new List { solutionMark.Location.FullPath }, true)); + }); } - private IProject TryToFindProject(ISolution solution, VirtualFileSystemPath unitTestProjectPath) + private static HashSet possibleTargets = new() { - return solution.FindProjectItemsByLocation(unitTestProjectPath).SingleItem() as IProject; + "net7.0", + "net6.0", + "netcoreapp1.0", + "netcoreapp1.1", + "netcoreapp2.0", + "netcoreapp2.1", + "netcoreapp2.2", + "netcoreapp3.0", + "netcoreapp3.1", + "net35", + "net40", + "net451", + "net452", + "net46", + "net461", + "net462", + "net47", + "net471", + "net472", + "net48" + }; + + private static string calculateTestProjectTarget(TargetFrameworkId tfm) + { + var id = tfm.TryGetShortIdentifier(); + + if (possibleTargets.Contains(id)) + return id; + + return "net6.0"; } -} +} \ No newline at end of file diff --git a/utbot-rider/src/dotnet/UtBot/UtBot/UnitTestMethodDescriptor.cs b/utbot-rider/src/dotnet/UtBot/UtBot/UnitTestMethodDescriptor.cs deleted file mode 100644 index cc53f4edfe..0000000000 --- a/utbot-rider/src/dotnet/UtBot/UtBot/UnitTestMethodDescriptor.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace UtBot; - -public class UnitTestMethodDescriptor -{ - public string MethodName; - public string TypeName; -} \ No newline at end of file diff --git a/utbot-rider/src/dotnet/UtBot/UtBot/TargetFrameworkChecker.cs b/utbot-rider/src/dotnet/UtBot/UtBot/VSharpFrameworkChecker.cs similarity index 71% rename from utbot-rider/src/dotnet/UtBot/UtBot/TargetFrameworkChecker.cs rename to utbot-rider/src/dotnet/UtBot/UtBot/VSharpFrameworkChecker.cs index 499fa0fd16..4af7c45330 100644 --- a/utbot-rider/src/dotnet/UtBot/UtBot/TargetFrameworkChecker.cs +++ b/utbot-rider/src/dotnet/UtBot/UtBot/VSharpFrameworkChecker.cs @@ -1,15 +1,14 @@ -#nullable enable using System; using System.Diagnostics; using System.Text.RegularExpressions; namespace UtBot; -public class FrameworkChecker +public class VSharpFrameworkChecker { private readonly int _majorVersion; - public FrameworkChecker() + public VSharpFrameworkChecker() { var dotnetInfo = RunDotnet(new ProcessStartInfo { @@ -27,7 +26,7 @@ public FrameworkChecker() throw new Exception("Could not parse dotnet version"); } - private static string? RunDotnet(ProcessStartInfo startInfo) + private static string RunDotnet(ProcessStartInfo startInfo) { startInfo.FileName = "dotnet"; startInfo.RedirectStandardError = true; @@ -48,4 +47,18 @@ public bool FrameworkSupportsProject(Version tfm) { return _majorVersion >= tfm.Major; } -} + + public static bool CanRunVSharp(Version tfm) + { + try + { + var checker = new VSharpFrameworkChecker(); + + return checker.FrameworkSupportsVSharp() && checker.FrameworkSupportsProject(tfm) && tfm.Major < 7; + } + catch (Exception _) + { + return false; + } + } +} \ No newline at end of file