Browse Source

Number.toPrecision throws between 26 & 100 (#631)

Marko Lahma 6 years ago
parent
commit
8adbbbcc1c
2 changed files with 72 additions and 3 deletions
  1. 61 0
      Jint.Tests/Runtime/NumberTests.cs
  2. 11 3
      Jint/Native/Number/NumberPrototype.cs

+ 61 - 0
Jint.Tests/Runtime/NumberTests.cs

@@ -0,0 +1,61 @@
+using System;
+using Jint.Runtime;
+using Xunit;
+
+namespace Jint.Tests.Runtime
+{
+    public class NumberTests
+    {
+        private readonly Engine _engine;
+
+        public NumberTests()
+        {
+            _engine = new Engine()
+                    .SetValue("log", new Action<object>(Console.WriteLine))
+                    .SetValue("assert", new Action<bool>(Assert.True))
+                    .SetValue("equal", new Action<object, object>(Assert.Equal));
+        }
+
+        private void RunTest(string source)
+        {
+            _engine.Execute(source);
+        }
+
+        [Theory]
+        [InlineData(1, "3.0e+0")]
+        [InlineData(50, "3.00000000000000000000000000000000000000000000000000e+0")]
+        [InlineData(100, "3.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e+0")]
+        public void ToExponential(int fractionDigits, string result)
+        {
+            var value = _engine.Execute($"(3).toExponential({fractionDigits}).toString()").GetCompletionValue().AsString();
+            Assert.Equal(result, value);
+        }
+
+        [Theory]
+        [InlineData(1, "3.0")]
+        [InlineData(50, "3.00000000000000000000000000000000000000000000000000")]
+        [InlineData(99, "3.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")]
+        public void ToFixed(int fractionDigits, string result)
+        {
+            var value = _engine.Execute($"(3).toFixed({fractionDigits}).toString()").GetCompletionValue().AsString();
+            Assert.Equal(result, value);
+        }
+
+        [Fact]
+        public void ToFixedWith100FractionDigitsThrows()
+        {
+            var ex = Assert.Throws<JavaScriptException>(() => _engine.Execute($"(3).toFixed(100)"));
+            Assert.Equal("100 fraction digits is not supported due to .NET format specifier limitation", ex.Message);
+        }
+
+        [Theory]
+        [InlineData(1, "3")]
+        [InlineData(50, "3.0000000000000000000000000000000000000000000000000")]
+        [InlineData(100, "3.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")]
+        public void ToPrecision(int fractionDigits, string result)
+        {
+            var value = _engine.Execute($"(3).toPrecision({fractionDigits}).toString()").GetCompletionValue().AsString();
+            Assert.Equal(result, value);
+        }
+    }
+}

+ 11 - 3
Jint/Native/Number/NumberPrototype.cs

@@ -106,12 +106,18 @@ namespace Jint.Native.Number
 
         private JsValue ToFixed(JsValue thisObj, JsValue[] arguments)
         {
-            var f = (int)TypeConverter.ToInteger(arguments.At(0, 0));
+            var f = (int) TypeConverter.ToInteger(arguments.At(0, 0));
             if (f < 0 || f > 100)
             {
                 ExceptionHelper.ThrowRangeError(_engine, "fractionDigits argument must be between 0 and 100");
             }
 
+            // limitation with .NET, max is 99
+            if (f == 100)
+            {
+                ExceptionHelper.ThrowRangeError(_engine, "100 fraction digits is not supported due to .NET format specifier limitation");
+            }
+
             var x = TypeConverter.ToNumber(thisObj);
 
             if (double.IsNaN(x))
@@ -180,9 +186,10 @@ namespace Jint.Native.Number
             }
 
             int decimalPoint;
-            var dtoaBuilder = new DtoaBuilder();
+            DtoaBuilder dtoaBuilder;
             if (f == -1)
             {
+                dtoaBuilder = new DtoaBuilder();
                 DtoaNumberFormatter.DoubleToAscii(
                     dtoaBuilder,
                     x,
@@ -194,6 +201,7 @@ namespace Jint.Native.Number
             }
             else
             {
+                dtoaBuilder = new DtoaBuilder(101);
                 DtoaNumberFormatter.DoubleToAscii(
                     dtoaBuilder,
                     x,
@@ -243,7 +251,7 @@ namespace Jint.Native.Number
                 ExceptionHelper.ThrowRangeError(_engine, "precision must be between 1 and 100");
             }
 
-            var dtoaBuilder = new DtoaBuilder();
+            var dtoaBuilder = new DtoaBuilder(101);
             DtoaNumberFormatter.DoubleToAscii(
                 dtoaBuilder,
                 x,