Files
codeql/csharp/extractor/Semmle.Extraction.Tests/Layout.cs

230 lines
9.5 KiB
C#

using System.IO;
using Xunit;
using Semmle.Util.Logging;
using System.Runtime.InteropServices;
namespace Semmle.Extraction.Tests
{
struct TransformedPathStub : PathTransformer.ITransformedPath
{
readonly string value;
public TransformedPathStub(string value) => this.value = value;
public string Value => value;
public string Extension => throw new System.NotImplementedException();
public string NameWithoutExtension => throw new System.NotImplementedException();
public PathTransformer.ITransformedPath ParentDirectory => throw new System.NotImplementedException();
public string DatabaseId => throw new System.NotImplementedException();
public PathTransformer.ITransformedPath WithSuffix(string suffix)
{
throw new System.NotImplementedException();
}
}
public class Layout
{
readonly ILogger Logger = new LoggerMock();
[Fact]
public void TestDefaultLayout()
{
var layout = new Semmle.Extraction.Layout(null, null, null);
var project = layout.LookupProjectOrNull(new TransformedPathStub("foo.cs"));
Assert.NotNull(project);
// All files are mapped when there's no layout file.
Assert.True(layout.FileInLayout(new TransformedPathStub("foo.cs")));
// Test trap filename
var tmpDir = Path.GetTempPath();
Directory.SetCurrentDirectory(tmpDir);
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
// `Directory.SetCurrentDirectory()` doesn't seem to work on macOS,
// so disable this test on macOS, for now
Assert.NotEqual(Directory.GetCurrentDirectory(), tmpDir);
return;
}
var f1 = project!.GetTrapPath(Logger, new TransformedPathStub("foo.cs"), TrapWriter.CompressionMode.Gzip);
var g1 = TrapWriter.NestPaths(Logger, tmpDir, "foo.cs.trap.gz");
Assert.Equal(f1, g1);
// Test trap file generation
var trapwriterFilename = project.GetTrapPath(Logger, new TransformedPathStub("foo.cs"), TrapWriter.CompressionMode.Gzip);
using (var trapwriter = project.CreateTrapWriter(Logger, new TransformedPathStub("foo.cs"), false, TrapWriter.CompressionMode.Gzip))
{
trapwriter.Emit("1=*");
Assert.False(File.Exists(trapwriterFilename));
}
Assert.True(File.Exists(trapwriterFilename));
File.Delete(trapwriterFilename);
}
[Fact]
public void TestLayoutFile()
{
File.WriteAllLines("layout.txt", new string[]
{
"# Section",
"TRAP_FOLDER=" + Path.GetFullPath("snapshot\\trap"),
"ODASA_DB=snapshot\\db-csharp",
"SOURCE_ARCHIVE=" + Path.GetFullPath("snapshot\\archive"),
"ODASA_BUILD_ERROR_DIR=snapshot\build-errors",
"-foo.cs",
"bar.cs",
"-excluded",
"excluded/foo.cs",
"included"
});
var layout = new Semmle.Extraction.Layout(null, null, "layout.txt");
// Test general pattern matching
Assert.True(layout.FileInLayout(new TransformedPathStub("bar.cs")));
Assert.False(layout.FileInLayout(new TransformedPathStub("foo.cs")));
Assert.False(layout.FileInLayout(new TransformedPathStub("goo.cs")));
Assert.False(layout.FileInLayout(new TransformedPathStub("excluded/bar.cs")));
Assert.True(layout.FileInLayout(new TransformedPathStub("excluded/foo.cs")));
Assert.True(layout.FileInLayout(new TransformedPathStub("included/foo.cs")));
// Test the trap file
var project = layout.LookupProjectOrNull(new TransformedPathStub("bar.cs"));
Assert.NotNull(project);
var trapwriterFilename = project!.GetTrapPath(Logger, new TransformedPathStub("bar.cs"), TrapWriter.CompressionMode.Gzip);
Assert.Equal(TrapWriter.NestPaths(Logger, Path.GetFullPath("snapshot\\trap"), "bar.cs.trap.gz"),
trapwriterFilename);
// Test the source archive
var trapWriter = project.CreateTrapWriter(Logger, new TransformedPathStub("bar.cs"), false, TrapWriter.CompressionMode.Gzip);
trapWriter.Archive("layout.txt", new TransformedPathStub("layout.txt"), System.Text.Encoding.ASCII);
var writtenFile = TrapWriter.NestPaths(Logger, Path.GetFullPath("snapshot\\archive"), "layout.txt");
Assert.True(File.Exists(writtenFile));
File.Delete("layout.txt");
}
[Fact]
public void TestTrapOverridesLayout()
{
// When you specify both a trap file and a layout, use the trap file.
var layout = new Semmle.Extraction.Layout(Path.GetFullPath("snapshot\\trap"), null, "something.txt");
Assert.True(layout.FileInLayout(new TransformedPathStub("bar.cs")));
var subProject = layout.LookupProjectOrNull(new TransformedPathStub("foo.cs"));
Assert.NotNull(subProject);
var f1 = subProject!.GetTrapPath(Logger, new TransformedPathStub("foo.cs"), TrapWriter.CompressionMode.Gzip);
var g1 = TrapWriter.NestPaths(Logger, Path.GetFullPath("snapshot\\trap"), "foo.cs.trap.gz");
Assert.Equal(f1, g1);
}
[Fact]
public void TestMultipleSections()
{
File.WriteAllLines("layout.txt", new string[]
{
"# Section 1",
"TRAP_FOLDER=" + Path.GetFullPath("snapshot\\trap1"),
"ODASA_DB=snapshot\\db-csharp",
"SOURCE_ARCHIVE=" + Path.GetFullPath("snapshot\\archive1"),
"ODASA_BUILD_ERROR_DIR=snapshot\build-errors",
"foo.cs",
"# Section 2",
"TRAP_FOLDER=" + Path.GetFullPath("snapshot\\trap2"),
"ODASA_DB=snapshot\\db-csharp",
"SOURCE_ARCHIVE=" + Path.GetFullPath("snapshot\\archive2"),
"ODASA_BUILD_ERROR_DIR=snapshot\build-errors",
"bar.cs",
});
var layout = new Semmle.Extraction.Layout(null, null, "layout.txt");
// Use Section 2
Assert.True(layout.FileInLayout(new TransformedPathStub("bar.cs")));
var subProject = layout.LookupProjectOrNull(new TransformedPathStub("bar.cs"));
Assert.NotNull(subProject);
var f1 = subProject!.GetTrapPath(Logger, new TransformedPathStub("bar.cs"), TrapWriter.CompressionMode.Gzip);
var g1 = TrapWriter.NestPaths(Logger, Path.GetFullPath("snapshot\\trap2"), "bar.cs.trap.gz");
Assert.Equal(f1, g1);
// Use Section 1
Assert.True(layout.FileInLayout(new TransformedPathStub("foo.cs")));
subProject = layout.LookupProjectOrNull(new TransformedPathStub("foo.cs"));
Assert.NotNull(subProject);
var f2 = subProject!.GetTrapPath(Logger, new TransformedPathStub("foo.cs"), TrapWriter.CompressionMode.Gzip);
var g2 = TrapWriter.NestPaths(Logger, Path.GetFullPath("snapshot\\trap1"), "foo.cs.trap.gz");
Assert.Equal(f2, g2);
// boo.dll is not in the layout, so use layout from first section.
Assert.False(layout.FileInLayout(new TransformedPathStub("boo.dll")));
var f3 = layout.LookupProjectOrDefault(new TransformedPathStub("boo.dll")).GetTrapPath(Logger, new TransformedPathStub("boo.dll"), TrapWriter.CompressionMode.Gzip);
var g3 = TrapWriter.NestPaths(Logger, Path.GetFullPath("snapshot\\trap1"), "boo.dll.trap.gz");
Assert.Equal(f3, g3);
// boo.cs is not in the layout, so return null
Assert.False(layout.FileInLayout(new TransformedPathStub("boo.cs")));
Assert.Null(layout.LookupProjectOrNull(new TransformedPathStub("boo.cs")));
}
[Fact]
public void MissingLayout()
{
Assert.Throws<Extraction.Layout.InvalidLayoutException>(() =>
new Semmle.Extraction.Layout(null, null, "nosuchfile.txt"));
}
[Fact]
public void EmptyLayout()
{
File.Create("layout.txt").Close();
Assert.Throws<Extraction.Layout.InvalidLayoutException>(() =>
new Semmle.Extraction.Layout(null, null, "layout.txt"));
}
[Fact]
public void InvalidLayout()
{
File.WriteAllLines("layout.txt", new string[]
{
"# Section 1"
});
Assert.Throws<Extraction.Layout.InvalidLayoutException>(() =>
new Semmle.Extraction.Layout(null, null, "layout.txt"));
}
class LoggerMock : ILogger
{
public void Dispose() { }
public void Log(Severity s, string text) { }
public void Log(Severity s, string text, params object[] args) { }
}
}
static class TrapWriterTestExtensions
{
public static void Emit(this TrapWriter trapFile, string s)
{
trapFile.Emit(new StringTrapEmitter(s));
}
class StringTrapEmitter : ITrapEmitter
{
readonly string Content;
public StringTrapEmitter(string content)
{
Content = content;
}
public void EmitTrap(TextWriter trapFile)
{
trapFile.Write(Content);
}
}
}
}