From 56651f955f6866d24bddbfbbedc680ae71873b72 Mon Sep 17 00:00:00 2001 From: Mate Dabis Date: Tue, 19 Feb 2019 12:25:02 +0100 Subject: [PATCH] Increase branch coverage: Array.prototype functions Added new test cases to improve branch coverage in Array.prototype routines. The following script is made for testing branch coverage with all the test suites (--jerry-test-suite --test262 --unittests --jerry-tests), or with only one .js file. https://github.com/matedabis/jerryscript/blob/gcov_coverage_tester/tests/gcov-tests/gcovtester.py While measuring the branch coverage we dont count JERRY_ASSERT s. The results are measured by running all the test scripts, with the modifications in the PRs. Branch coverage including pando-project#2682 and pando-project#2674: -before: 399 / 476 -after: 472 / 476 There are 28 functions in ecma-builtin-array-prototype.c, we hit 14 from them. The other 14 functions are either already covered, or we could not improve the coverage of it. More information about the coverage improvement and the branches not reached: https://gist.github.com/matedabis/d7b9fc0690aa2f4be6aa160fdf482e0e While improving the coverage we found an unnecessary condition check, which can not be false in any cases. Co-authored-by: Csaba Repasi repasics@inf.u-szeged.hu JerryScript-DCO-1.0-Signed-off-by: Csaba Repasi repasics@inf.u-szeged.hu JerryScript-DCO-1.0-Signed-off-by: Mate Dabis mdabis@inf.u-szeged.hu --- .../ecma-builtin-array-prototype.c | 5 +- tests/jerry/array-prototype-concat.js | 14 ++ tests/jerry/array-prototype-join.js | 13 ++ tests/jerry/array-prototype-pop.js | 24 +++ tests/jerry/array-prototype-push.js | 12 ++ tests/jerry/array-prototype-reverse.js | 74 +++++++ tests/jerry/array-prototype-shift.js | 58 ++++++ tests/jerry/array-prototype-slice.js | 41 ++++ tests/jerry/array-prototype-sort.js | 92 +++++++++ tests/jerry/array-prototype-splice.js | 184 ++++++++++++++++++ tests/jerry/array-prototype-unshift.js | 22 +++ tests/jerry/es2015/array-prototype-find.js | 11 ++ 12 files changed, 548 insertions(+), 2 deletions(-) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c index fd863f1b73..530b7e5dac 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c @@ -579,7 +579,7 @@ ecma_builtin_array_prototype_object_reverse (ecma_value_t this_arg, /**< this ar ECMA_FINALIZE (put_value); } /* 6.j */ - else if (lower_exist && !upper_exist) + else if (lower_exist) { ECMA_TRY_CATCH (del_value, ecma_op_object_delete (obj_p, lower_str_p, true), ret_value); ECMA_TRY_CATCH (put_value, ecma_op_object_put (obj_p, upper_str_p, lower_value, true), ret_value); @@ -1224,8 +1224,9 @@ ecma_builtin_array_prototype_object_splice (const ecma_value_t args[], /**< argu } } /* 13. */ - else if (item_count > delete_count) + else { + JERRY_ASSERT (item_count > delete_count); /* 13.b */ for (k = len - delete_count; k > start && ecma_is_value_empty (ret_value); k--) { diff --git a/tests/jerry/array-prototype-concat.js b/tests/jerry/array-prototype-concat.js index dc1f37889d..a0d26545f8 100644 --- a/tests/jerry/array-prototype-concat.js +++ b/tests/jerry/array-prototype-concat.js @@ -74,3 +74,17 @@ try { assert(e.message === "foo"); assert(e instanceof ReferenceError); } + +/* ES v5.1 15.4.4.4.5. + Checking behavior when unable to get element from a given array */ +arr1 = []; +arr2 = []; +arr3 = []; +Object.defineProperty(arr2, '0', { 'get' : function () {throw new ReferenceError ("foo"); } }); + +try { + arr1.concat(arr2, arr3); + assert(false); +} catch (e) { + assert(e instanceof ReferenceError); +} diff --git a/tests/jerry/array-prototype-join.js b/tests/jerry/array-prototype-join.js index 96233d0e72..2629732f75 100644 --- a/tests/jerry/array-prototype-join.js +++ b/tests/jerry/array-prototype-join.js @@ -74,3 +74,16 @@ obj_2[3] = 4; obj_2.join = Array.prototype.join; assert (obj_2.join() === "1,2,3"); + +/* ES v5.1 15.4.4.5.7. + Checking behavior when an element throws error */ +try { + var f = function () { throw new TypeError("ooo");}; + var arr = [0, 1, 2, 3]; + Object.defineProperty(arr, '0', { 'get' : f }); + Array.prototype.join.call(arr); + assert(false); +} catch (e) { + assert(e instanceof TypeError); + assert(e.message == "ooo"); +} diff --git a/tests/jerry/array-prototype-pop.js b/tests/jerry/array-prototype-pop.js index 0d58dcba50..dab96c06db 100644 --- a/tests/jerry/array-prototype-pop.js +++ b/tests/jerry/array-prototype-pop.js @@ -72,3 +72,27 @@ try { assert(e.message === "foo"); assert(e instanceof ReferenceError); } + +/* ES v5.1 15.4.4.6.5.c + Checking behavior when unable to delete property */ +var obj = {pop : Array.prototype.pop, length : 2}; +Object.defineProperty(obj, '1', function () {}); + +try { + obj.pop(); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +/* ES v5.1 15.4.4.6.5.d + Checking behavior when array is not modifiable */ +var obj = {pop : Array.prototype.pop, length : 2}; +Object.freeze(obj); + +try { + obj.pop(); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/array-prototype-push.js b/tests/jerry/array-prototype-push.js index 84a55e9bfb..3c83838aca 100644 --- a/tests/jerry/array-prototype-push.js +++ b/tests/jerry/array-prototype-push.js @@ -74,3 +74,15 @@ try { } assert(o.length === 1); assert(o[0] === "z"); + +/* ES v5.1 15.4.4.7.5. + Checking behavior when array is non-extensible while pushing */ +var arr = []; +Object.freeze(arr); + +try { + arr.push(1, 2); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/array-prototype-reverse.js b/tests/jerry/array-prototype-reverse.js index 69be5af418..0434a55f2b 100644 --- a/tests/jerry/array-prototype-reverse.js +++ b/tests/jerry/array-prototype-reverse.js @@ -43,3 +43,77 @@ try { assert(e.message === "foo"); assert(e instanceof ReferenceError); } + +/* ES v5.1 15.4.4.8.6.e. + Checking behavior when unable to get the last element */ +var obj = { reverse : Array.prototype.reverse, length : 4 }; +Object.defineProperty(obj, '3', { 'get' : function () {throw new ReferenceError ("foo"); } }); + +try { + obj.reverse(); + assert(false); +} catch (e) { + assert(e.message === "foo"); + assert(e instanceof ReferenceError); +} + +/* ES v5.1 15.4.4.8.6.h.i. + Checking behavior when first 3 elements are not writable */ +try { + var arr = [,,, 3, 4, 5, 6,,,,,,,,,0, 1, 2, 3, 4, 5, 6]; + Object.defineProperty(arr, '0', {}); + Object.defineProperty(arr, '1', {}); + Object.defineProperty(arr, '2', {}); + Array.prototype.reverse.call(arr); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +/* ES v5.1 15.4.4.8.6.h.ii. + Checking behavior when last 3 elements are not writable */ +try { + var arr = [0, 1, 2, 3, 4, 5, 6,,,,,,,,,0, 1, 2, 3,,,]; + Object.defineProperty(arr, '19', {}); + Object.defineProperty(arr, '20', {}); + Object.defineProperty(arr, '21', {}); + Array.prototype.reverse.call(arr); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +/* ES v5.1 15.4.4.8.6.i.i. + Checking behavior when first elements do not exist and the array is freezed */ +try { + var arr = [,,,,,,,,,,,,,,,,0, 1, 2, 3, 4, 5, 6]; + arr = Object.freeze(arr); + Array.prototype.reverse.call(arr); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +/* ES v5.1 15.4.4.8.6.i.ii. + Checking behavior when unable to get the first 2 elements */ +var obj = { reverse : Array.prototype.reverse, length : 4 }; +Object.defineProperty(obj, '2', { value : 0 }); +Object.defineProperty(obj, '3', { value : 0 }); +try { + obj.reverse(); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +/* ES v5.1 15.4.4.8.6.j.i. + Checking behavior when unable to get the last 2 elements */ +var obj = { reverse : Array.prototype.reverse, length : 4 }; +Object.defineProperty(obj, '0', { value : 0 }); +Object.defineProperty(obj, '1', { value : 0 }); +try { + obj.reverse(); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/array-prototype-shift.js b/tests/jerry/array-prototype-shift.js index 843c17c943..a188f2ffbb 100644 --- a/tests/jerry/array-prototype-shift.js +++ b/tests/jerry/array-prototype-shift.js @@ -77,3 +77,61 @@ try { assert(e.message === "foo"); assert(e instanceof ReferenceError); } + +/* ES v5.1 15.4.4.9.7.c. + Checking behavior when the array is freezed */ +try { + f = function () { throw new ReferenceError("getter"); }; + arr = { length : 9 }; + Object.defineProperty(arr, '8', { 'get' : f }); + Array.prototype.shift.call(arr); + assert(false); +} catch (e) { + assert(e instanceof ReferenceError); + assert(e.message == "getter"); +} + +/* ES v5.1 15.4.4.9.7.d.ii. + Checking behavior when the array is freezed */ +try { + arr = { length : 9 }; + Object.defineProperty(arr, '8', { value : 8 }); + Object.defineProperty(arr, '7', { value : 7 }); + Array.prototype.shift.call(arr); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +/* ES v5.1 15.4.4.9.7.e.i. + Checking behavior when the first element is null */ +try { + arr = { length : 9 }; + Object.defineProperty(arr, '0', { value : null }); + Array.prototype.shift.call(arr); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +/* ES v5.1 15.4.4.9.8. + Checking behavior when last element is not writable */ +try { + arr = { length : 9 }; + Object.defineProperty(arr, '8', { writable : false }); + Array.prototype.shift.call(arr); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +/* ES v5.1 15.4.4.9.9. + Checking behavior when the array is freezed */ +try { + arr = { length : 9 }; + Object.freeze(arr); + Array.prototype.shift.call(arr); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/array-prototype-slice.js b/tests/jerry/array-prototype-slice.js index bb1a2e800b..1ba2f9fc5a 100644 --- a/tests/jerry/array-prototype-slice.js +++ b/tests/jerry/array-prototype-slice.js @@ -110,3 +110,44 @@ try { assert (e.message === "foo"); assert (e instanceof ReferenceError); } + +/* ES v5.1 15.4.4.10.5. + Checking behavior when start value throws exception */ +var arg1 = { }; +Object.defineProperty(arg1, 'valueOf', { 'get' : function () { throw new ReferenceError ("foo"); } }); +var obj = { slice : Array.prototype.slice }; + +try { + obj.slice(arg1); + assert(false); +} catch (e) { + assert(e.message === 'foo'); + assert(e instanceof ReferenceError); +} + +/* ES v5.1 15.4.4.10.7. + Checking behavior when end value throws exception */ +var arg2 = { }; +Object.defineProperty(arg2, 'valueOf', { 'get' : function () { throw new ReferenceError ("foo"); } }); +var obj = { slice : Array.prototype.slice }; + +try { + obj.slice(0, arg2); + assert(false); +} catch (e) { + assert(e.message === 'foo'); + assert(e instanceof ReferenceError); +} + +/* ES v5.1 15.4.4.10.10. + Checking behavior when unable to get element */ +var obj = { length : 3, slice : Array.prototype.slice }; +Object.defineProperty(obj, '1', { 'get' : function () { throw new ReferenceError ("foo"); } }); + +try { + obj.slice(0, 3); + assert (false); +} catch (e) { + assert (e.message === "foo"); + assert (e instanceof ReferenceError); +} diff --git a/tests/jerry/array-prototype-sort.js b/tests/jerry/array-prototype-sort.js index 22b9d4ecff..a036e18d18 100644 --- a/tests/jerry/array-prototype-sort.js +++ b/tests/jerry/array-prototype-sort.js @@ -92,3 +92,95 @@ try { assert(e.message === "foo"); assert(e instanceof ReferenceError); } + +// Checking behavior when unable to get elements +var obj = { sort : Array.prototype.sort, length : 2}; +Object.defineProperty(obj, '0', { 'get' : function () { throw new ReferenceError ("foo"); } }); +Object.defineProperty(obj, '1', { 'get' : function () { throw new ReferenceError ("bar"); } }); + +try { + obj.sort(); + assert(false); +} catch (e) { + assert(e.message === "foo"); + assert(e instanceof ReferenceError); +} + +// Checking behavior when array is non-extensible while sorting +var arr = [1, 0]; + +try { + arr.sort(function () { Object.freeze(arr) }); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +// Checking behavior when unable to delete property +var obj = {sort : Array.prototype.sort, '0' : 2, '1' : 1, length : 4}; +Object.defineProperty(obj, '3', function () {}); + +try { + obj.sort(); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +// Checking behavior when unable to get the last element +var arr = [1, 2, ]; +Object.defineProperty(arr, '2', { 'get' : function () { throw new ReferenceError ("foo"); } }); + +try { + arr.sort(); + assert(false); +} catch (e) { + assert(e.message === 'foo'); + assert(e instanceof ReferenceError); +} + +// Checking behavior when lhs_value throws exception at comparefn +f = function () { throw new ReferenceError('foo'); }; +obj = { 'toString' : f }; +arr = [obj, 1]; + +try { + arr.sort(); + assert(false); +} catch (e) { + assert(e.message === 'foo'); + assert(e instanceof ReferenceError); +} + +// Checking behavior when rhs_value throws exception at comparefn +f = function () { throw new ReferenceError('foo'); }; +obj = { 'toString' : f }; +arr = [1, obj]; + +try { + arr.sort(); + assert(false); +} catch (e) { + assert(e.message === 'foo'); + assert(e instanceof ReferenceError); +} + +// Sorting when array elements are the same string +arr = ['foo', 'foo']; +arr.sort(); + +assert(arr[0] === 'foo'); +assert(arr[1] === 'foo'); + +// Checking behavior when comparefn's call value cannot be converted to number +obj = { }; +Object.defineProperty(obj, 'toString', function () { }); +f = function () { return obj }; +arr = [1, 2]; + +try { + arr.sort(f); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/array-prototype-splice.js b/tests/jerry/array-prototype-splice.js index c5c01ab505..d64119ed31 100644 --- a/tests/jerry/array-prototype-splice.js +++ b/tests/jerry/array-prototype-splice.js @@ -175,3 +175,187 @@ try { assert (e.message === "foo"); assert (e instanceof ReferenceError); } + +/* ES v5.1 15.4.4.12.5. + Checking behavior when the first argument of the function is an object, which throws error */ +try { + var o = {}; + Object.defineProperty(o, 'toString', { 'get' : function() { throw new ReferenceError("1"); } }); + [1, 2].splice(o); + assert(false); +} catch (e) { + assert(e instanceof ReferenceError); + assert(e.message == "1"); +} + +/* ES v5.1 15.4.4.12.7. + Checking behavior when the second argument of the function is an object, which throws error */ +try { + var o = {}; + Object.defineProperty(o, 'toString', { 'get' : function() { throw new ReferenceError("2"); } }); + [1, 2].splice(1, o); + assert(false); +} catch (e) { + assert(e instanceof ReferenceError); + assert(e.message == "2"); +} + +/* ES v5.1 15.4.4.12.9.b + Checking behavior when the first element throws error */ +try { + var a = [1, 5, 6, 7, 8, 5]; + Object.defineProperty(a, '0', { 'get' : function() { throw new ReferenceError("foo0"); } }); + Array.prototype.splice.call(a, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3); + assert(false); +} catch (e) { + assert(e instanceof ReferenceError); + assert(e.message == "foo0"); +} + +/* ES v5.1 15.4.4.12.12.b.iii. + Checking behavior when an element of the array throws error */ +function f0() { throw new TypeError("4"); }; + +try { + obj = {get: f0, valueOf : f0, toString: f0}; + arr = [1, 2, obj, 4, 5]; + Object.defineProperty(arr, '4', { 'get' : f0 }); + arr.splice(1, 3, obj); + assert(false); +} catch (e) { + assert(e instanceof TypeError); + assert(e.message == "4"); +} + +/* ES v5.1 15.4.4.12 12.b.iv. + Checking behavior when a modified object is an element of the array */ +function f() { + delete arr[3]; + arr.length = 13; + Object.defineProperty(arr, '5', function() { }); +}; + +try { + obj = {get: f, valueOf : f, toString: f}; + arr = [1, 2, obj, 4, 5]; + Object.defineProperty(arr, '2',{ 'get' : f } ); + for(var i = 0; i < arr.length; i++) { + var a = arr[i]; + } + arr.splice(1, 4, obj); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +/* ES v5.1 15.4.4.12.12.b.v. + Checking behavior when elements are getting deleted by an element which only has a get function */ +function f1() { + for(var i = 0; i < arr.length; i++) { + delete arr[i]; + } +}; + +try{ + arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + delete arr[2]; + Object.defineProperty(arr, '2', { 'get' : f1 }); + arr.splice(1, 7, 5); +} catch (e) { + assert(e instanceof TypeError); +} + +/* ES v5.1 15.4.4.12.12.d.i. + Checking behavior when a modified object is an element of the array and deletes the elements */ +function f2() { + for(var i = 0; i < arr.length; i++) { + delete arr[i]; + } +}; + +try { + obj = {get: f2, valueOf : f2, toString: f2 }; + arr = [1, 2, obj, 4, 5]; + for(var i = 0; i < 6; i++) { + Object.defineProperty(arr, i, { 'get' : f2 }); + } + arr.splice(1, 3, obj); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +/* ES v5.1 15.4.4.12.13.b.iii. + Checking behavior when a yet non existing element will throw an error */ +function f3() { throw new TypeError("6");}; + +try { + arr = [1, 2, 4, 5]; + Object.defineProperty(arr, '4',{ 'get' : f3 }); + arr.splice(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + assert(false); +} catch (e) { + assert(e instanceof TypeError); + assert(e.message == "6"); +} + +/* ES v5.1 15.4.4.12.13.b.iv.2. + Checking behavior when the last element gets deleted */ +function f4() { delete arr[23]; }; + +try { + arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]; + delete arr[23]; + Object.defineProperty(arr, '23', { 'get' : f4 }); + arr.splice(1, 7, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +/* ES v5.1 15.4.4.12.13.b.v.1. + Checking behavior when the last element throws error */ +function f5() { + for(var i = 0; i < arr.length; i++) { + delete arr[i]; + } +}; + +try { + arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]; + delete arr[23]; + Object.defineProperty(arr, '23', { 'get' : f5 }); + arr.splice(1, 7, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +/* ES v5.1 15.4.4.12.15.b. + Checking behavior when the issue is the same as above, but splice has more arguments */ +function f6() { + for(var i = 0; i < arr.length; i++) { + delete arr[i]; + } +}; + +try { + arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + delete arr[2]; + Object.defineProperty(arr, '2', { 'get' : f6 }); + arr.splice(1, 7, 5, 5, 5, 5); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +/* ES v5.1 15.4.4.12.16. + Checking behavior when the array is empty, large, and not writable */ +try { + arr = []; + Object.defineProperty(arr, 'length', { value : 999, writable: false }); + arr.splice(1, 2, 4, 5); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/array-prototype-unshift.js b/tests/jerry/array-prototype-unshift.js index a4394d415c..1ba97b7d77 100644 --- a/tests/jerry/array-prototype-unshift.js +++ b/tests/jerry/array-prototype-unshift.js @@ -101,3 +101,25 @@ assert(obj[0] === "baz"); assert(obj[1] === "foo"); assert(obj[2] === undefined); assert(obj[3] === "bar"); + +/* ES v5.1 15.4.4.13.6.d.ii. + Checking behavior when the array is freezed */ +try { + var arr = [0, 1]; + Object.freeze(arr); + Array.prototype.unshift.call(arr, 2, 3); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +/* ES v5.1 15.4.4.13.6.e.i. + Checking behavior when the array has only one property and bigger length */ +try { + var arr = { length : 9 }; + Object.defineProperty(arr, '6', { value : 2 }); + Array.prototype.unshift.call(arr, 2, 3); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/array-prototype-find.js b/tests/jerry/es2015/array-prototype-find.js index c238cc4ebd..a034c56da0 100644 --- a/tests/jerry/es2015/array-prototype-find.js +++ b/tests/jerry/es2015/array-prototype-find.js @@ -135,3 +135,14 @@ try { // Checking behavior when the there are more than 2 arguments assert (array.find (function (e) { return e < 2 }, {}, 8, 4, 5, 6, 6) === 1); + +function func (element) { + return element > 8; +} + +/* ES v6.0 22.1.3.8.8.c + Checking behavior when the first element deletes the second */ +function f() { delete arr[1]; }; +var arr = [0, 1, 2, 3]; +Object.defineProperty(arr, '0', { 'get' : f }); +Array.prototype.find.call(arr, func);