202 lines
5.4 KiB
C#
202 lines
5.4 KiB
C#
// Copyright (c) StellaOps. All rights reserved.
|
|
// Licensed under AGPL-3.0-or-later. See LICENSE in the project root.
|
|
|
|
using StellaOps.BinaryIndex.Decompiler;
|
|
using Xunit;
|
|
|
|
namespace StellaOps.BinaryIndex.Decompiler.Tests;
|
|
|
|
[Trait("Category", "Unit")]
|
|
public sealed class CodeNormalizerTests
|
|
{
|
|
private readonly CodeNormalizer _normalizer = new();
|
|
|
|
[Fact]
|
|
public void Normalize_WithWhitespace_NormalizesWhitespace()
|
|
{
|
|
// Arrange
|
|
var code = "int x = 1;";
|
|
var options = new NormalizationOptions { NormalizeWhitespace = true };
|
|
|
|
// Act
|
|
var normalized = _normalizer.Normalize(code, options);
|
|
|
|
// Assert
|
|
Assert.DoesNotContain(" ", normalized);
|
|
}
|
|
|
|
[Fact]
|
|
public void Normalize_WithVariables_NormalizesVariableNames()
|
|
{
|
|
// Arrange
|
|
var code = "int myVar = 1; int otherVar = myVar;";
|
|
var options = new NormalizationOptions { NormalizeVariables = true };
|
|
|
|
// Act
|
|
var normalized = _normalizer.Normalize(code, options);
|
|
|
|
// Assert
|
|
// Original variable names should be replaced with canonical names
|
|
Assert.DoesNotContain("myVar", normalized);
|
|
Assert.DoesNotContain("otherVar", normalized);
|
|
Assert.Contains("var_", normalized);
|
|
}
|
|
|
|
[Fact]
|
|
public void Normalize_WithConstants_NormalizesLargeNumbers()
|
|
{
|
|
// Arrange
|
|
var code = "int x = 1234567890;";
|
|
var options = new NormalizationOptions { NormalizeConstants = true };
|
|
|
|
// Act
|
|
var normalized = _normalizer.Normalize(code, options);
|
|
|
|
// Assert
|
|
Assert.DoesNotContain("1234567890", normalized);
|
|
}
|
|
|
|
[Fact]
|
|
public void Normalize_PreservesKeywords_DoesNotRenameKeywords()
|
|
{
|
|
// Arrange
|
|
var code = "int foo() { return 1; }";
|
|
var options = new NormalizationOptions { NormalizeVariables = true };
|
|
|
|
// Act
|
|
var normalized = _normalizer.Normalize(code, options);
|
|
|
|
// Assert
|
|
Assert.Contains("return", normalized);
|
|
Assert.Contains("int", normalized);
|
|
}
|
|
|
|
[Fact]
|
|
public void Normalize_PreservesStandardLibraryFunctions()
|
|
{
|
|
// Arrange
|
|
var code = "printf(\"hello\"); malloc(100); free(ptr);";
|
|
var options = new NormalizationOptions { NormalizeFunctionCalls = true };
|
|
|
|
// Act
|
|
var normalized = _normalizer.Normalize(code, options);
|
|
|
|
// Assert
|
|
Assert.Contains("printf", normalized);
|
|
Assert.Contains("malloc", normalized);
|
|
Assert.Contains("free", normalized);
|
|
}
|
|
|
|
[Fact]
|
|
public void ComputeCanonicalHash_SameCode_ReturnsSameHash()
|
|
{
|
|
// Arrange
|
|
var code1 = "int foo() { return 1; }";
|
|
var code2 = "int foo() { return 1; }";
|
|
|
|
// Act
|
|
var hash1 = _normalizer.ComputeCanonicalHash(code1);
|
|
var hash2 = _normalizer.ComputeCanonicalHash(code2);
|
|
|
|
// Assert
|
|
Assert.Equal(hash1, hash2);
|
|
}
|
|
|
|
[Fact]
|
|
public void ComputeCanonicalHash_DifferentWhitespace_ReturnsSameHash()
|
|
{
|
|
// Arrange
|
|
var code1 = "int foo(){return 1;}";
|
|
var code2 = "int foo() { return 1; }";
|
|
|
|
// Act
|
|
var hash1 = _normalizer.ComputeCanonicalHash(code1);
|
|
var hash2 = _normalizer.ComputeCanonicalHash(code2);
|
|
|
|
// Assert
|
|
Assert.Equal(hash1, hash2);
|
|
}
|
|
|
|
[Fact]
|
|
public void ComputeCanonicalHash_DifferentVariableNames_ReturnsSameHash()
|
|
{
|
|
// Arrange
|
|
var code1 = "int foo(int x) { return x + 1; }";
|
|
var code2 = "int foo(int y) { return y + 1; }";
|
|
|
|
// Act
|
|
var hash1 = _normalizer.ComputeCanonicalHash(code1);
|
|
var hash2 = _normalizer.ComputeCanonicalHash(code2);
|
|
|
|
// Assert
|
|
Assert.Equal(hash1, hash2);
|
|
}
|
|
|
|
[Fact]
|
|
public void ComputeCanonicalHash_DifferentLogic_ReturnsDifferentHash()
|
|
{
|
|
// Arrange
|
|
var code1 = "int foo(int x) { return x + 1; }";
|
|
var code2 = "int foo(int x) { return x - 1; }";
|
|
|
|
// Act
|
|
var hash1 = _normalizer.ComputeCanonicalHash(code1);
|
|
var hash2 = _normalizer.ComputeCanonicalHash(code2);
|
|
|
|
// Assert
|
|
Assert.NotEqual(hash1, hash2);
|
|
}
|
|
|
|
[Fact]
|
|
public void ComputeCanonicalHash_Returns32Bytes()
|
|
{
|
|
// Arrange
|
|
var code = "int foo() { return 1; }";
|
|
|
|
// Act
|
|
var hash = _normalizer.ComputeCanonicalHash(code);
|
|
|
|
// Assert (SHA256 = 32 bytes)
|
|
Assert.Equal(32, hash.Length);
|
|
}
|
|
|
|
[Fact]
|
|
public void Normalize_RemovesComments()
|
|
{
|
|
// Arrange
|
|
var code = @"
|
|
int foo() {
|
|
// This is a comment
|
|
return 1; /* inline comment */
|
|
}";
|
|
var options = NormalizationOptions.Default;
|
|
|
|
// Act
|
|
var normalized = _normalizer.Normalize(code, options);
|
|
|
|
// Assert
|
|
Assert.DoesNotContain("//", normalized);
|
|
Assert.DoesNotContain("/*", normalized);
|
|
}
|
|
|
|
[Fact]
|
|
public void NormalizeAst_WithParser_NormalizesAstNodes()
|
|
{
|
|
// Arrange
|
|
var parser = new DecompiledCodeParser();
|
|
var code = @"
|
|
int foo(int myVar) {
|
|
return myVar + 1;
|
|
}";
|
|
var ast = parser.Parse(code);
|
|
var options = new NormalizationOptions { NormalizeVariables = true };
|
|
|
|
// Act
|
|
var normalizedAst = _normalizer.NormalizeAst(ast, options);
|
|
|
|
// Assert
|
|
Assert.NotNull(normalizedAst);
|
|
Assert.Equal(ast.NodeCount, normalizedAst.NodeCount);
|
|
}
|
|
}
|