Skip to content

Commit

Permalink
Feature/issue 6 handle type string (#112)
Browse files Browse the repository at this point in the history
* build: remove global.json

* build: remove .netstandard dependency and old msbuild dependencies

* tests: add more tests for coverage

* build: remove unused dependency on Microsoft.CodeAnalysis.CSharp.Workspaces

* refactor: remove SQ complaint

* test: add more tests for better coverage

* feat: add parameterized `ToString` functions for REAL and BOOLEAN

Fixes #111

---------

Co-authored-by: Stephen Reindl <[email protected]>
  • Loading branch information
steven-r and Stephen Reindl authored Nov 19, 2024
1 parent 42b260b commit d793dc6
Show file tree
Hide file tree
Showing 11 changed files with 344 additions and 69 deletions.
70 changes: 70 additions & 0 deletions Oberon0.Generator.MsilBin.Tests/Types/StringTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// --------------------------------------------------------------------------------------------------------------------
#endregion

using System.Globalization;
using System.IO;
using Microsoft.CodeAnalysis.CSharp;
using Xunit;
Expand Down Expand Up @@ -182,4 +183,73 @@ END Test.
Assert.Equal("", output1.ToString());
}

[Theory]
[InlineData(0.0, "0", "G")]
[InlineData(1.0, "1", "G")]
[InlineData(10000000000000.00001, "10000000000000", "G")]
[InlineData(0.1, "0.1", "G")]
[InlineData(2.3E-06, "2.3E-06", "G")]
[InlineData(2.3E06, "2300000", "G")]
[InlineData(double.MinValue, "-1.7976931348623157E+308", "G")]
public void TestToStringRealFormat(double value, string expected, string format)
{
string source = $"""
MODULE Test;
VAR
r: REAL;
s: STRING;
b: INTEGER;
BEGIN
r := {value.ToString(CultureInfo.InvariantCulture)};
s := ToString(r, '{format}');
WriteString(s)
END Test.
""";
var cg = CompileHelper.CompileOberon0Code(source, out string code, output);
Assert.NotEmpty(code);

var syntaxTree = CSharpSyntaxTree.ParseText(code);

byte[] assembly = syntaxTree.CompileAndLoadAssembly(cg, true);
Assert.NotNull(assembly);

using var output1 = new StringWriter();
Runner.Execute(assembly, output1);
Assert.Equal(expected, output1.ToString());
}

[Theory]
[InlineData(false, "false", "true", "false")]
[InlineData(true, "true", "true", "false")]
[InlineData(false, "0", "1", "0")]
[InlineData(true, "1", "1", "0")]
public void TestToStringBooleanFormat(bool value, string expected, string trueVal, string falseVal)
{
string source = $"""
MODULE Test;
VAR
r: BOOLEAN;
s: STRING;
b: INTEGER;
BEGIN
r := {value.ToString().ToUpper()};
s := ToString(r, '{trueVal}', '{falseVal}');
WriteString(s)
END Test.
""";
var cg = CompileHelper.CompileOberon0Code(source, out string code, output);
Assert.NotEmpty(code);

var syntaxTree = CSharpSyntaxTree.ParseText(code);

byte[] assembly = syntaxTree.CompileAndLoadAssembly(cg, true);
Assert.NotNull(assembly);

using var output1 = new StringWriter();
Runner.Execute(assembly, output1);
Assert.Equal(expected, output1.ToString());
}

}
4 changes: 2 additions & 2 deletions Oberon0.Generator.MsilBin/CreateBinary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using Oberon0.Compiler.Exceptions;
using Oberon0.Shared;

namespace Oberon0.Generator.MsilBin
Expand Down Expand Up @@ -49,8 +50,7 @@ private static string GetDotnetExe ()

