Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Port some methods of the VB Interaction module #39574

Merged
merged 7 commits into from
Jul 20, 2019
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
Original file line number Diff line number Diff line change
Expand Up @@ -481,8 +481,11 @@ public sealed partial class Interaction
internal Interaction() { }
public static void Beep() { }
public static object CallByName(object ObjectRef, string ProcName, CallType UseCallType, params object[] Args) { throw null; }
public static object Choose(double Index, params object[] Choice) { throw null; }
public static object CreateObject(string ProgId, string ServerName = "") { throw null; }
public static object IIf(bool Expression, object TruePart, object FalsePart) { throw null; }
public static string Partition(long Number, long Start, long Stop, long Interval) { throw null; }
public static object Switch(params object[] VarExpr) { throw null; }
}
public enum MsgBoxResult
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
' See the LICENSE file in the project root for more information.

Imports System
Imports System.Text
Imports System.Runtime.InteropServices

Imports Microsoft.VisualBasic.CompilerServices
Expand All @@ -25,6 +26,22 @@ Namespace Microsoft.VisualBasic
#End If
End Sub

'============================================================================
' String functions.
'============================================================================
Public Function Choose(ByVal Index As Double, ByVal ParamArray Choice() As Object) As Object

Dim FixedIndex As Integer = CInt(Fix(Index) - 1) 'ParamArray is 0 based, but Choose assumes 1 based

If Choice.Rank <> 1 Then
Throw New ArgumentException(GetResourceString(SR.Argument_RankEQOne1, "Choice"))
ElseIf FixedIndex < 0 OrElse FixedIndex > Choice.GetUpperBound(0) Then
Return Nothing
End If

Return Choice(FixedIndex)
End Function

Public Function IIf(ByVal Expression As Boolean, ByVal TruePart As Object, ByVal FalsePart As Object) As Object
If Expression Then
Return TruePart
Expand All @@ -41,6 +58,143 @@ Namespace Microsoft.VisualBasic
Return falsePart
End Function

Public Function Partition(ByVal Number As Long, ByVal Start As Long, ByVal [Stop] As Long, ByVal Interval As Long) As String
'CONSIDER: Change to use StringBuilder
Dim Lower As Long
Dim Upper As Long
Dim NoUpper As Boolean
Dim NoLower As Boolean
Dim Buffer As String = Nothing
Dim Buffer1 As String
Dim Buffer2 As String
Dim Spaces As Long

'Validate arguments
If Start < 0 Then
Throw New ArgumentException(GetResourceString(SR.Argument_InvalidValue1, "Start"))
End If

If [Stop] <= Start Then
Throw New ArgumentException(GetResourceString(SR.Argument_InvalidValue1, "Stop"))
End If

If Interval < 1 Then
Throw New ArgumentException(GetResourceString(SR.Argument_InvalidValue1, "Interval"))
End If

'Check for before-first and after-last ranges
If Number < Start Then
Upper = Start - 1
NoLower = True
ElseIf Number > [Stop] Then
Lower = [Stop] + 1
NoUpper = True
ElseIf Interval = 1 Then 'This is a special case
Lower = Number
Upper = Number
Else
'Calculate the upper and lower ranges
'Note the use of Integer division "\" which truncates to whole number
Lower = ((Number - Start) \ Interval) * Interval + Start
Upper = Lower + Interval - 1

'Adjust for first and last ranges
If Upper > [Stop] Then
Upper = [Stop]
End If

If Lower < Start Then
Lower = Start
End If
End If

'Build-up the string. Calculate number of spaces needed: VB3 uses Stop + 1.
'This may seem bogus but it has to be this way for VB3 compatibilty.
Buffer1 = CStr([Stop] + 1)
Buffer2 = CStr(Start - 1)

If Len(Buffer1) > Len(Buffer2) Then
Spaces = Len(Buffer1)
Else
Spaces = Len(Buffer2)
End If

'Handle case where Upper is -1 and Stop < 9
If NoLower Then
Buffer1 = CStr(Upper)
If Spaces < Len(Buffer1) Then
Spaces = Len(Buffer1)
End If
End If

'Insert lower-end of partition range.
If NoLower Then
InsertSpaces(Buffer, Spaces)
Else
InsertNumber(Buffer, Lower, Spaces)
End If

'Insert the partition
Buffer = Buffer & ":"

'Insert upper-end of partition range
If NoUpper Then
InsertSpaces(Buffer, Spaces)
Else
InsertNumber(Buffer, Upper, Spaces)
End If

Return Buffer
End Function

Private Sub InsertSpaces(ByRef Buffer As String, ByVal Spaces As Long)
Do While Spaces > 0 'consider: - use stringbuilder
Buffer = Buffer & " "
Spaces = Spaces - 1
Loop
End Sub

Private Sub InsertNumber(ByRef Buffer As String, ByVal Num As Long, ByVal Spaces As Long)
Dim Buffer1 As String 'consider: - use stringbuilder

'Convert number to a string
Buffer1 = CStr(Num)

'Insert leading spaces
InsertSpaces(Buffer, Spaces - Len(Buffer1))

'Append string
Buffer = Buffer & Buffer1
End Sub

Public Function Switch(ByVal ParamArray VarExpr() As Object) As Object
Dim Elements As Integer
Dim Index As Integer

If VarExpr Is Nothing Then
Return Nothing
End If

Elements = VarExpr.Length
Index = 0

