Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
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
6 changes: 6 additions & 0 deletions src/System.Runtime/ref/System.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2156,6 +2156,7 @@ public String(System.ReadOnlySpan<char> value) { }
public bool Contains(string value, StringComparison comparisonType) { throw null; }
public static System.String Copy(System.String str) { throw null; }
public void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count) { }
public static string Create<TState>(int length, TState state, System.Buffers.SpanAction<char, TState> action) { throw null; }
public bool EndsWith(char value) { throw null; }
public bool EndsWith(string value) { throw null; }
public bool EndsWith(System.String value, bool ignoreCase, System.Globalization.CultureInfo culture) { throw null; }
Expand Down Expand Up @@ -3857,6 +3858,11 @@ public abstract class OwnedMemory<T> : IDisposable, IRetainable
protected internal abstract bool TryGetArray(out ArraySegment<T> arraySegment);
}
}
namespace System.Buffers
{
public delegate void SpanAction<T, in TArg>(Span<T> span, TArg arg);
public delegate void ReadOnlySpanAction<T, in TArg>(ReadOnlySpan<T> span, TArg arg);
}
namespace System.Collections
{
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
Expand Down
58 changes: 58 additions & 0 deletions src/System.Runtime/tests/System/StringTests.netcoreapp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,64 @@ public static void Ctor_CharSpan(char[] valueArray, int startIndex, int length,
Assert.Equal(expected, new string(span));
}

[Fact]
public static void Create_InvalidArguments_Throw()
{
AssertExtensions.Throws<ArgumentNullException>("action", () => string.Create(-1, 0, null));
AssertExtensions.Throws<ArgumentOutOfRangeException>("length", () => string.Create(-1, 0, (span, state) => { }));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not that I expect anything weird to happen, but seeing the empty action here made me wonder if it's worth having a non-zero length with the empty action. (which should just be equal to new string((char)0, length)

Actually, I guess really it's ensuring that we're using cleared memory, since the other tests set every char position we don't have that assurance.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestion, @bartonjs. I added a test for it.

}

[Fact]
public static void Create_Length0_ReturnsEmptyString()
{
bool actionInvoked = false;
Assert.Same(string.Empty, string.Create(0, 0, (span, state) => actionInvoked = true));
Assert.False(actionInvoked);
}

[Fact]
public static void Create_NullState_Allowed()
{
string result = string.Create(1, (object)null, (span, state) =>
{
span[0] = 'a';
Assert.Null(state);
});
Assert.Equal("a", result);
}

[Fact]
public static void Create_ClearsMemory()
{
const int Length = 10;
string result = string.Create(Length, (object)null, (span, state) =>
{
for (int i = 0; i < span.Length; i++)
{
Assert.Equal('\0', span[i]);
}
});
Assert.Equal(new string('\0', Length), result);
}

[Theory]
[InlineData("a")]
[InlineData("this is a test")]
[InlineData("\0\u8001\u8002\ufffd\u1234\ud800\udfff")]
public static void Create_ReturnsExpectedString(string expected)
{
char[] input = expected.ToCharArray();
string result = string.Create(input.Length, input, (span, state) =>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's supposed to happen when action is null?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should throw. I think in my tired stupor I subconsciously saw "span" and thought "that can't be null" :)

{
Assert.Same(input, state);
for (int i = 0; i < state.Length; i++)
{
span[i] = state[i];
}
});
Assert.Equal(expected, result);
}

[Theory]
// CurrentCulture
[InlineData("Hello", "ello", StringComparison.CurrentCulture, true)]
Expand Down