private CreateBinaryOptions SetOptions(CreateBinaryOptions options)
{
// ReSharper disable once UnthrowableException
options.ModuleName ??= _codeGenerator.Module.Name ?? throw new NullReferenceException("Name needs to be set");
options.ModuleName ??= _codeGenerator.Module.Name ?? throw new InternalCompilerException("Name needs to be set");
options.SolutionPath ??= BuildOutputPath(options);
options.OutputPath ??= Environment.CurrentDirectory;
return options;
Expand Down
1 change: 0 additions & 1 deletion Oberon0.Generator.MsilBin/Oberon0.Generator.MsilBin.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
<PackageReference Include="AnyClone" Version="1.1.6" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.11.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.11.0" />
</ItemGroup>

<ItemGroup>
Expand Down
33 changes: 33 additions & 0 deletions Oberon0.System.Tests/Oberon0.System.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Oberon0.System\Oberon0.System.csproj" />
</ItemGroup>

<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>

</Project>
20 changes: 20 additions & 0 deletions Oberon0.System.Tests/Oberon0System.MathTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace Oberon0.System.Tests;

using Oberon0System;
using Xunit;

public static partial class Oberon0SystemTests
{
[Theory]
[InlineData(0.0, false)]
[InlineData(double.NegativeInfinity, true)]
[InlineData(double.PositiveInfinity, true)]
public static void CanCallIsInfinity(double value, bool expected)
{
// Act
bool result = Oberon0System.IsInfinity(value);

// Assert
Assert.Equal(expected, result);
}
}
77 changes: 77 additions & 0 deletions Oberon0.System.Tests/Oberon0System.StringsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System.Globalization;

namespace Oberon0.System.Tests;

using Oberon0System;
using Xunit;

public static partial class Oberon0SystemTests
{
[Theory]
[InlineData(0)]
[InlineData(int.MaxValue)]
[InlineData(int.MinValue)]
[InlineData(5274097)]
[InlineData(-771204301)]
public static void CanCallConvertToStringWithInt(int value)
{
// Act
string result = Oberon0System.ConvertToString(value);

// Assert
Assert.Equal(value.ToString(), result);
}

[Theory]
[InlineData(0.0)]
[InlineData(1.0)]
[InlineData(double.MinValue)]
[InlineData(5274097.9283)]
[InlineData(-771204301.211)]
public static void CanCallConvertToStringWithReal(double value)
{
// Act
string result = Oberon0System.ConvertToString(value);

// Assert
Assert.Equal(value.ToString(CultureInfo.InvariantCulture), result);
}

[Theory]
[InlineData(false)]
[InlineData(true)]
public static void CanCallConvertToStringWithBoolean(bool value)
{
// Act
string result = Oberon0System.ConvertToString(value);

// Assert
Assert.Equal(value.ToString(), result);
}


[Theory]
[InlineData(0.0, "0", "G")]
[InlineData(1.0, "1", "G")]
[InlineData(10000000000000.00001, "10000000000000", "G")]
[InlineData(0.1, "0.1", "G")]
[InlineData(2.3E-06, "2.3E-06", "G")]
[InlineData(2.3E06, "2300000", "G")]
[InlineData(double.MinValue, "-1.7976931348623157E+308", "G")]
public static void TestToStringRealFormat(double value, string expected, string format)
{
string result = Oberon0System.ConvertToString(value, format);
Assert.Equal(expected, result);
}

[Theory]
[InlineData(false, "false", "true", "false")]
[InlineData(true, "true", "true", "false")]
[InlineData(false, "0", "1", "0")]
[InlineData(true, "1", "1", "0")]
public static void TestToStringBooleanFormat(bool value, string expected, string trueVal, string falseVal)
{
string result = Oberon0System.ConvertToString(value, trueVal, falseVal);
Assert.Equal(expected, result);
}
}
126 changes: 76 additions & 50 deletions Oberon0.System/Oberon0System.Strings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,56 +8,82 @@
using System.Globalization;
using Oberon0System.Attributes;

namespace Oberon0System
namespace Oberon0System;

public static partial class Oberon0System
{
public static partial class Oberon0System
/// <summary>
/// Convert INTEGER to STRING.
/// </summary>
/// <param name="value">the value to convert</param>
/// <returns>the converted string</returns>
[Oberon0Export("ToString", "STRING", "INTEGER")]
// ReSharper disable once UnusedMember.Global
public static string ConvertToString(int value)
{
return value.ToString(CultureInfo.InvariantCulture);
}

/// <summary>
/// Convert REAL to STRING.
/// </summary>
/// <param name="value">the value to convert</param>
/// <returns>the converted string</returns>
[Oberon0Export("ToString", "STRING", "REAL")]
// ReSharper disable once UnusedMember.Global
public static string ConvertToString(double value)
{
return value.ToString(CultureInfo.InvariantCulture);
}

/// <summary>
/// Convert BOOLEAN to STRING.
/// </summary>
/// <param name="value">the value to convert</param>
/// <returns>the converted string</returns>
[Oberon0Export("ToString", "STRING", "BOOLEAN")]
// ReSharper disable once UnusedMember.Global
public static string ConvertToString(bool value)
{
return value.ToString(CultureInfo.InvariantCulture);
}

/// <summary>
/// Convert REAL to STRING.
/// </summary>
/// <param name="value">the value to convert</param>
/// <param name="format">The format according to https://learn.microsoft.com/en-us/dotnet/api/system.double.tostring?view=net-8.0</param>
/// <returns>the converted string</returns>
[Oberon0Export("ToString", "STRING", "REAL", "STRING")]
// ReSharper disable once UnusedMember.Global
public static string ConvertToString(double value, string format)
{
return value.ToString(format, CultureInfo.InvariantCulture);
}

/// <summary>
/// Convert REAL to STRING.
/// </summary>
/// <param name="value">the value to convert</param>
/// <param name="trueValue">value to be returned if <c>value</c> is true</param>
/// <param name="falseValue">value to be returned if <c>value</c> is false</param>
/// <returns>the converted string</returns>
[Oberon0Export("ToString", "STRING", "BOOLEAN", "STRING", "STRING")]
// ReSharper disable once UnusedMember.Global
public static string ConvertToString(bool value, string trueValue, string falseValue)
{
return value ? trueValue : falseValue;
}

/// <summary>
/// Get string length
/// </summary>
/// <param name="value">the value to convert</param>
/// <returns>the converted string</returns>
[Oberon0Export("Length", "INTEGER", "STRING")]
// ReSharper disable once UnusedMember.Global
public static int Length(string value)
{
/// <summary>
/// Convert INTEGER to STRING.
/// </summary>
/// <param name="value">the value to convert</param>
/// <returns>the converted string</returns>
[Oberon0Export("ToString", "STRING", "INTEGER")]
// ReSharper disable once UnusedMember.Global
public static string ConvertToString(int value)
{
return value.ToString(CultureInfo.InvariantCulture);
}

/// <summary>
/// Convert REAL to STRING.
/// </summary>
/// <param name="value">the value to convert</param>
/// <returns>the converted string</returns>
[Oberon0Export("ToString", "STRING", "REAL")]
// ReSharper disable once UnusedMember.Global
public static string ConvertToString(double value)
{
return value.ToString(CultureInfo.InvariantCulture);
}

/// <summary>
/// Convert BOOLEAN to STRING.
/// </summary>
/// <param name="value">the value to convert</param>
/// <returns>the converted string</returns>
[Oberon0Export("ToString", "STRING", "BOOLEAN")]
// ReSharper disable once UnusedMember.Global
public static string ConvertToString(bool value)
{
return value.ToString(CultureInfo.InvariantCulture);
}

/// <summary>
/// Get string length
/// </summary>
/// <param name="value">the value to convert</param>
/// <returns>the converted string</returns>
[Oberon0Export("Length", "INTEGER", "STRING")]
// ReSharper disable once UnusedMember.Global
public static int Length(string value)
{
return value.Length;
}
return value.Length;
}
}
}
Loading

0 comments on commit d793dc6

Please sign in to comment.