using StellaOps.Scanner.Analyzers.Lang.DotNet.Internal.Capabilities; namespace StellaOps.Scanner.Analyzers.Lang.DotNet.Tests.Internal; /// /// Tests for . /// public sealed class DotNetCapabilityScannerTests { private const string TestFile = "Test.cs"; #region ScanFile - General Tests [Fact] public void ScanFile_NullContent_ReturnsEmpty() { var result = DotNetCapabilityScanner.ScanFile(null!, TestFile); Assert.Empty(result); } [Fact] public void ScanFile_EmptyContent_ReturnsEmpty() { var result = DotNetCapabilityScanner.ScanFile("", TestFile); Assert.Empty(result); } [Fact] public void ScanFile_WhitespaceContent_ReturnsEmpty() { var result = DotNetCapabilityScanner.ScanFile(" \n\t\n ", TestFile); Assert.Empty(result); } [Fact] public void ScanFile_NoPatterns_ReturnsEmpty() { const string code = @" namespace Test { public class Program { public static void Main() => Console.WriteLine(""Hello""); } }"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Empty(result); } [Fact] public void ScanFile_NormalizesBackslashesInPath() { const string code = @"Process.Start(""notepad.exe"");"; var result = DotNetCapabilityScanner.ScanFile(code, @"C:\src\Test.cs"); Assert.Single(result); Assert.Equal("C:/src/Test.cs", result[0].SourceFile); } [Fact] public void ScanFile_DeduplicatesSamePatternOnSameLine() { const string code = @"Process.Start(""cmd""); Process.Start(""notepad"");"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); // Same pattern on same line should be deduplicated Assert.Single(result); } #endregion #region ScanFile - Comment Stripping [Fact] public void ScanFile_IgnoresSingleLineComments() { const string code = @" // Process.Start(""cmd""); public void Method() { }"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Empty(result); } [Fact] public void ScanFile_IgnoresMultiLineComments() { const string code = @" /* Process.Start(""cmd""); File.Delete(""file.txt""); */ public void Method() { }"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Empty(result); } #endregion #region ScanFile - Exec Patterns [Fact] public void ScanFile_DetectsProcessStart() { const string code = @"Process.Start(""notepad.exe"");"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Exec, result[0].Kind); Assert.Equal("Process.Start", result[0].Pattern); Assert.Equal(CapabilityRisk.Critical, result[0].Risk); Assert.Equal(1.0f, result[0].Confidence); } [Fact] public void ScanFile_DetectsNewProcessStartInfo() { const string code = @"var psi = new ProcessStartInfo(""cmd.exe"");"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Exec, result[0].Kind); Assert.Equal("ProcessStartInfo", result[0].Pattern); Assert.Equal(CapabilityRisk.Critical, result[0].Risk); } [Fact] public void ScanFile_DetectsProcessStartInfoObjectInitializer() { const string code = @"var psi = new ProcessStartInfo { FileName = ""cmd.exe"" };"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Exec, result[0].Kind); } [Fact] public void ScanFile_DetectsUseShellExecuteTrue() { const string code = @"psi.UseShellExecute = true;"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Exec, result[0].Kind); Assert.Equal("UseShellExecute=true", result[0].Pattern); Assert.Equal(CapabilityRisk.Critical, result[0].Risk); } #endregion #region ScanFile - Filesystem Patterns [Fact] public void ScanFile_DetectsFileReadAllText() { const string code = @"var content = File.ReadAllText(""file.txt"");"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Filesystem, result[0].Kind); Assert.Equal("File.ReadAll/WriteAll", result[0].Pattern); Assert.Equal(CapabilityRisk.Medium, result[0].Risk); } [Fact] public void ScanFile_DetectsFileWriteAllText() { const string code = @"File.WriteAllText(""file.txt"", content);"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Filesystem, result[0].Kind); Assert.Equal("File.ReadAll/WriteAll", result[0].Pattern); } [Fact] public void ScanFile_DetectsFileDelete() { const string code = @"File.Delete(""file.txt"");"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Filesystem, result[0].Kind); Assert.Equal("File/Directory.Delete", result[0].Pattern); Assert.Equal(CapabilityRisk.High, result[0].Risk); } [Fact] public void ScanFile_DetectsDirectoryDelete() { const string code = @"Directory.Delete(""dir"", true);"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Filesystem, result[0].Kind); Assert.Equal("File/Directory.Delete", result[0].Pattern); Assert.Equal(CapabilityRisk.High, result[0].Risk); } [Fact] public void ScanFile_DetectsFileCopy() { const string code = @"File.Copy(""src.txt"", ""dest.txt"");"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Filesystem, result[0].Kind); Assert.Equal("File/Directory operations", result[0].Pattern); Assert.Equal(CapabilityRisk.Medium, result[0].Risk); } [Fact] public void ScanFile_DetectsNewFileStream() { const string code = @"using var fs = new FileStream(""file.bin"", FileMode.Open);"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Filesystem, result[0].Kind); Assert.Equal("FileStream", result[0].Pattern); } [Fact] public void ScanFile_DetectsSetAccessControl() { const string code = @"fileInfo.SetAccessControl(security);"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Filesystem, result[0].Kind); Assert.Equal("SetAccessControl", result[0].Pattern); Assert.Equal(CapabilityRisk.High, result[0].Risk); } #endregion #region ScanFile - Network Patterns [Fact] public void ScanFile_DetectsNewHttpClient() { const string code = @"using var client = new HttpClient();"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Network, result[0].Kind); Assert.Equal("HttpClient", result[0].Pattern); Assert.Equal(CapabilityRisk.Medium, result[0].Risk); } [Fact] public void ScanFile_DetectsGetAsync() { const string code = @"var response = await client.GetAsync(url);"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Network, result[0].Kind); Assert.Equal("HttpClient", result[0].Pattern); } [Fact] public void ScanFile_DetectsNewWebClient() { const string code = @"using var client = new WebClient();"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Network, result[0].Kind); Assert.Equal("WebClient", result[0].Pattern); } [Fact] public void ScanFile_DetectsNewSocket() { const string code = @"var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Network, result[0].Kind); Assert.Equal("Socket/TcpClient", result[0].Pattern); } [Fact] public void ScanFile_DetectsNewTcpClient() { const string code = @"var tcp = new TcpClient(""localhost"", 8080);"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Network, result[0].Kind); Assert.Equal("Socket/TcpClient", result[0].Pattern); } [Fact] public void ScanFile_DetectsWebRequestCreate() { const string code = @"var request = WebRequest.Create(url);"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Network, result[0].Kind); Assert.Equal("WebRequest", result[0].Pattern); } #endregion #region ScanFile - Environment Patterns [Fact] public void ScanFile_DetectsEnvironmentGetEnvironmentVariable() { const string code = @"var path = Environment.GetEnvironmentVariable(""PATH"");"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Environment, result[0].Kind); Assert.Equal("Environment.GetEnvironmentVariable", result[0].Pattern); Assert.Equal(CapabilityRisk.Medium, result[0].Risk); } [Fact] public void ScanFile_DetectsEnvironmentSetEnvironmentVariable() { const string code = @"Environment.SetEnvironmentVariable(""MY_VAR"", ""value"");"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Environment, result[0].Kind); Assert.Equal("Environment.SetEnvironmentVariable", result[0].Pattern); Assert.Equal(CapabilityRisk.High, result[0].Risk); } [Fact] public void ScanFile_DetectsEnvironmentGetEnvironmentVariables() { const string code = @"var envVars = Environment.GetEnvironmentVariables();"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Environment, result[0].Kind); Assert.Equal("Environment.GetEnvironmentVariables", result[0].Pattern); } #endregion #region ScanFile - Serialization Patterns (Critical for deserialization attacks) [Fact] public void ScanFile_DetectsBinaryFormatter() { const string code = @"var formatter = new BinaryFormatter();"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Serialization, result[0].Kind); Assert.Equal("BinaryFormatter", result[0].Pattern); Assert.Equal(CapabilityRisk.Critical, result[0].Risk); } [Fact] public void ScanFile_DetectsObjectStateFormatter() { const string code = @"var formatter = new ObjectStateFormatter();"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Serialization, result[0].Kind); Assert.Equal("ObjectStateFormatter", result[0].Pattern); Assert.Equal(CapabilityRisk.Critical, result[0].Risk); } [Fact] public void ScanFile_DetectsNetDataContractSerializer() { const string code = @"var serializer = new NetDataContractSerializer();"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Serialization, result[0].Kind); Assert.Equal("NetDataContractSerializer", result[0].Pattern); Assert.Equal(CapabilityRisk.Critical, result[0].Risk); } [Fact] public void ScanFile_DetectsLosFormatter() { const string code = @"var formatter = new LosFormatter();"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Serialization, result[0].Kind); Assert.Equal("LosFormatter", result[0].Pattern); Assert.Equal(CapabilityRisk.Critical, result[0].Risk); } [Fact] public void ScanFile_DetectsSoapFormatter() { const string code = @"var formatter = new SoapFormatter();"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Serialization, result[0].Kind); Assert.Equal("SoapFormatter", result[0].Pattern); Assert.Equal(CapabilityRisk.Critical, result[0].Risk); } [Fact] public void ScanFile_DetectsDataContractSerializer() { const string code = @"var serializer = new DataContractSerializer(typeof(MyClass));"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Serialization, result[0].Kind); Assert.Equal("DataContractSerializer", result[0].Pattern); Assert.Equal(CapabilityRisk.Medium, result[0].Risk); } [Fact] public void ScanFile_DetectsJsonDeserialize() { const string code = @"var obj = JsonSerializer.Deserialize(json);"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Serialization, result[0].Kind); Assert.Equal("JsonSerializer.Deserialize", result[0].Pattern); Assert.Equal(CapabilityRisk.Low, result[0].Risk); } #endregion #region ScanFile - Crypto Patterns [Fact] public void ScanFile_DetectsAesCreate() { const string code = @"using var aes = Aes.Create();"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Crypto, result[0].Kind); Assert.Equal("Cryptography", result[0].Pattern); Assert.Equal(CapabilityRisk.Low, result[0].Risk); } [Fact] public void ScanFile_DetectsRsaCreate() { const string code = @"using var rsa = RSA.Create();"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Crypto, result[0].Kind); Assert.Equal("Asymmetric crypto", result[0].Pattern); } #endregion #region ScanFile - Database Patterns [Fact] public void ScanFile_DetectsNewSqlConnection() { const string code = @"using var conn = new SqlConnection(connectionString);"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Database, result[0].Kind); Assert.Equal("SqlConnection", result[0].Pattern); Assert.Equal(CapabilityRisk.Medium, result[0].Risk); } [Fact] public void ScanFile_DetectsNewSqlCommand() { const string code = @"var cmd = new SqlCommand(""SELECT * FROM Users"", conn);"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Database, result[0].Kind); Assert.Equal("SqlCommand", result[0].Pattern); } [Fact] public void ScanFile_DetectsExecuteNonQuery() { const string code = @"cmd.ExecuteNonQuery();"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Database, result[0].Kind); Assert.Equal("Execute*", result[0].Pattern); } [Fact] public void ScanFile_DetectsExecuteReader() { const string code = @"using var reader = cmd.ExecuteReader();"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Database, result[0].Kind); } #endregion #region ScanFile - Dynamic Code Patterns [Fact] public void ScanFile_DetectsDynamicMethod() { const string code = @"var dm = new DynamicMethod(""Test"", typeof(int), null);"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.DynamicCode, result[0].Kind); Assert.Equal("DynamicMethod", result[0].Pattern); Assert.Equal(CapabilityRisk.Critical, result[0].Risk); } [Fact] public void ScanFile_DetectsILGenerator() { const string code = @"var il = dm.GetILGenerator();"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.DynamicCode, result[0].Kind); Assert.Equal("ILGenerator", result[0].Pattern); Assert.Equal(CapabilityRisk.Critical, result[0].Risk); } [Fact] public void ScanFile_DetectsCSharpScript() { const string code = @"var result = await CSharpScript.EvaluateAsync(code);"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.DynamicCode, result[0].Kind); Assert.Equal("CSharpScript", result[0].Pattern); Assert.Equal(CapabilityRisk.Critical, result[0].Risk); } [Fact] public void ScanFile_DetectsTypeBuilder() { const string code = @"var tb = mb.DefineType(""MyType"");"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); // TypeBuilder check expects "TypeBuilder" in the line Assert.Empty(result); // DefineType doesn't match TypeBuilder pattern } #endregion #region ScanFile - Reflection Patterns [Fact] public void ScanFile_DetectsAssemblyLoad() { const string code = @"var assembly = Assembly.Load(""MyAssembly"");"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Reflection, result[0].Kind); Assert.Equal("Assembly.Load", result[0].Pattern); Assert.Equal(CapabilityRisk.High, result[0].Risk); } [Fact] public void ScanFile_DetectsAssemblyLoadFrom() { const string code = @"var assembly = Assembly.LoadFrom(""plugin.dll"");"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Reflection, result[0].Kind); Assert.Equal("Assembly.Load", result[0].Pattern); } [Fact] public void ScanFile_DetectsAssemblyLoadFile() { const string code = @"var assembly = Assembly.LoadFile(path);"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Reflection, result[0].Kind); } [Fact] public void ScanFile_DetectsTypeInvokeMember() { const string code = @"type.InvokeMember(""Method"", BindingFlags.InvokeMethod, null, obj, args);"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Reflection, result[0].Kind); Assert.Equal("Type.InvokeMember", result[0].Pattern); Assert.Equal(CapabilityRisk.High, result[0].Risk); } [Fact] public void ScanFile_DetectsActivatorCreateInstance() { const string code = @"var obj = Activator.CreateInstance(type);"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.Reflection, result[0].Kind); Assert.Equal("Activator.CreateInstance", result[0].Pattern); Assert.Equal(CapabilityRisk.Medium, result[0].Risk); } #endregion #region ScanFile - Native Code Patterns [Fact] public void ScanFile_DetectsDllImport() { const string code = @"[DllImport(""kernel32.dll"")]"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.NativeCode, result[0].Kind); Assert.Equal("DllImport", result[0].Pattern); Assert.Equal(CapabilityRisk.High, result[0].Risk); } [Fact] public void ScanFile_DetectsLibraryImport() { const string code = @"[LibraryImport(""user32.dll"")]"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.NativeCode, result[0].Kind); Assert.Equal("LibraryImport", result[0].Pattern); Assert.Equal(CapabilityRisk.High, result[0].Risk); } [Fact] public void ScanFile_DetectsMarshalPtrToStructure() { const string code = @"var obj = Marshal.PtrToStructure(ptr);"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.NativeCode, result[0].Kind); Assert.Equal("Marshal operations", result[0].Pattern); } [Fact] public void ScanFile_DetectsMarshalAllocHGlobal() { const string code = @"var ptr = Marshal.AllocHGlobal(size);"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.NativeCode, result[0].Kind); } [Fact] public void ScanFile_DetectsNativeLibraryLoad() { const string code = @"var lib = NativeLibrary.Load(""mylib.dll"");"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.NativeCode, result[0].Kind); Assert.Equal("NativeLibrary.Load", result[0].Pattern); } [Fact] public void ScanFile_DetectsIntPtrOperations() { const string code = @"var ptr = new IntPtr(address);"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.NativeCode, result[0].Kind); Assert.Equal("IntPtr operations", result[0].Pattern); Assert.Equal(CapabilityRisk.Medium, result[0].Risk); } #endregion #region ScanFile - Unsafe Patterns [Fact] public void ScanFile_DetectsUnsafeBlock() { const string code = @"unsafe { var ptr = &value; }"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.NativeCode, result[0].Kind); Assert.Equal("unsafe block", result[0].Pattern); Assert.Equal(CapabilityRisk.Critical, result[0].Risk); } [Fact] public void ScanFile_DetectsFixedStatement() { const string code = @"fixed (byte* ptr = array) { }"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.NativeCode, result[0].Kind); Assert.Equal("fixed statement", result[0].Pattern); Assert.Equal(CapabilityRisk.High, result[0].Risk); } [Fact] public void ScanFile_DetectsStackalloc() { const string code = @"Span buffer = stackalloc byte[256];"; var result = DotNetCapabilityScanner.ScanFile(code, TestFile); Assert.Single(result); Assert.Equal(CapabilityKind.NativeCode, result[0].Kind); Assert.Equal("stackalloc", result[0].Pattern); Assert.Equal(CapabilityRisk.High, result[0].Risk); } #endregion #region DotNetCapabilityEvidence Tests [Fact] public void Evidence_DeduplicationKey_IsCorrect() { var evidence = new DotNetCapabilityEvidence( CapabilityKind.Exec, "Test.cs", 10, "Process.Start"); Assert.Equal("Exec|Test.cs|10|Process.Start", evidence.DeduplicationKey); } [Fact] public void Evidence_ConfidenceIsClamped() { var evidence1 = new DotNetCapabilityEvidence( CapabilityKind.Exec, "Test.cs", 1, "pattern", confidence: 2.0f); var evidence2 = new DotNetCapabilityEvidence( CapabilityKind.Exec, "Test.cs", 1, "pattern", confidence: -1.0f); Assert.Equal(1.0f, evidence1.Confidence); Assert.Equal(0.0f, evidence2.Confidence); } [Fact] public void Evidence_CreateMetadata_IncludesAllFields() { var evidence = new DotNetCapabilityEvidence( CapabilityKind.Exec, "Test.cs", 10, "Process.Start", snippet: "Process.Start(\"cmd.exe\");", confidence: 0.95f, risk: CapabilityRisk.Critical); var metadata = evidence.CreateMetadata().ToDictionary(kv => kv.Key, kv => kv.Value); Assert.Equal("exec", metadata["capability.kind"]); Assert.Equal("Test.cs:10", metadata["capability.source"]); Assert.Equal("Process.Start", metadata["capability.pattern"]); Assert.Equal("critical", metadata["capability.risk"]); Assert.Equal("0.95", metadata["capability.confidence"]); Assert.Contains("Process.Start", metadata["capability.snippet"]); } [Fact] public void Evidence_ToLanguageEvidence_ReturnsCorrectFormat() { var evidence = new DotNetCapabilityEvidence( CapabilityKind.Exec, "Test.cs", 10, "Process.Start"); var langEvidence = evidence.ToLanguageEvidence(); Assert.Equal(LanguageEvidenceKind.Metadata, langEvidence.Kind); Assert.Equal("Test.cs", langEvidence.Source); Assert.Equal("line:10", langEvidence.Locator); Assert.Equal("Exec:Process.Start", langEvidence.Value); } #endregion }