Skip to content
Open
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
6 changes: 6 additions & 0 deletions Bot.sln
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Storage", "csharp\Storage\S
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TraderBot", "csharp\TraderBot\TraderBot.csproj", "{FAE89FE2-17C5-4AD6-98EC-84002CC4C672}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Storage.Tests", "csharp\Storage.Tests\Storage.Tests.csproj", "{B8E5F9A1-2D34-4E7F-9F8C-1A2B3C4D5E6F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -36,5 +38,9 @@ Global
{FAE89FE2-17C5-4AD6-98EC-84002CC4C672}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FAE89FE2-17C5-4AD6-98EC-84002CC4C672}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FAE89FE2-17C5-4AD6-98EC-84002CC4C672}.Release|Any CPU.Build.0 = Release|Any CPU
{B8E5F9A1-2D34-4E7F-9F8C-1A2B3C4D5E6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B8E5F9A1-2D34-4E7F-9F8C-1A2B3C4D5E6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B8E5F9A1-2D34-4E7F-9F8C-1A2B3C4D5E6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B8E5F9A1-2D34-4E7F-9F8C-1A2B3C4D5E6F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
153 changes: 153 additions & 0 deletions csharp/Storage.Tests/AstTransformationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
using System;
using System.IO;
using Xunit;
using Storage.Local;
using Storage.AST;

namespace Storage.Tests
{
public class AstTransformationTests : IDisposable
{
private readonly string _testDbPath;
private readonly FileStorage _storage;

public AstTransformationTests()
{
_testDbPath = Path.GetTempFileName();
_storage = new FileStorage(_testDbPath);
}

[Fact]
public void TransformCodeToAst_WithSimpleCode_ShouldCreateAstInLinksStore()
{
// Arrange
var code = @"using System;
namespace TestNamespace
{
public class TestClass
{
public void TestMethod()
{
Console.WriteLine(""Hello World"");
}
}
}";

// Act
var rootAstNodeLink = _storage.TransformCodeToAst(code);

// Assert
Assert.NotEqual(0UL, rootAstNodeLink);

var astNodes = _storage.GetAllAstNodes();
Assert.NotEmpty(astNodes);

var rootNodeInfo = _storage.GetAstNodeInfo(rootAstNodeLink);
Assert.Equal("CompilationUnit", rootNodeInfo["NodeType"]);
Assert.False(rootNodeInfo.ContainsKey("Error"));
}

[Fact]
public void CSharpAstTransformer_WithSimpleCode_ShouldMapNodesToExactPositions()
{
// Arrange
var transformer = new CSharpAstTransformer();
var code = "using System;\nnamespace Test {}";

// Act
var rootNode = transformer.TransformCode(code);

// Assert
Assert.Equal("CompilationUnit", rootNode.NodeType);
Assert.Equal(0, rootNode.StartPosition);
Assert.Equal(code.Length - 1, rootNode.EndPosition);
Assert.Equal(1, rootNode.StartLine);
Assert.Equal(2, rootNode.EndLine);

// Check that children are created
Assert.NotEmpty(rootNode.Children);

// Verify all nodes have position information
var allNodes = transformer.GetAllNodesWithPositions(rootNode);
foreach (var node in allNodes)
{
Assert.True(node.StartPosition >= 0);
Assert.True(node.EndPosition >= node.StartPosition);
Assert.True(node.StartLine >= 1);
Assert.True(node.StartColumn >= 0);
}
}

[Fact]
public void AstNode_WithChildNodes_ShouldMaintainParentChildRelationships()
{
// Arrange
var parent = new AstNode { NodeType = "Parent", Text = "parent content" };
var child1 = new AstNode { NodeType = "Child1", Text = "child1 content" };
var child2 = new AstNode { NodeType = "Child2", Text = "child2 content" };

// Act
parent.AddChild(child1);
parent.AddChild(child2);

// Assert
Assert.Equal(2, parent.Children.Count);
Assert.Equal(parent, child1.Parent);
Assert.Equal(parent, child2.Parent);
Assert.Equal(0, parent.Depth);
Assert.Equal(1, child1.Depth);
Assert.Equal(1, child2.Depth);
}

[Fact]
public void TransformCodeToAst_WithEmptyCode_ShouldThrowArgumentException()
{
// Act & Assert
Assert.Throws<ArgumentException>(() => _storage.TransformCodeToAst(""));
Assert.Throws<ArgumentException>(() => _storage.TransformCodeToAst(null));
}

[Fact]
public void GetAstNodeInfo_WithValidAstNode_ShouldReturnNodeInformation()
{
// Arrange
var code = "public class TestClass {}";
var rootAstNodeLink = _storage.TransformCodeToAst(code);

// Act
var nodeInfo = _storage.GetAstNodeInfo(rootAstNodeLink);

// Assert
Assert.Contains("NodeType", nodeInfo.Keys);
Assert.Contains("Text", nodeInfo.Keys);
Assert.Contains("LinkAddress", nodeInfo.Keys);
Assert.Contains("HasPositionInfo", nodeInfo.Keys);
Assert.False(nodeInfo.ContainsKey("Error"));
}

[Fact]
public void GetAllAstNodes_AfterTransformation_ShouldReturnStoredNodes()
{
// Arrange
var code1 = "public class Class1 {}";
var code2 = "public interface ITest {}";

// Act
_storage.TransformCodeToAst(code1);
_storage.TransformCodeToAst(code2);
var allAstNodes = _storage.GetAllAstNodes();

// Assert
Assert.True(allAstNodes.Count >= 2); // At least 2 root nodes
}

public void Dispose()
{
_storage?.Dispose();
if (System.IO.File.Exists(_testDbPath))
{
System.IO.File.Delete(_testDbPath);
}
}
}
}
132 changes: 132 additions & 0 deletions csharp/Storage.Tests/AstUsageExample.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
using System;
using System.IO;
using Storage.Local;
using Storage.AST;

namespace Storage.Tests
{
/// <summary>
/// Example demonstrating how to use the AST transformation functionality.
/// </summary>
public class AstUsageExample
{
public static void RunExample()
{
var dbPath = Path.GetTempFileName();
try
{
using var storage = new FileStorage(dbPath);

// Example C# code to transform into AST
var csharpCode = @"using System;
namespace MyNamespace
{
public class Calculator
{
private int result;

public int Add(int a, int b)
{
result = a + b;
return result;
}

public void Reset()
{
result = 0;
}
}
}";

Console.WriteLine("Original C# code:");
Console.WriteLine(csharpCode);
Console.WriteLine("\n" + new string('=', 50) + "\n");

// Transform code into AST and store it in links
var rootAstNodeLink = storage.TransformCodeToAst(csharpCode);
Console.WriteLine($"Root AST node stored at link address: {rootAstNodeLink}");

// Get all AST nodes from the links store
var allAstNodes = storage.GetAllAstNodes();
Console.WriteLine($"Total AST nodes stored: {allAstNodes.Count}");

// Display information for each AST node
Console.WriteLine("\nAST Nodes with position mapping:");
Console.WriteLine(new string('-', 60));

foreach (var nodeLink in allAstNodes)
{
var nodeInfo = storage.GetAstNodeInfo(nodeLink);
if (!nodeInfo.ContainsKey("Error"))
{
Console.WriteLine($"Link: {nodeLink}");
Console.WriteLine($"Type: {nodeInfo["NodeType"]}");
Console.WriteLine($"Text: \"{nodeInfo["Text"]}\"");
Console.WriteLine($"Has Position Info: {nodeInfo["HasPositionInfo"]}");
Console.WriteLine();
}
}

// Demonstrate direct AST transformer usage
var transformer = new CSharpAstTransformer();
var astRoot = transformer.TransformCode(csharpCode);

Console.WriteLine("\nDirect AST Transformation Result:");
Console.WriteLine(new string('-', 40));
PrintAstNode(astRoot, 0);

// Get all nodes with positions
var allNodes = transformer.GetAllNodesWithPositions(astRoot);
Console.WriteLine($"\nTotal nodes with position mapping: {allNodes.Count}");
Console.WriteLine("\nNode position details:");
Console.WriteLine(new string('-', 80));

foreach (var node in allNodes.Take(10)) // Show first 10 for brevity
{
Console.WriteLine($"{node.NodeType,-20} | Pos: {node.StartPosition,3}-{node.EndPosition,3} | Line: {node.StartLine,2}-{node.EndLine,2} | \"{node.Text.Replace("\n", "\\n").Trim()}\"");
}

if (allNodes.Count > 10)
{
Console.WriteLine($"... and {allNodes.Count - 10} more nodes");
}
}
finally
{
if (System.IO.File.Exists(dbPath))
{
System.IO.File.Delete(dbPath);
}
}
}

private static void PrintAstNode(AstNode node, int depth)
{
var indent = new string(' ', depth * 2);
var truncatedText = node.Text.Length > 30 ? node.Text.Substring(0, 30) + "..." : node.Text;
truncatedText = truncatedText.Replace("\n", "\\n").Replace("\r", "\\r");

Console.WriteLine($"{indent}{node.NodeType} [{node.StartLine}:{node.StartColumn}-{node.EndLine}:{node.EndColumn}] \"{truncatedText}\"");

foreach (var child in node.Children)
{
PrintAstNode(child, depth + 1);
}
}
}
}

// Extension method to provide Take functionality
public static class EnumerableExtensions
{
public static System.Collections.Generic.IEnumerable<T> Take<T>(this System.Collections.Generic.IEnumerable<T> source, int count)
{
var enumerator = source.GetEnumerator();
int current = 0;
while (current < count && enumerator.MoveNext())
{
yield return enumerator.Current;
current++;
}
}
}
21 changes: 21 additions & 0 deletions csharp/Storage.Tests/Storage.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit" Version="2.6.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="../Storage/Storage.csproj" />
</ItemGroup>

</Project>
Loading
Loading