Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 26 additions & 10 deletions tests/VbaCompiler.Tests/Streams/VbaProjectRoundTripTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under MIT-style license (see LICENSE.txt file).

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
Expand All @@ -24,6 +25,8 @@ class VbaProjectRoundTripTests
{
private byte[] _compiledVbaProject = null!;
private byte[] _compiledMultiModuleVbaProject = null!;
private string _testModuleExpectedSource = null!;
private string _classExpectedSource = null!;

[SetUp]
public void Setup()
Expand All @@ -34,6 +37,12 @@ public void Setup()
var modulePath = Path.Combine(sourcePath, "TestModule.vb");
var classPath = Path.Combine(sourcePath, "Class.vb");

// Generate expected compiled source using ModuleUnit (includes VBA headers)
var testModule = ModuleUnit.FromFile(modulePath, ModuleUnitType.Module, null);
var classModule = ModuleUnit.FromFile(classPath, ModuleUnitType.Class, null);
_testModuleExpectedSource = testModule.ToModuleCode();
_classExpectedSource = classModule.ToModuleCode();

// Compile single-module project
var compiler = CreateTestCompiler("RoundTripTest");
compiler.AddModule(modulePath);
Expand Down Expand Up @@ -140,7 +149,7 @@ public void CompileVbaProject_ShouldProduceReadableModules()
}

[Test]
public void CompileVbaProject_DecompiledCodeShouldContainOriginalSource()
public void CompileVbaProject_DecompiledCodeShouldMatchOriginalSource()
{
using var compoundFile = new CompoundFile(new MemoryStream(_compiledVbaProject));
var vbaStorage = compoundFile.RootStorage.GetStorage("VBA");
Expand Down Expand Up @@ -168,16 +177,12 @@ public void CompileVbaProject_DecompiledCodeShouldContainOriginalSource()

var decompressedSource = Encoding.GetEncoding(1252).GetString(VbaCompression.Decompress(moduleCode));

ClassicAssert.IsTrue(decompressedSource.Contains("HelloWorld"),
"Decompiled source should contain 'HelloWorld' function");
ClassicAssert.IsTrue(decompressedSource.Contains("AddNumbers"),
"Decompiled source should contain 'AddNumbers' function");
ClassicAssert.IsTrue(decompressedSource.Contains("MsgBox"),
"Decompiled source should contain 'MsgBox' call");
ClassicAssert.AreEqual(_testModuleExpectedSource, decompressedSource,
"Decompiled source should exactly match the original source with VBA headers");
}

[Test]
public void CompileVbaProject_WithMultipleModules_AllShouldBeDecompilable()
public void CompileVbaProject_WithMultipleModules_AllShouldMatchOriginalSource()
{
using var compoundFile = new CompoundFile(new MemoryStream(_compiledMultiModuleVbaProject));
var vbaStorage = compoundFile.RootStorage.GetStorage("VBA");
Expand All @@ -192,6 +197,13 @@ public void CompileVbaProject_WithMultipleModules_AllShouldBeDecompilable()
var modules = VbadDecompiler.DirStream.GetModules(dirData).ToList();
ClassicAssert.AreEqual(2, modules.Count, "Should have exactly 2 modules (TestModule and Class)");

// Map of module names to their expected source
var expectedSources = new Dictionary<string, string>
{
{ "TestModule", _testModuleExpectedSource },
{ "Class", _classExpectedSource }
};

foreach (var module in modules)
{
var moduleStream = vbaStorage.GetStream(module.Name);
Expand All @@ -205,8 +217,12 @@ public void CompileVbaProject_WithMultipleModules_AllShouldBeDecompilable()
ClassicAssert.Greater(moduleCode.Length, 0,
$"Module '{module.Name}' code after offset is empty");

var decompressedCode = VbaCompression.Decompress(moduleCode);
ClassicAssert.IsNotNull(decompressedCode, $"Module '{module.Name}' should decompress successfully");
var decompressedSource = Encoding.GetEncoding(1252).GetString(VbaCompression.Decompress(moduleCode));

ClassicAssert.IsTrue(expectedSources.ContainsKey(module.Name!),
$"Unexpected module '{module.Name}' found in compiled project");
ClassicAssert.AreEqual(expectedSources[module.Name!], decompressedSource,
$"Decompiled source for module '{module.Name}' should exactly match the original source with VBA headers");
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions tests/VbaCompiler.Tests/data/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# VBA source files must have Windows line endings (CRLF)
*.vb text eol=crlf
9 changes: 9 additions & 0 deletions tests/VbaCompiler.Tests/data/Class.vb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Public Property Name As String

Public Sub Initialize()
Name = "John Doe"
End Sub

Public Function GetGreeting() As String
GetGreeting = "Hello, " & Name & "!"
End Function
20 changes: 20 additions & 0 deletions tests/VbaCompiler.Tests/data/Module.vb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Attribute VB_Name = "Module1"
Option Explicit

' Sample module for VBA compiler testing
Public Sub HelloWorld()
Debug.Print "Hello, World!"
End Sub

Public Function Add(ByVal a As Integer, ByVal b As Integer) As Integer
Add = a + b
End Function

Public Function Multiply(ByVal x As Double, ByVal y As Double) As Double
Multiply = x * y
End Function

Private Sub InternalMethod()
' This is a private helper method
Debug.Print "Internal method called"
End Sub