337 lines
7.8 KiB
C#
337 lines
7.8 KiB
C#
|
|
using System;
|
||
|
|
using System.Threading.Tasks;
|
||
|
|
using Microsoft.CodeAnalysis;
|
||
|
|
using Microsoft.CodeAnalysis.CSharp.Testing;
|
||
|
|
using Microsoft.CodeAnalysis.Testing;
|
||
|
|
using Microsoft.CodeAnalysis.Testing.Verifiers;
|
||
|
|
using SqrtSpace.SpaceTime.Analyzers;
|
||
|
|
using Xunit;
|
||
|
|
|
||
|
|
namespace SqrtSpace.SpaceTime.Tests.Analyzers;
|
||
|
|
|
||
|
|
public class LargeAllocationAnalyzerTests : CSharpAnalyzerTest<LargeAllocationAnalyzer, XUnitVerifier>
|
||
|
|
{
|
||
|
|
[Fact]
|
||
|
|
public async Task ToList_OnIQueryable_ProducesDiagnostic()
|
||
|
|
{
|
||
|
|
const string source = @"
|
||
|
|
using System.Linq;
|
||
|
|
|
||
|
|
class TestClass
|
||
|
|
{
|
||
|
|
void TestMethod()
|
||
|
|
{
|
||
|
|
var context = new TestContext();
|
||
|
|
var result = context.LargeCollection.{|#0:ToList|}();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class TestContext
|
||
|
|
{
|
||
|
|
public IQueryable<string> LargeCollection { get; set; }
|
||
|
|
}";
|
||
|
|
|
||
|
|
var test = new CSharpAnalyzerTest<LargeAllocationAnalyzer, XUnitVerifier>
|
||
|
|
{
|
||
|
|
TestCode = source
|
||
|
|
};
|
||
|
|
|
||
|
|
test.ExpectedDiagnostics.Add(
|
||
|
|
new DiagnosticResult(LargeAllocationAnalyzer.DiagnosticId, DiagnosticSeverity.Warning)
|
||
|
|
.WithLocation(0)
|
||
|
|
.WithArguments("collection"));
|
||
|
|
|
||
|
|
await test.RunAsync();
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task ToArray_OnLargeCollection_ProducesDiagnostic()
|
||
|
|
{
|
||
|
|
const string source = @"
|
||
|
|
using System.Linq;
|
||
|
|
|
||
|
|
class TestClass
|
||
|
|
{
|
||
|
|
void TestMethod()
|
||
|
|
{
|
||
|
|
var context = new DatabaseContext();
|
||
|
|
var array = context.Items.{|#0:ToArray|}();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class DatabaseContext
|
||
|
|
{
|
||
|
|
public IQueryable<Item> Items { get; set; }
|
||
|
|
}
|
||
|
|
|
||
|
|
class Item { }";
|
||
|
|
|
||
|
|
var test = new CSharpAnalyzerTest<LargeAllocationAnalyzer, XUnitVerifier>
|
||
|
|
{
|
||
|
|
TestCode = source
|
||
|
|
};
|
||
|
|
|
||
|
|
test.ExpectedDiagnostics.Add(
|
||
|
|
new DiagnosticResult(LargeAllocationAnalyzer.DiagnosticId, DiagnosticSeverity.Warning)
|
||
|
|
.WithLocation(0)
|
||
|
|
.WithArguments("collection"));
|
||
|
|
|
||
|
|
await test.RunAsync();
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task OrderBy_OnLargeCollection_ProducesDiagnostic()
|
||
|
|
{
|
||
|
|
const string source = @"
|
||
|
|
using System.Linq;
|
||
|
|
|
||
|
|
class TestClass
|
||
|
|
{
|
||
|
|
void TestMethod()
|
||
|
|
{
|
||
|
|
var context = new DataContext();
|
||
|
|
var sorted = context.Records.{|#0:OrderBy|}(r => r.Date);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class DataContext
|
||
|
|
{
|
||
|
|
public IQueryable<Record> Records { get; set; }
|
||
|
|
}
|
||
|
|
|
||
|
|
class Record
|
||
|
|
{
|
||
|
|
public DateTime Date { get; set; }
|
||
|
|
}";
|
||
|
|
|
||
|
|
var test = new CSharpAnalyzerTest<LargeAllocationAnalyzer, XUnitVerifier>
|
||
|
|
{
|
||
|
|
TestCode = source
|
||
|
|
};
|
||
|
|
|
||
|
|
test.ExpectedDiagnostics.Add(
|
||
|
|
new DiagnosticResult(LargeAllocationAnalyzer.DiagnosticId, DiagnosticSeverity.Warning)
|
||
|
|
.WithLocation(0)
|
||
|
|
.WithArguments("OrderBy"));
|
||
|
|
|
||
|
|
await test.RunAsync();
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task GroupBy_OnLargeCollection_ProducesDiagnostic()
|
||
|
|
{
|
||
|
|
const string source = @"
|
||
|
|
using System.Linq;
|
||
|
|
|
||
|
|
class TestClass
|
||
|
|
{
|
||
|
|
void TestMethod()
|
||
|
|
{
|
||
|
|
var context = new DataContext();
|
||
|
|
var groups = context.Users.{|#0:GroupBy|}(u => u.Country);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class DataContext
|
||
|
|
{
|
||
|
|
public IQueryable<User> Users { get; set; }
|
||
|
|
}
|
||
|
|
|
||
|
|
class User
|
||
|
|
{
|
||
|
|
public string Country { get; set; }
|
||
|
|
}";
|
||
|
|
|
||
|
|
var test = new CSharpAnalyzerTest<LargeAllocationAnalyzer, XUnitVerifier>
|
||
|
|
{
|
||
|
|
TestCode = source
|
||
|
|
};
|
||
|
|
|
||
|
|
test.ExpectedDiagnostics.Add(
|
||
|
|
new DiagnosticResult(LargeAllocationAnalyzer.DiagnosticId, DiagnosticSeverity.Warning)
|
||
|
|
.WithLocation(0)
|
||
|
|
.WithArguments("GroupBy"));
|
||
|
|
|
||
|
|
await test.RunAsync();
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task LargeArrayAllocation_ProducesDiagnostic()
|
||
|
|
{
|
||
|
|
const string source = @"
|
||
|
|
class TestClass
|
||
|
|
{
|
||
|
|
void TestMethod()
|
||
|
|
{
|
||
|
|
var largeArray = {|#0:new int[100000]|};
|
||
|
|
}
|
||
|
|
}";
|
||
|
|
|
||
|
|
var test = new CSharpAnalyzerTest<LargeAllocationAnalyzer, XUnitVerifier>
|
||
|
|
{
|
||
|
|
TestCode = source
|
||
|
|
};
|
||
|
|
|
||
|
|
test.ExpectedDiagnostics.Add(
|
||
|
|
new DiagnosticResult(LargeAllocationAnalyzer.DiagnosticId, DiagnosticSeverity.Warning)
|
||
|
|
.WithLocation(0)
|
||
|
|
.WithArguments("array allocation"));
|
||
|
|
|
||
|
|
await test.RunAsync();
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task LargeListAllocation_ProducesDiagnostic()
|
||
|
|
{
|
||
|
|
const string source = @"
|
||
|
|
using System.Collections.Generic;
|
||
|
|
|
||
|
|
class TestClass
|
||
|
|
{
|
||
|
|
void TestMethod()
|
||
|
|
{
|
||
|
|
var largeList = {|#0:new List<string>(100000)|};
|
||
|
|
}
|
||
|
|
}";
|
||
|
|
|
||
|
|
var test = new CSharpAnalyzerTest<LargeAllocationAnalyzer, XUnitVerifier>
|
||
|
|
{
|
||
|
|
TestCode = source
|
||
|
|
};
|
||
|
|
|
||
|
|
test.ExpectedDiagnostics.Add(
|
||
|
|
new DiagnosticResult(LargeAllocationAnalyzer.DiagnosticId, DiagnosticSeverity.Warning)
|
||
|
|
.WithLocation(0)
|
||
|
|
.WithArguments("list allocation"));
|
||
|
|
|
||
|
|
await test.RunAsync();
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task SmallAllocation_NoDiagnostic()
|
||
|
|
{
|
||
|
|
const string source = @"
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Linq;
|
||
|
|
|
||
|
|
class TestClass
|
||
|
|
{
|
||
|
|
void TestMethod()
|
||
|
|
{
|
||
|
|
var smallArray = new int[100];
|
||
|
|
var smallList = new List<string>(100);
|
||
|
|
var items = new[] { 1, 2, 3, 4, 5 };
|
||
|
|
var sorted = items.OrderBy(x => x).ToList();
|
||
|
|
}
|
||
|
|
}";
|
||
|
|
|
||
|
|
var test = new CSharpAnalyzerTest<LargeAllocationAnalyzer, XUnitVerifier>
|
||
|
|
{
|
||
|
|
TestCode = source
|
||
|
|
};
|
||
|
|
|
||
|
|
await test.RunAsync();
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task ToList_OnSmallCollection_NoDiagnostic()
|
||
|
|
{
|
||
|
|
const string source = @"
|
||
|
|
using System.Linq;
|
||
|
|
|
||
|
|
class TestClass
|
||
|
|
{
|
||
|
|
void TestMethod()
|
||
|
|
{
|
||
|
|
var items = new[] { 1, 2, 3, 4, 5 };
|
||
|
|
var list = items.ToList();
|
||
|
|
}
|
||
|
|
}";
|
||
|
|
|
||
|
|
var test = new CSharpAnalyzerTest<LargeAllocationAnalyzer, XUnitVerifier>
|
||
|
|
{
|
||
|
|
TestCode = source
|
||
|
|
};
|
||
|
|
|
||
|
|
await test.RunAsync();
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task NestedLinqOperations_ProducesMultipleDiagnostics()
|
||
|
|
{
|
||
|
|
const string source = @"
|
||
|
|
using System;
|
||
|
|
using System.Linq;
|
||
|
|
|
||
|
|
class TestClass
|
||
|
|
{
|
||
|
|
void TestMethod()
|
||
|
|
{
|
||
|
|
var context = new BigDataContext();
|
||
|
|
var result = context.Transactions
|
||
|
|
.{|#0:OrderBy|}(t => t.Date)
|
||
|
|
.{|#1:GroupBy|}(t => t.Category)
|
||
|
|
.{|#2:ToList|}();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class BigDataContext
|
||
|
|
{
|
||
|
|
public IQueryable<Transaction> Transactions { get; set; }
|
||
|
|
}
|
||
|
|
|
||
|
|
class Transaction
|
||
|
|
{
|
||
|
|
public DateTime Date { get; set; }
|
||
|
|
public string Category { get; set; }
|
||
|
|
}";
|
||
|
|
|
||
|
|
var test = new CSharpAnalyzerTest<LargeAllocationAnalyzer, XUnitVerifier>
|
||
|
|
{
|
||
|
|
TestCode = source
|
||
|
|
};
|
||
|
|
|
||
|
|
test.ExpectedDiagnostics.Add(
|
||
|
|
new DiagnosticResult(LargeAllocationAnalyzer.DiagnosticId, DiagnosticSeverity.Warning)
|
||
|
|
.WithLocation(0)
|
||
|
|
.WithArguments("OrderBy"));
|
||
|
|
|
||
|
|
test.ExpectedDiagnostics.Add(
|
||
|
|
new DiagnosticResult(LargeAllocationAnalyzer.DiagnosticId, DiagnosticSeverity.Warning)
|
||
|
|
.WithLocation(1)
|
||
|
|
.WithArguments("GroupBy"));
|
||
|
|
|
||
|
|
test.ExpectedDiagnostics.Add(
|
||
|
|
new DiagnosticResult(LargeAllocationAnalyzer.DiagnosticId, DiagnosticSeverity.Warning)
|
||
|
|
.WithLocation(2)
|
||
|
|
.WithArguments("collection"));
|
||
|
|
|
||
|
|
await test.RunAsync();
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task DynamicSizeAllocation_ProducesDiagnostic()
|
||
|
|
{
|
||
|
|
const string source = @"
|
||
|
|
class TestClass
|
||
|
|
{
|
||
|
|
void TestMethod(int size)
|
||
|
|
{
|
||
|
|
// Dynamic size - analyzer assumes it could be large
|
||
|
|
var array = {|#0:new byte[size]|};
|
||
|
|
}
|
||
|
|
}";
|
||
|
|
|
||
|
|
var test = new CSharpAnalyzerTest<LargeAllocationAnalyzer, XUnitVerifier>
|
||
|
|
{
|
||
|
|
TestCode = source
|
||
|
|
};
|
||
|
|
|
||
|
|
test.ExpectedDiagnostics.Add(
|
||
|
|
new DiagnosticResult(LargeAllocationAnalyzer.DiagnosticId, DiagnosticSeverity.Warning)
|
||
|
|
.WithLocation(0)
|
||
|
|
.WithArguments("array allocation"));
|
||
|
|
|
||
|
|
await test.RunAsync();
|
||
|
|
}
|
||
|
|
}
|