Skip to content

Commit

Permalink
Implementing string.startsWith
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastienros committed Dec 13, 2017
1 parent 2f8bc2b commit 0281b6a
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 0 deletions.
44 changes: 44 additions & 0 deletions Jint.Tests/Runtime/EngineTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2172,6 +2172,50 @@ public void ShouldPadEnd(string source, object expected)

Assert.Equal(expected, result);
}

/// <summary>
/// Tests for startsWith - tests created from MDN and https://github.com/mathiasbynens/String.prototype.startsWith/blob/master/tests/tests.js
/// </summary>
[Theory]
[InlineData("'To be, or not to be, that is the question.'.startsWith('To be')", true)]
[InlineData("'To be, or not to be, that is the question.'.startsWith('not to be')", false)]
[InlineData("'To be, or not to be, that is the question.'.startsWith()", false)]
[InlineData("'To be, or not to be, that is the question.'.startsWith('not to be', 10)", true)]
[InlineData("'undefined'.startsWith()", true)]
[InlineData("'undefined'.startsWith(undefined)", true)]
[InlineData("'undefined'.startsWith(null)", false)]
[InlineData("'null'.startsWith()", false)]
[InlineData("'null'.startsWith(undefined)", false)]
[InlineData("'null'.startsWith(null)", true)]
[InlineData("'abc'.startsWith()", false)]
[InlineData("'abc'.startsWith('')", true)]
[InlineData("'abc'.startsWith('\0')", false)]
[InlineData("'abc'.startsWith('a')", true)]
[InlineData("'abc'.startsWith('b')", false)]
[InlineData("'abc'.startsWith('ab')", true)]
[InlineData("'abc'.startsWith('bc')", false)]
[InlineData("'abc'.startsWith('abc')", true)]
[InlineData("'abc'.startsWith('bcd')", false)]
[InlineData("'abc'.startsWith('abcd')", false)]
[InlineData("'abc'.startsWith('bcde')", false)]
[InlineData("'abc'.startsWith('', 1)", true)]
[InlineData("'abc'.startsWith('\0', 1)", false)]
[InlineData("'abc'.startsWith('a', 1)", false)]
[InlineData("'abc'.startsWith('b', 1)", true)]
[InlineData("'abc'.startsWith('ab', 1)", false)]
[InlineData("'abc'.startsWith('bc', 1)", true)]
[InlineData("'abc'.startsWith('abc', 1)", false)]
[InlineData("'abc'.startsWith('bcd', 1)", false)]
[InlineData("'abc'.startsWith('abcd', 1)", false)]
[InlineData("'abc'.startsWith('bcde', 1)", false)]
public void ShouldStartWith(string source, object expected)
{
var engine = new Engine();
var result = engine.Execute(source).GetCompletionValue().ToObject();

Assert.Equal(expected, result);
}

[Theory]
[InlineData("throw {}", "undefined")]
[InlineData("throw {message:null}","null")]
Expand Down
49 changes: 49 additions & 0 deletions Jint/Native/String/StringPrototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public void Configure()
FastAddProperty("charCodeAt", new ClrFunctionInstance(Engine, CharCodeAt, 1), true, false, true);
FastAddProperty("concat", new ClrFunctionInstance(Engine, Concat, 1), true, false, true);
FastAddProperty("indexOf", new ClrFunctionInstance(Engine, IndexOf, 1), true, false, true);
FastAddProperty("startsWith", new ClrFunctionInstance(Engine, StartsWith, 1), true, false, true);
FastAddProperty("lastIndexOf", new ClrFunctionInstance(Engine, LastIndexOf, 1), true, false, true);
FastAddProperty("localeCompare", new ClrFunctionInstance(Engine, LocaleCompare, 1), true, false, true);
FastAddProperty("match", new ClrFunctionInstance(Engine, Match, 1), true, false, true);
Expand Down Expand Up @@ -793,5 +794,53 @@ private JsValue Pad(JsValue thisObj, JsValue[] arguments, bool padStart)

return padStart ? $"{padString.Substring(0, targetLength)}{s}" : $"{s}{padString.Substring(0, targetLength)}";
}

/// <summary>
/// https://www.ecma-international.org/ecma-262/6.0/#sec-string.prototype.startswith
/// </summary>
/// <param name="thisObj"></param>
/// <param name="arguments"></param>
/// <returns></returns>
private JsValue StartsWith(JsValue thisObj, JsValue[] arguments)
{
TypeConverter.CheckObjectCoercible(Engine, thisObj);

var s = TypeConverter.ToString(thisObj);

var searchString = arguments.At(0);
if (searchString == Null.Instance)
{
searchString = Null.Text;
}
else
{
if (searchString.IsRegExp())
{
throw new JavaScriptException(Engine.TypeError);
}
}

var searchStr = TypeConverter.ToString(searchString);

var pos = TypeConverter.ToInt32(arguments.At(1));

var len = s.Length;
var start = System.Math.Min(System.Math.Max(pos, 0), len);
var searchLength = searchStr.Length;
if (searchLength + start > len)
{
return false;
}

for (var i = 0; i < searchLength; i++)
{
if (s[start + i] != searchStr[i])
{
return false;
}
}

return true;
}
}
}

0 comments on commit 0281b6a

Please sign in to comment.