'Ensure we have an even number of arguments (0 based)
If (Elements Mod 2) <> 0 Then
Throw New ArgumentException(GetResourceString(SR.Argument_InvalidValue1, "VarExpr"))
End If

Do While Elements > 0
If CBool(VarExpr(Index)) Then
Return VarExpr(Index + 1)
End If

Index += 2
Elements -= 2
Loop

Return Nothing 'If nothing matched above
End Function

Public Function CreateObject(ByVal ProgId As String, Optional ByVal ServerName As String = "") As Object
'Creates local or remote COM2 objects. Should not be used to create COM+ objects.
'Applications that need to be STA should set STA either on their Sub Main via STAThreadAttribute
Expand Down
80 changes: 80 additions & 0 deletions src/Microsoft.VisualBasic.Core/tests/InteractionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,22 @@ public object this[object index]
}
}


[Fact]
public void Choose()
{
object[] x = { "Choice1", "Choice2", "Choice3", "Choice4", "Choice5", "Choice6" };
Assert.Equal(null, Interaction.Choose(5));
Assert.Equal(null, Interaction.Choose(0, x)); // < 1
Assert.Equal(null, Interaction.Choose(x.Length + 1, x)); // > UpperBound
Assert.Equal(2, Interaction.Choose(2, 1, 2, 3));
Assert.Equal("Choice3", Interaction.Choose(3, x[0], x[1], x[2]));
for (int i = 1; i <= x.Length; i++)
{
Assert.Equal(x[i - 1], Interaction.Choose(i, x));
}
}

[Fact]
public void CreateObject()
{
Expand All @@ -98,5 +114,69 @@ private static IEnumerable<object[]> IIf_TestData()
yield return new object[] { false, 3, "str", "str" };
yield return new object[] { true, 3, "str", 3 };
}

[Theory]
[InlineData(0, 1, 2, 1, " :0")]
[InlineData(1, 1, 2, 1, "1:1")]
[InlineData(2, 1, 2, 1, "2:2")]
[InlineData(3, 1, 2, 1, "3: ")]
ehasis marked this conversation as resolved.
Show resolved Hide resolved
[InlineData(10, 1, 9, 1, "10: ")]
[InlineData(-1, 0, 1, 1, " :-1")]
[InlineData(-50, 0, 1, 1, " :-1")]
[InlineData(0, 1, 100, 10, " : 0")]
[InlineData(1, 1, 100, 10, " 1: 10")]
[InlineData(15, 1, 100, 10, " 11: 20")]
[InlineData(25, 1, 100, 10, " 21: 30")]
[InlineData(35, 1, 100, 10, " 31: 40")]
[InlineData(45, 1, 100, 10, " 41: 50")]
[InlineData(50, 40, 100, 10, " 50: 59")]
[InlineData(120, 100, 200, 10, "120:129")]
[InlineData(150, 100, 120, 10, "121: ")]
[InlineData(5001, 1, 10000, 100, " 5001: 5100")]
[InlineData(1, 0, 1, long.MaxValue, " 0: 1")]
[InlineData(1, 0, long.MaxValue - 1, long.MaxValue, " 0:9223372036854775806")]
[InlineData(long.MaxValue, 0, long.MaxValue - 1, 1, "9223372036854775807: ")]
[InlineData(long.MaxValue - 1, 0, long.MaxValue - 1, 1, "9223372036854775806:9223372036854775806")]
public void Partition(long Number, long Start, long Stop, long Interval, string expected)
ehasis marked this conversation as resolved.
Show resolved Hide resolved
{
Assert.Equal(expected, Interaction.Partition(Number, Start, Stop, Interval));
}

[Theory]
[InlineData(0, -1, 100, 10)] // Start < 0
[InlineData(0, 100, 100, 10)] // Stop <= Start
[InlineData(0, 1, 100, 0)] // Interval < 1
public void Partition_Invalid(long Number, long Start, long Stop, long Interval)
{
Assert.Throws<ArgumentException>(() => Interaction.Partition(Number, Start, Stop, Interval));
}

[Theory]
[InlineData(1, 0, long.MaxValue, 1)] // Stop + 1
[InlineData(1, 0, long.MaxValue, long.MaxValue)]
[InlineData(2, 1, 2, long.MaxValue)] // Lower + Interval
[InlineData(long.MaxValue - 1, long.MaxValue - 1, long.MaxValue, 1)]
public void Partition_Overflow(long Number, long Start, long Stop, long Interval)
{
Assert.Throws<OverflowException>(() => Interaction.Partition(Number, Start, Stop, Interval));
}

[Theory]
[InlineData(null, null)] // empty
ehasis marked this conversation as resolved.
Show resolved Hide resolved
[InlineData(new object[0], null)] // empty
[InlineData(new object[] { false, "red", false, "green", false, "blue" }, null)] // none
[InlineData(new object[] { true, "red", false, "green", false, "blue" }, "red")]
[InlineData(new object[] { false, "red", true, "green", false, "blue" }, "green")]
[InlineData(new object[] { false, "red", false, "green", true, "blue" }, "blue")]
public void Switch(object[] VarExpr, object expected)
{
Assert.Equal(expected, Interaction.Switch(VarExpr));
}

[Fact]
public void Switch_Invalid()
{
Assert.Throws<ArgumentException>(() => Interaction.Switch(true, "a", false));
}
}
}