From 4d60a6a3c8c2bc224c4975bd607cfc26e7be9147 Mon Sep 17 00:00:00 2001
From: Christoph Diehl <1614333+posidron@users.noreply.github.com>
Date: Thu, 22 Mar 2018 18:36:59 +0100
Subject: [PATCH 1/9] Update README.md
---
README.md | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/README.md b/README.md
index 2093525..3c07d26 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,11 @@ Octo.js bundles core functions and generic boilerplate code commonly used in mos
Octo's future aims to be a stable, well-tested and well-documented standard library for fuzzing in a JavaScript environment.
+# NOTE
+The ES6 branch is under active development while we are incorporating it into our existing fuzzers.
+This branch is current not maintained.
+
+
## Usage
```html
From 9807668e3e7dea2002a98683c9572f23b865a7b3 Mon Sep 17 00:00:00 2001
From: pyoor
Date: Wed, 28 Mar 2018 13:26:28 -0400
Subject: [PATCH 2/9] Add support for wrapping arrays elements in try/catch
---
lib/utils/script.js | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/lib/utils/script.js b/lib/utils/script.js
index f245d5d..4070d3d 100644
--- a/lib/utils/script.js
+++ b/lib/utils/script.js
@@ -58,8 +58,12 @@ utils.script = {
}
return JSON.stringify(o)
},
- safely: function (s) {
- return 'try { ' + s + ' } catch(e) { }'
+ safely: function (obj) {
+ if (Array.isArray(obj)) {
+ return obj.map(s => utils.script.safely(s)).join(' ')
+ } else {
+ return `try { ${obj} } catch(e) { }`
+ }
},
makeLoop: function (s, max) {
return 'for (let i = 0; i < ' + (max || make.number.range()) + '; i++) {' + s + '}'
From f8c8f7037ed81a864ad81e6ad15dc1073fd836cf Mon Sep 17 00:00:00 2001
From: Christoph Diehl <1614333+posidron@users.noreply.github.com>
Date: Wed, 11 Apr 2018 20:36:29 +0200
Subject: [PATCH 3/9] Backport WebGL additions from Node
---
lib/make/webgl.js | 187 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 187 insertions(+)
diff --git a/lib/make/webgl.js b/lib/make/webgl.js
index db6f384..aef2a66 100644
--- a/lib/make/webgl.js
+++ b/lib/make/webgl.js
@@ -551,5 +551,192 @@ make.webgl = {
])
}
return random.item(usage)
+ },
+ randomParameter: (isWebGL2) => {
+ let pname = [
+ 'ACTIVE_TEXTURE',
+ 'ALIASED_LINE_WIDTH_RANGE',
+ 'ALIASED_POINT_SIZE_RANGE',
+ 'ALPHA_BITS',
+ 'ARRAY_BUFFER_BINDING',
+ 'BLEND',
+ 'BLEND_COLOR',
+ 'BLEND_DST_ALPHA',
+ 'BLEND_DST_RGB',
+ 'BLEND_EQUATION_ALPHA',
+ 'BLEND_EQUATION_RGB',
+ 'BLEND_SRC_ALPHA',
+ 'BLEND_SRC_RGB',
+ 'BLUE_BITS',
+ 'COLOR_CLEAR_VALUE',
+ 'COLOR_WRITEMASK',
+ 'COMPRESSED_TEXTURE_FORMATS',
+ 'CULL_FACE',
+ 'CULL_FACE_MODE',
+ 'CURRENT_PROGRAM',
+ 'DEPTH_BITS',
+ 'DEPTH_CLEAR_VALUE',
+ 'DEPTH_FUNC',
+ 'DEPTH_RANGE',
+ 'DEPTH_TEST',
+ 'DEPTH_WRITEMASK',
+ 'DITHER',
+ 'ELEMENT_ARRAY_BUFFER_BINDING',
+ 'FRAMEBUFFER_BINDING',
+ 'FRONT_FACE',
+ 'GENERATE_MIPMAP_HINT',
+ 'GREEN_BITS',
+ 'IMPLEMENTATION_COLOR_READ_FORMAT',
+ 'IMPLEMENTATION_COLOR_READ_TYPE',
+ 'LINE_WIDTH',
+ 'MAX_COMBINED_TEXTURE_IMAGE_UNITS',
+ 'MAX_CUBE_MAP_TEXTURE_SIZE',
+ 'MAX_FRAGMENT_UNIFORM_VECTORS',
+ 'MAX_RENDERBUFFER_SIZE',
+ 'MAX_TEXTURE_IMAGE_UNITS',
+ 'MAX_TEXTURE_SIZE',
+ 'MAX_VARYING_VECTORS',
+ 'MAX_VERTEX_ATTRIBS',
+ 'MAX_VERTEX_TEXTURE_IMAGE_UNITS',
+ 'MAX_VERTEX_UNIFORM_VECTORS',
+ 'MAX_VIEWPORT_DIMS',
+ 'PACK_ALIGNMENT',
+ 'POLYGON_OFFSET_FACTOR',
+ 'POLYGON_OFFSET_FILL',
+ 'POLYGON_OFFSET_UNITS',
+ 'RED_BITS',
+ 'RENDERBUFFER_BINDING',
+ 'RENDERER',
+ 'SAMPLE_ALPHA_TO_COVERAGE',
+ 'SAMPLE_BUFFERS',
+ 'SAMPLE_COVERAGE',
+ 'SAMPLE_COVERAGE_INVERT',
+ 'SAMPLE_COVERAGE_VALUE',
+ 'SAMPLES',
+ 'SCISSOR_BOX',
+ 'SCISSOR_TEST',
+ 'SHADING_LANGUAGE_VERSION',
+ 'STENCIL_BACK_FAIL',
+ 'STENCIL_BACK_FUNC',
+ 'STENCIL_BACK_PASS_DEPTH_FAIL',
+ 'STENCIL_BACK_PASS_DEPTH_PASS',
+ 'STENCIL_BACK_REF',
+ 'STENCIL_BACK_VALUE_MASK',
+ 'STENCIL_BACK_WRITEMASK',
+ 'STENCIL_BITS',
+ 'STENCIL_CLEAR_VALUE',
+ 'STENCIL_FAIL',
+ 'STENCIL_FUNC',
+ 'STENCIL_PASS_DEPTH_FAIL',
+ 'STENCIL_PASS_DEPTH_PASS',
+ 'STENCIL_REF',
+ 'STENCIL_TEST',
+ 'STENCIL_VALUE_MASK',
+ 'STENCIL_WRITEMASK',
+ 'SUBPIXEL_BITS',
+ 'TEXTURE_BINDING_2D',
+ 'TEXTURE_BINDING_CUBE_MAP',
+ 'UNPACK_ALIGNMENT',
+ 'UNPACK_COLORSPACE_CONVERSION_WEBGL',
+ 'UNPACK_FLIP_Y_WEBGL',
+ 'UNPACK_PREMULTIPLY_ALPHA_WEBGL',
+ 'VENDOR',
+ 'VERSION',
+ 'VIEWPORT',
+ 'VERSION',
+ 'SHADING_LANGUAGE_VERSION',
+ 'VENDOR',
+ 'RENDERER'
+ ]
+
+ if (isWebGL2) {
+ pname.extends([
+ 'COPY_READ_BUFFER_BINDING',
+ 'COPY_WRITE_BUFFER_BINDING',
+ 'DRAW_BUFFERi',
+ 'DRAW_FRAMEBUFFER_BINDING',
+ 'FRAGMENT_SHADER_DERIVATIVE_HINT',
+ 'MAX_3D_TEXTURE_SIZE',
+ 'MAX_ARRAY_TEXTURE_LAYERS',
+ 'MAX_CLIENT_WAIT_TIMEOUT_WEBGL',
+ 'MAX_COLOR_ATTACHMENTS',
+ 'MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS',
+ 'MAX_COMBINED_UNIFORM_BLOCKS',
+ 'MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS',
+ 'MAX_DRAW_BUFFERS',
+ 'MAX_ELEMENT_INDEX',
+ 'MAX_ELEMENTS_INDICE',
+ 'MAX_ELEMENTS_VERTICES',
+ 'MAX_FRAGMENT_INPUT_COMPONENTS',
+ 'MAX_FRAGMENT_UNIFORM_BLOCKS',
+ 'MAX_FRAGMENT_UNIFORM_COMPONENTS',
+ 'MAX_PROGRAM_TEXEL_OFFSET',
+ 'MAX_SAMPLES',
+ 'MAX_SERVER_WAIT_TIMEOUT',
+ 'MAX_TEXTURE_LOD_BIAS',
+ 'MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS',
+ 'MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS',
+ 'MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS',
+ 'MAX_UNIFORM_BLOCK_SIZE',
+ 'MAX_UNIFORM_BUFFER_BINDINGS',
+ 'MAX_VARYING_COMPONENTS',
+ 'MAX_VERTEX_OUTPUT_COMPONENTS',
+ 'MAX_VERTEX_UNIFORM_BLOCKS',
+ 'MAX_VERTEX_UNIFORM_COMPONENTS',
+ 'MIN_PROGRAM_TEXEL_OFFSET',
+ 'PACK_ROW_LENGTH',
+ 'PACK_SKIP_PIXELS',
+ 'PACK_SKIP_ROWS',
+ 'PIXEL_PACK_BUFFER_BINDING',
+ 'PIXEL_UNPACK_BUFFER_BINDING',
+ 'RASTERIZER_DISCARD',
+ 'READ_BUFFER',
+ 'READ_FRAMEBUFFER_BINDING',
+ 'SAMPLER_BINDING',
+ 'TEXTURE_BINDING_2D_ARRAY',
+ 'TEXTURE_BINDING_3D',
+ 'TRANSFORM_FEEDBACK_ACTIVE',
+ 'TRANSFORM_FEEDBACK_BINDING',
+ 'TRANSFORM_FEEDBACK_BUFFER_BINDING',
+ 'TRANSFORM_FEEDBACK_PAUSED',
+ 'UNIFORM_BUFFER_BINDING',
+ 'UNIFORM_BUFFER_OFFSET_ALIGNMENT',
+ 'UNPACK_IMAGE_HEIGHT',
+ 'UNPACK_ROW_LENGTH',
+ 'UNPACK_SKIP_IMAGES',
+ 'UNPACK_SKIP_PIXELS',
+ 'UNPACK_SKIP_ROWS',
+ 'VERTEX_ARRAY_BINDING'
+ ])
+ }
+ return random.item(pname)
+ },
+ randomProgramParameter: () => {
+ let pname = [
+ 'DELETE_STATUS',
+ 'LINK_STATUS',
+ 'VALIDATE_STATUS',
+ 'ATTACHED_SHADERS',
+ 'ACTIVE_ATTRIBUTES',
+ 'ACTIVE_UNIFORMS',
+ 'TRANSFORM_FEEDBACK_BUFFER_MODE',
+ 'TRANSFORM_FEEDBACK_VARYINGS',
+ 'ACTIVE_UNIFORM_BLOCKS'
+ ]
+ return random.item(pname)
+ },
+ randomRenderBufferParameter: () => {
+ let pname = [
+ 'RENDERBUFFER_WIDTH',
+ 'RENDERBUFFER_HEIGHT',
+ 'RENDERBUFFER_INTERNAL_FORMAT',
+ 'RENDERBUFFER_RED_SIZE',
+ 'RENDERBUFFER_GREEN_SIZE',
+ 'RENDERBUFFER_BLUE_SIZE',
+ 'RENDERBUFFER_ALPHA_SIZE',
+ 'RENDERBUFFER_DEPTH_SIZE',
+ 'RENDERBUFFER_STENCIL_SIZE'
+ ]
+ return random.item(pname)
}
}
From cd0d0c316a94d19390935dd8fd7d511b45981f10 Mon Sep 17 00:00:00 2001
From: posidron <1614333+posidron@users.noreply.github.com>
Date: Thu, 23 Aug 2018 17:30:52 +0200
Subject: [PATCH 4/9] Fix stuff failed during merge
---
README.md | 4 -
lib/make/webgl.js | 187 ----------------------------------------------
2 files changed, 191 deletions(-)
diff --git a/README.md b/README.md
index 4aaf101..92defe2 100644
--- a/README.md
+++ b/README.md
@@ -18,10 +18,6 @@ Octo.js bundles core functions and generic boilerplate code commonly used in mos
Octo's future aims to be a stable, well-tested and well-documented standard library for fuzzing in a JavaScript environment.
-## Note
-The ES6 branch is under active development while we are incorporating it with our existing fuzzers.
-
-
## Playbook
https://runkit.com/posidron/octo-js-playbook
diff --git a/lib/make/webgl.js b/lib/make/webgl.js
index d14c72b..6a4cce0 100644
--- a/lib/make/webgl.js
+++ b/lib/make/webgl.js
@@ -621,193 +621,6 @@ class webgl extends make {
])
}
return random.item(usage)
- },
- randomParameter: (isWebGL2) => {
- let pname = [
- 'ACTIVE_TEXTURE',
- 'ALIASED_LINE_WIDTH_RANGE',
- 'ALIASED_POINT_SIZE_RANGE',
- 'ALPHA_BITS',
- 'ARRAY_BUFFER_BINDING',
- 'BLEND',
- 'BLEND_COLOR',
- 'BLEND_DST_ALPHA',
- 'BLEND_DST_RGB',
- 'BLEND_EQUATION_ALPHA',
- 'BLEND_EQUATION_RGB',
- 'BLEND_SRC_ALPHA',
- 'BLEND_SRC_RGB',
- 'BLUE_BITS',
- 'COLOR_CLEAR_VALUE',
- 'COLOR_WRITEMASK',
- 'COMPRESSED_TEXTURE_FORMATS',
- 'CULL_FACE',
- 'CULL_FACE_MODE',
- 'CURRENT_PROGRAM',
- 'DEPTH_BITS',
- 'DEPTH_CLEAR_VALUE',
- 'DEPTH_FUNC',
- 'DEPTH_RANGE',
- 'DEPTH_TEST',
- 'DEPTH_WRITEMASK',
- 'DITHER',
- 'ELEMENT_ARRAY_BUFFER_BINDING',
- 'FRAMEBUFFER_BINDING',
- 'FRONT_FACE',
- 'GENERATE_MIPMAP_HINT',
- 'GREEN_BITS',
- 'IMPLEMENTATION_COLOR_READ_FORMAT',
- 'IMPLEMENTATION_COLOR_READ_TYPE',
- 'LINE_WIDTH',
- 'MAX_COMBINED_TEXTURE_IMAGE_UNITS',
- 'MAX_CUBE_MAP_TEXTURE_SIZE',
- 'MAX_FRAGMENT_UNIFORM_VECTORS',
- 'MAX_RENDERBUFFER_SIZE',
- 'MAX_TEXTURE_IMAGE_UNITS',
- 'MAX_TEXTURE_SIZE',
- 'MAX_VARYING_VECTORS',
- 'MAX_VERTEX_ATTRIBS',
- 'MAX_VERTEX_TEXTURE_IMAGE_UNITS',
- 'MAX_VERTEX_UNIFORM_VECTORS',
- 'MAX_VIEWPORT_DIMS',
- 'PACK_ALIGNMENT',
- 'POLYGON_OFFSET_FACTOR',
- 'POLYGON_OFFSET_FILL',
- 'POLYGON_OFFSET_UNITS',
- 'RED_BITS',
- 'RENDERBUFFER_BINDING',
- 'RENDERER',
- 'SAMPLE_ALPHA_TO_COVERAGE',
- 'SAMPLE_BUFFERS',
- 'SAMPLE_COVERAGE',
- 'SAMPLE_COVERAGE_INVERT',
- 'SAMPLE_COVERAGE_VALUE',
- 'SAMPLES',
- 'SCISSOR_BOX',
- 'SCISSOR_TEST',
- 'SHADING_LANGUAGE_VERSION',
- 'STENCIL_BACK_FAIL',
- 'STENCIL_BACK_FUNC',
- 'STENCIL_BACK_PASS_DEPTH_FAIL',
- 'STENCIL_BACK_PASS_DEPTH_PASS',
- 'STENCIL_BACK_REF',
- 'STENCIL_BACK_VALUE_MASK',
- 'STENCIL_BACK_WRITEMASK',
- 'STENCIL_BITS',
- 'STENCIL_CLEAR_VALUE',
- 'STENCIL_FAIL',
- 'STENCIL_FUNC',
- 'STENCIL_PASS_DEPTH_FAIL',
- 'STENCIL_PASS_DEPTH_PASS',
- 'STENCIL_REF',
- 'STENCIL_TEST',
- 'STENCIL_VALUE_MASK',
- 'STENCIL_WRITEMASK',
- 'SUBPIXEL_BITS',
- 'TEXTURE_BINDING_2D',
- 'TEXTURE_BINDING_CUBE_MAP',
- 'UNPACK_ALIGNMENT',
- 'UNPACK_COLORSPACE_CONVERSION_WEBGL',
- 'UNPACK_FLIP_Y_WEBGL',
- 'UNPACK_PREMULTIPLY_ALPHA_WEBGL',
- 'VENDOR',
- 'VERSION',
- 'VIEWPORT',
- 'VERSION',
- 'SHADING_LANGUAGE_VERSION',
- 'VENDOR',
- 'RENDERER'
- ]
-
- if (isWebGL2) {
- pname.extends([
- 'COPY_READ_BUFFER_BINDING',
- 'COPY_WRITE_BUFFER_BINDING',
- 'DRAW_BUFFERi',
- 'DRAW_FRAMEBUFFER_BINDING',
- 'FRAGMENT_SHADER_DERIVATIVE_HINT',
- 'MAX_3D_TEXTURE_SIZE',
- 'MAX_ARRAY_TEXTURE_LAYERS',
- 'MAX_CLIENT_WAIT_TIMEOUT_WEBGL',
- 'MAX_COLOR_ATTACHMENTS',
- 'MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS',
- 'MAX_COMBINED_UNIFORM_BLOCKS',
- 'MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS',
- 'MAX_DRAW_BUFFERS',
- 'MAX_ELEMENT_INDEX',
- 'MAX_ELEMENTS_INDICE',
- 'MAX_ELEMENTS_VERTICES',
- 'MAX_FRAGMENT_INPUT_COMPONENTS',
- 'MAX_FRAGMENT_UNIFORM_BLOCKS',
- 'MAX_FRAGMENT_UNIFORM_COMPONENTS',
- 'MAX_PROGRAM_TEXEL_OFFSET',
- 'MAX_SAMPLES',
- 'MAX_SERVER_WAIT_TIMEOUT',
- 'MAX_TEXTURE_LOD_BIAS',
- 'MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS',
- 'MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS',
- 'MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS',
- 'MAX_UNIFORM_BLOCK_SIZE',
- 'MAX_UNIFORM_BUFFER_BINDINGS',
- 'MAX_VARYING_COMPONENTS',
- 'MAX_VERTEX_OUTPUT_COMPONENTS',
- 'MAX_VERTEX_UNIFORM_BLOCKS',
- 'MAX_VERTEX_UNIFORM_COMPONENTS',
- 'MIN_PROGRAM_TEXEL_OFFSET',
- 'PACK_ROW_LENGTH',
- 'PACK_SKIP_PIXELS',
- 'PACK_SKIP_ROWS',
- 'PIXEL_PACK_BUFFER_BINDING',
- 'PIXEL_UNPACK_BUFFER_BINDING',
- 'RASTERIZER_DISCARD',
- 'READ_BUFFER',
- 'READ_FRAMEBUFFER_BINDING',
- 'SAMPLER_BINDING',
- 'TEXTURE_BINDING_2D_ARRAY',
- 'TEXTURE_BINDING_3D',
- 'TRANSFORM_FEEDBACK_ACTIVE',
- 'TRANSFORM_FEEDBACK_BINDING',
- 'TRANSFORM_FEEDBACK_BUFFER_BINDING',
- 'TRANSFORM_FEEDBACK_PAUSED',
- 'UNIFORM_BUFFER_BINDING',
- 'UNIFORM_BUFFER_OFFSET_ALIGNMENT',
- 'UNPACK_IMAGE_HEIGHT',
- 'UNPACK_ROW_LENGTH',
- 'UNPACK_SKIP_IMAGES',
- 'UNPACK_SKIP_PIXELS',
- 'UNPACK_SKIP_ROWS',
- 'VERTEX_ARRAY_BINDING'
- ])
- }
- return random.item(pname)
- },
- randomProgramParameter: () => {
- let pname = [
- 'DELETE_STATUS',
- 'LINK_STATUS',
- 'VALIDATE_STATUS',
- 'ATTACHED_SHADERS',
- 'ACTIVE_ATTRIBUTES',
- 'ACTIVE_UNIFORMS',
- 'TRANSFORM_FEEDBACK_BUFFER_MODE',
- 'TRANSFORM_FEEDBACK_VARYINGS',
- 'ACTIVE_UNIFORM_BLOCKS'
- ]
- return random.item(pname)
- },
- randomRenderBufferParameter: () => {
- let pname = [
- 'RENDERBUFFER_WIDTH',
- 'RENDERBUFFER_HEIGHT',
- 'RENDERBUFFER_INTERNAL_FORMAT',
- 'RENDERBUFFER_RED_SIZE',
- 'RENDERBUFFER_GREEN_SIZE',
- 'RENDERBUFFER_BLUE_SIZE',
- 'RENDERBUFFER_ALPHA_SIZE',
- 'RENDERBUFFER_DEPTH_SIZE',
- 'RENDERBUFFER_STENCIL_SIZE'
- ]
- return random.item(pname)
}
static randomParameter (isWebGL2) {
From fb4e0b1fcafbd87cd8b15613118e109228f732a6 Mon Sep 17 00:00:00 2001
From: posidron <1614333+posidron@users.noreply.github.com>
Date: Thu, 23 Aug 2018 22:29:55 +0200
Subject: [PATCH 5/9] Add ESDoc documentation generator
---
.travis.yml | 44 +++++++++++++++++++++++---------------------
esdoc.json | 14 ++++++++++++++
package.json | 6 +++++-
3 files changed, 42 insertions(+), 22 deletions(-)
create mode 100644 esdoc.json
diff --git a/.travis.yml b/.travis.yml
index 0433354..df0d8ab 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,31 +1,33 @@
language: node_js
dist: trusty
env:
- - DISPLAY=:99.0 CHROME_BIN=chromium-browser
+- DISPLAY=:99.0 CHROME_BIN=chromium-browser
node_js:
- - "7"
+- "7"
addons:
- firefox: latest
+- firefox: latest
before_script:
- - sh -e /etc/init.d/xvfb start
-before_deploy:
- - mkdir -p deploy
- - ./build.py -l lib -d deploy
+- sh -e /etc/init.d/xvfb start
+script:
+- yarn run build
+after_success:
+- yarn run docs
notifications:
slack:
secure: Kwe1KBh4SMzgXaj6GQg3ZmopRYcDR3Vnd4C/gyiEOJsXzKRlU5dA7WwM/mbyOe9+ZvWDyp+g2CoQYYyvLR0SHEy1m0gn6M8fBzgSZQlWxOxAJxkwVsyxUNwAy2FylMpS+ugpw/fBMSbnSFqfZSa/tGB3KhBc0yA7V9wVS0hnwBfICqKKlFdLPcp+Us4zpXRUmcL1e0BVwm2klJi0CoKlOmTa4lI3tUa/YiuuMpgk89/PioMEr6/PP+5OfWV624djw2gznoualvcwdfZniC/oxkdTUbcu4nbTf+bFk5uwwW+XBpUhm9rMUoftngYCrWdtYHS6qenyzmflO5bgCDg5W8onv3qgMcDTEHDjlO8JMoEQLC2o27Hsyukrh2Iu0Hn2k4S10ZIDWLUZXf8ERKdU7v8o5xaiCrP7NO8fJlyGbWwYxwpFi9dpacb8qWuWw53k8+ld9orl2Zu5t1Y1QJCvT0DP0iGYSxbbICfex7im0fgh3A+MHTfhxxiGQtFJRUxqO5wGCIsT4dJJkYwRJ1HoCPyLT1x1WT8iy4lr8ivRhanEwQ5g2OmuRKz522yCrm2DPaRR/LDhqK9xghJqqh4RNx9Be5xNaxSxKs4Hcya4ZXrGaU9tzGTehRkNQksKUHq9PpdY85Mbk84wEq7zKLhtLPTn17DQePFm2DbdX4392o4=
deploy:
- - provider: releases
- api_key:
- secure: HszUovTqcRxuXTmH3/rStEe1ZeZbrZweQah8Bq0POs89P3/GjyEat11WbH9S7tfIT1yVcF736TmsDNRtl34Rmr71P7rczwFlX1yJOIamH4jT9vG8ocpZH4Orc6XA2s7UclD1HwJwStM1k2J4CV34eTTlX36ngjYrp09HertXAQWSK6TZk9RK6ql2HlNzchImz2EY1aQnfqkrFByOtM4o/SJJryJJBJUMD69gWrYu6cv51w/jMEoUtzvV6Nr2o9YOuo97B0scJmbxgfx67FaCQwEOxKtr8xT5nttJ2q6EeaAiErAieG8/o8yRsJRFrHyVm42v9PEfoe8O8Y4g/1VrtbjY3vH8LPpCotMxhshjUCBaLDc8TCC/osik6dxhv/fqjbdPwrGRW2qzsmXIZug7+YCEW+qUFRPwwX+Cr0ENnaPFMSDFxANeLF7KfF7oaVnr8JTlZnu9G+Uliqe6RNCoWfQtpTRM759cDLQp4b5eBQF2G61x2XOdRqcNZepRaRVnsaCo0lNPW9o5HCQnJnMbEB9Gdowt18PwgVucIdIPJeAPodMs40s7sUOP5Xik58b4YBG9lsgLBcfCgTy+n8JPS2LJsclG82pBACtSV+ucc6rVeD+5fbSUxn4ItaK4e0MonCv4Jnp7zGn6hErcpexBmXSdYQSrdsemKDTGHibOF6U=
- file: deploy/octo.js
- skip_cleanup: true
- on:
- tags: true
- - provider: pages
- github_token:
- secure: HszUovTqcRxuXTmH3/rStEe1ZeZbrZweQah8Bq0POs89P3/GjyEat11WbH9S7tfIT1yVcF736TmsDNRtl34Rmr71P7rczwFlX1yJOIamH4jT9vG8ocpZH4Orc6XA2s7UclD1HwJwStM1k2J4CV34eTTlX36ngjYrp09HertXAQWSK6TZk9RK6ql2HlNzchImz2EY1aQnfqkrFByOtM4o/SJJryJJBJUMD69gWrYu6cv51w/jMEoUtzvV6Nr2o9YOuo97B0scJmbxgfx67FaCQwEOxKtr8xT5nttJ2q6EeaAiErAieG8/o8yRsJRFrHyVm42v9PEfoe8O8Y4g/1VrtbjY3vH8LPpCotMxhshjUCBaLDc8TCC/osik6dxhv/fqjbdPwrGRW2qzsmXIZug7+YCEW+qUFRPwwX+Cr0ENnaPFMSDFxANeLF7KfF7oaVnr8JTlZnu9G+Uliqe6RNCoWfQtpTRM759cDLQp4b5eBQF2G61x2XOdRqcNZepRaRVnsaCo0lNPW9o5HCQnJnMbEB9Gdowt18PwgVucIdIPJeAPodMs40s7sUOP5Xik58b4YBG9lsgLBcfCgTy+n8JPS2LJsclG82pBACtSV+ucc6rVeD+5fbSUxn4ItaK4e0MonCv4Jnp7zGn6hErcpexBmXSdYQSrdsemKDTGHibOF6U=
- local_dir: deploy
- skip_cleanup: true
- on:
- branch: master
+- provider: releases
+ api_key:
+ secure: HszUovTqcRxuXTmH3/rStEe1ZeZbrZweQah8Bq0POs89P3/GjyEat11WbH9S7tfIT1yVcF736TmsDNRtl34Rmr71P7rczwFlX1yJOIamH4jT9vG8ocpZH4Orc6XA2s7UclD1HwJwStM1k2J4CV34eTTlX36ngjYrp09HertXAQWSK6TZk9RK6ql2HlNzchImz2EY1aQnfqkrFByOtM4o/SJJryJJBJUMD69gWrYu6cv51w/jMEoUtzvV6Nr2o9YOuo97B0scJmbxgfx67FaCQwEOxKtr8xT5nttJ2q6EeaAiErAieG8/o8yRsJRFrHyVm42v9PEfoe8O8Y4g/1VrtbjY3vH8LPpCotMxhshjUCBaLDc8TCC/osik6dxhv/fqjbdPwrGRW2qzsmXIZug7+YCEW+qUFRPwwX+Cr0ENnaPFMSDFxANeLF7KfF7oaVnr8JTlZnu9G+Uliqe6RNCoWfQtpTRM759cDLQp4b5eBQF2G61x2XOdRqcNZepRaRVnsaCo0lNPW9o5HCQnJnMbEB9Gdowt18PwgVucIdIPJeAPodMs40s7sUOP5Xik58b4YBG9lsgLBcfCgTy+n8JPS2LJsclG82pBACtSV+ucc6rVeD+5fbSUxn4ItaK4e0MonCv4Jnp7zGn6hErcpexBmXSdYQSrdsemKDTGHibOF6U=
+ file: deploy/octo.js
+ skip_cleanup: true
+ on:
+ tags: true
+- provider: pages
+ keep-history: true
+ skip_cleanup: true
+ github_token:
+ secure: PvCrB9ckDfWedl1rdo/3mUvCy/Vg4ksZR2mj4KT3AdEyukbpMiVVDkocMFohuIq+mnRdeyhpvM2KluLHhQrEhWjvqVobiZ9/c0gWWxZHV8doDdqNUPm693MpGojMOxHT4qRih6x9KyjanmWAwy/Bc972dpD5vtaTx1gKOzRUjUI=
+ on:
+ branch: master
+ local_dir: docs/
diff --git a/esdoc.json b/esdoc.json
new file mode 100644
index 0000000..937dff9
--- /dev/null
+++ b/esdoc.json
@@ -0,0 +1,14 @@
+{
+ "source": "./octo",
+ "destination": "./docs",
+ "plugins": [
+ {
+ "name": "esdoc-standard-plugin",
+ "option": {
+ "lint": { "enable": true },
+ "coverage": { "enable": true }
+ }
+ },
+ { "name": "esdoc-node" }
+ ]
+}
diff --git a/package.json b/package.json
index f4f8a99..a79946f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@mozillasecurity/octo",
- "version": "1.0.14",
+ "version": "1.0.15",
"description": "",
"keywords": [
"fuzzing",
@@ -24,6 +24,7 @@
"test": "grunt test --verbose",
"test:lint": "cross-env NODE_ENV=test standard --verbose",
"test:lint:fix": "cross-env NODE_ENV=test standard --fix --verbose",
+ "docs": "esdoc -c esdoc.json",
"build": "webpack -p",
"watch": "webpack --watch",
"precommit": "npm run test:lint",
@@ -43,6 +44,9 @@
},
"devDependencies": {
"cross-env": "^5.1.4",
+ "esdoc": "^1.1.0",
+ "esdoc-node": "^1.0.3",
+ "esdoc-standard-plugin": "^1.0.0",
"grunt": "*",
"grunt-karma": "*",
"grunt-karma-coveralls": "*",
From 60c8f2174d697b698e89bb4368dc9bd6e5058fdb Mon Sep 17 00:00:00 2001
From: posidron <1614333+posidron@users.noreply.github.com>
Date: Sat, 25 Aug 2018 07:28:30 +0200
Subject: [PATCH 6/9] Fix test suite which is broken since the switch to
Webpack #4
---
.gitignore | 2 +
Gruntfile.js | 31 -
README.md | 53 +-
esdoc.json | 14 -
karma.conf.js | 60 -
lib/random/__tests__/mersennetwister.test.js | 92 ++
lib/random/__tests__/random.test.js | 1374 ++++++++++++++++++
package.json | 60 +-
tests/index.html | 44 -
tests/random/mersennetwister.js | 58 -
tests/random/random.js | 892 ------------
11 files changed, 1536 insertions(+), 1144 deletions(-)
delete mode 100644 Gruntfile.js
delete mode 100644 esdoc.json
delete mode 100644 karma.conf.js
create mode 100644 lib/random/__tests__/mersennetwister.test.js
create mode 100644 lib/random/__tests__/random.test.js
delete mode 100644 tests/index.html
delete mode 100644 tests/random/mersennetwister.js
delete mode 100644 tests/random/random.js
diff --git a/.gitignore b/.gitignore
index ec70e51..9895e88 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
.DS_Store
+.vscode
node_modules
package-lock.json
+yarn.lock
tests/coverage
diff --git a/Gruntfile.js b/Gruntfile.js
deleted file mode 100644
index 5cc3bff..0000000
--- a/Gruntfile.js
+++ /dev/null
@@ -1,31 +0,0 @@
-module.exports = function (grunt) {
- let pkg = grunt.file.readJSON('package.json')
-
- grunt.initConfig({
- pkg: pkg,
-
- karma: {
- unit: {
- configFile: 'karma.conf.js'
- }
- },
- coveralls: {
- options: {
- coverageDir: 'tests/coverage/',
- force: true
- }
- },
- standard: {
- options: pkg.standard,
- lib: {
- src: ['lib/**/*.js']
- }
- }
- })
-
- grunt.loadNpmTasks('grunt-karma')
- grunt.loadNpmTasks('grunt-karma-coveralls')
- grunt.loadNpmTasks('grunt-standard')
-
- grunt.registerTask('test', ['standard', 'karma', 'coveralls'])
-}
diff --git a/README.md b/README.md
index 92defe2..9f661d9 100644
--- a/README.md
+++ b/README.md
@@ -18,15 +18,24 @@ Octo.js bundles core functions and generic boilerplate code commonly used in mos
Octo's future aims to be a stable, well-tested and well-documented standard library for fuzzing in a JavaScript environment.
-## Playbook
+## Table of Contents
+- [Table of Contents](#table-of-contents)
+ - [Playbook](#playbook)
+ - [Usage in Node](#usage-in-node)
+ - [Usage in Browser](#usage-in-browser)
+ - [Develop](#develop)
+ - [Testing](#testing)
+ - [API Documentation](#api-documentation)
+
+### Playbook
https://runkit.com/posidron/octo-js-playbook
-## Node
+### Usage in Node
```
-npm i @mozillasecurity/octo
+yarn add @mozillasecurity/octo
```
```
@@ -34,33 +43,35 @@ const {random} = require('@mozillasecurity/octo')
random.init()
```
-
-## Browser
-
-We have not yet merged ES6 to master, hence the browser version which was released on master is not up-to-date.
-Use the `dist/octo.js` version of this branch by running the following command.
+### Usage in Browser
```
-npm run build
+yarn build
```
-
-## Development
+### Develop
```bash
-npm install
-npm run build
-npm run watch
-npm run test:lint
+yarn install
+yarn lint
+yarn test
+yarn build
```
-## Testing
+### Testing
-Tests live in the `tests/` subdirectory, and are written for [QUnit](https://qunitjs.com/).
-To run tests locally, open `tests/index.html` in a browser.
-The automated tests are run in Firefox or Chrome using [Karma](https://karma-runner.github.io/).
-To run the automated tests:
+Octo.js uses Jest for testing. Each directory should contain a `__tests__` folder containing the tests.
```bash
-npm test
+yarn test
+```
+
+### API Documentation
+
+* https://
+
+or
+
+```
+yarn docs
```
diff --git a/esdoc.json b/esdoc.json
deleted file mode 100644
index 937dff9..0000000
--- a/esdoc.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "source": "./octo",
- "destination": "./docs",
- "plugins": [
- {
- "name": "esdoc-standard-plugin",
- "option": {
- "lint": { "enable": true },
- "coverage": { "enable": true }
- }
- },
- { "name": "esdoc-node" }
- ]
-}
diff --git a/karma.conf.js b/karma.conf.js
deleted file mode 100644
index 324735b..0000000
--- a/karma.conf.js
+++ /dev/null
@@ -1,60 +0,0 @@
-module.exports = function (config) {
- let configuration = {
- basePath: './tests',
-
- frameworks: ['qunit'],
-
- files: [
- '../lib/utils/init.js',
- '../lib/utils/*.js',
- '../lib/logging/*.js',
- '../lib/make/init.js',
- '../lib/make/*.js',
- '../lib/random/*.js',
- '**/*.js'
- ],
-
- exclude: [
- ],
-
- preprocessors: {
- '../lib/**/*.js': ['coverage']
- },
-
- reporters: ['progress', 'coverage'],
-
- port: 9876,
-
- colors: true,
-
- logLevel: config.LOG_INFO,
-
- autoWatch: true,
-
- browsers: ['Chrome', 'Firefox'],
-
- singleRun: true,
-
- browserNoActivityTimeout: 30000,
-
- customLaunchers: {
- Chrome_travis_ci: {
- base: 'Chrome',
- flags: ['--no-sandbox']
- }
- },
-
- coverageReporter: {
- reporters: [
- { type: 'lcov', dir: 'coverage/' },
- { type: 'text-summary' }
- ]
- }
- }
-
- if (process.env.TRAVIS) {
- configuration.browsers = ['Chrome_travis_ci', 'Firefox']
- }
-
- config.set(configuration)
-}
diff --git a/lib/random/__tests__/mersennetwister.test.js b/lib/random/__tests__/mersennetwister.test.js
new file mode 100644
index 0000000..49f2764
--- /dev/null
+++ b/lib/random/__tests__/mersennetwister.test.js
@@ -0,0 +1,92 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* eslint-env jest */
+const MersenneTwister = require('../mersennetwister')
+
+describe('MersenneTwister', () => {
+ test('uniform distribution', () => {
+ const N = Math.pow(2, 18)
+ const TRIES = 10
+ const XSQ = 293.25 // quantile of chi-square dist. k=255, p=.05
+
+ let mt = new MersenneTwister()
+ mt.seed(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let data = new Uint32Array(N)
+ let sh
+ for (let i = 0; i < data.length; ++i) {
+ data[i] = mt.int32()
+ }
+ for (sh = 0; sh <= 24; ++sh) {
+ let bins = new Uint32Array(256)
+ for (let b of data) {
+ ++bins[(b >>> sh) & 0xff]
+ }
+ let xsq = bins.reduce((a, v) => {
+ let e = N / bins.length
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 255)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ if (sh === 25) {
+ return
+ }
+ }
+ return false
+ }
+
+ expect(_test()).toBe(true)
+ })
+
+ test('float distribution', () => {
+ const N = Math.pow(2, 18)
+ const TRIES = 3
+ const XSQ = 564.7 // quantile of chi-square dist. k=511, p=.05
+
+ let mt = new MersenneTwister()
+ mt.seed(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(512)
+ for (let i = 0; i < N; ++i) {
+ let tmp = (mt.real2() * bins.length) >>> 0
+ if (tmp >= bins.length) {
+ throw new Error('random.float() >= 1.0')
+ }
+ ++bins[tmp]
+ }
+ let xsq = bins.reduce((a, v) => {
+ let e = N / bins.length
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 511)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": " + tries)
+ return false
+ }
+ expect(_test()).toBe(true)
+ })
+})
diff --git a/lib/random/__tests__/random.test.js b/lib/random/__tests__/random.test.js
new file mode 100644
index 0000000..d3434e9
--- /dev/null
+++ b/lib/random/__tests__/random.test.js
@@ -0,0 +1,1374 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* eslint-disable camelcase */
+/* eslint-env jest */
+const random = require('../random')
+
+describe('Random', () => {
+ test('init', () => {
+ expect(() => {
+ random.number()
+ }).toThrow()
+ random.init(1)
+ random.number()
+ })
+
+ test('number() corner cases', () => {
+ random.init(Math.random() * 0x100000000)
+ let sum = 0
+
+ for (let i = 0; i < 100; ++i) {
+ sum += random.number(0)
+ }
+ expect(sum).toEqual(0)
+
+ for (let i = 0; i < 100; ++i) {
+ sum += random.number(1)
+ }
+ expect(sum).toEqual(0)
+
+ let bins = new Uint32Array(2)
+ for (let i = 0; i < 100; ++i) {
+ ++bins[random.number(2)]
+ }
+ expect(bins[0] + bins[1]).toEqual(100)
+ expect(bins[0]).toBeGreaterThan(20)
+
+ sum = 0
+ for (let i = 0; i < 15; ++i) {
+ sum |= random.number()
+ }
+ expect(sum >>> 0).toEqual(0xffffffff)
+ })
+
+ test('number() uniform distriution', () => {
+ const N = Math.pow(2, 17)
+ const TRIES = 3
+ const XSQ = 564.7 // quantile of chi-square dist. k=511, p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(512)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.number(bins.length)
+ expect(tmp).toBeLessThan(bins.length)
+ ++bins[tmp]
+ }
+ let xsq = bins.reduce((a, v) => {
+ let e = N / bins.length
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 511)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": " + tries)
+ return false
+ }
+
+ expect(_test()).toBe(true)
+ })
+
+ test('float() uniform distribution', () => {
+ const N = Math.pow(2, 17)
+ const TRIES = 3
+ const XSQ = 564.7 // quantile of chi-square dist. k=511, p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(512)
+ for (let i = 0; i < N; ++i) {
+ let tmp = (random.float() * bins.length) >>> 0
+ expect(tmp).toBeLessThan(bins.length)
+ ++bins[tmp]
+ }
+ let xsq = bins.reduce((a, v) => {
+ let e = N / bins.length
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 511)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": " + tries)
+ return false
+ }
+
+ expect(_test()).toBe(true)
+ })
+
+ test('range() uniform distribution', () => {
+ const N = 1e4
+ const TRIES = 3
+ const XSQ = 66.34 // quantile of chi-square dist. k=49, p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(50)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.range(0, bins.length - 1)
+ expect(tmp).toBeLessThan(bins.length)
+ ++bins[tmp]
+ }
+ let xsq = bins.reduce((a, v) => {
+ let e = N / bins.length
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 49)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": " + tries)
+ return false
+ }
+
+ expect(_test()).toBe(true)
+ })
+
+ test('range() uniform distribution with offset', () => {
+ const N = 1e4
+ const TRIES = 3
+ const XSQ = 66.34 // quantile of chi-square dist. k=49, p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(50)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.range(10, 10 + bins.length - 1) - 10
+ expect(tmp).toBeGreaterThanOrEqual(0)
+ expect(tmp).toBeLessThan(bins.length)
+ ++bins[tmp]
+ }
+ let xsq = bins.reduce((a, v) => {
+ let e = N / bins.length
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 49)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": " + tries)
+ return false
+ }
+
+ expect(_test()).toBe(true)
+ })
+
+ test('range() PRNG reproducibility', () => {
+ let seed, result1, result2
+ seed = Math.random() * 0x100000000
+ for (let t = 0; t < 50; ++t) {
+ random.init(seed)
+ result1 = random.range(1, 20)
+ for (let i = 0; i < 5; ++i) {
+ random.init(seed)
+ result2 = random.range(1, 20)
+ expect(result1).toBe(result2)
+ }
+ seed = random.number()
+ }
+ })
+
+ test('item() exception cases', () => {
+ expect(() => {
+ random.item()
+ }).toThrowError('random.item() received invalid object: (undefined)')
+ expect(() => {
+ random.item(1)
+ }).toThrowError('random.item() received invalid object: (1)')
+ expect(() => {
+ random.item('1')
+ }).toThrowError('random.item() received invalid object: (1)')
+ expect(() => {
+ random.item({})
+ }).toThrowError('random.item() received invalid object: ([object Object])')
+ })
+
+ test('item() distribution with list', () => {
+ const N = 1e4
+ const TRIES = 3
+ const XSQ = 5.99 // quantile of chi-square dist. k=2, p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(3)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.item([99, 100, 101]) - 99
+ expect(tmp).toBeGreaterThanOrEqual(0)
+ expect(tmp).toBeLessThan(bins.length)
+ ++bins[tmp]
+ }
+ let xsq = bins.reduce((a, v) => {
+ let e = N / bins.length
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 2)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": " + tries)
+ return false
+ }
+
+ expect(_test()).toBe(true)
+ })
+
+ test('key() distribution', () => {
+ const N = 1e4
+ const TRIES = 3
+ const XSQ = 5.99 // quantile of chi-square dist. k=2, p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(3)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.key({ 99: 0, 100: 0, 101: 0 }) - 99
+ expect(tmp).toBeGreaterThanOrEqual(0)
+ expect(tmp).toBeLessThan(bins.length)
+ ++bins[tmp]
+ }
+ let xsq = bins.reduce((a, v) => {
+ let e = N / bins.length
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 2)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": " + tries)
+ return false
+ }
+ expect(_test()).toBe(true)
+ })
+
+ test('bool() distribution', () => {
+ const N = 1e4
+ const TRIES = 3
+ const XSQ = 3.84 // quantile of chi-square dist. k=1, p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(2)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.bool()
+ if (tmp === true) {
+ tmp = 1
+ } else if (tmp === false) {
+ tmp = 0
+ } else {
+ throw new Error(`Unexpected random.bool() result: ${tmp}`)
+ }
+ ++bins[tmp]
+ }
+ let xsq = bins.reduce((a, v) => {
+ let e = N / bins.length
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 1)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": " + tries)
+ return false
+ }
+ expect(_test()).toBe(true)
+ })
+
+ test('pick() cases', () => {
+ random.init(Math.random() * 0x100000000)
+
+ for (let i = 0; i < 100; ++i) {
+ let tmp = Math.random()
+ expect(random.pick(tmp)).toEqual(tmp)
+ }
+
+ for (let i = 0; i < 100; ++i) {
+ let tmp = (Math.random() * 100) >>> 0
+ expect(random.pick(tmp)).toEqual(tmp)
+ }
+
+ for (let i = 0; i < 100; ++i) {
+ let tmp = Math.random() + ''
+ expect(random.pick(tmp)).toEqual(tmp)
+ }
+
+ for (let i = 0; i < 100; ++i) {
+ let tmp = Math.random()
+ expect(random.pick([tmp])).toEqual(tmp)
+ }
+
+ for (let i = 0; i < 100; ++i) {
+ let tmp = Math.random()
+ expect(random.pick(() => tmp)).toEqual(tmp)
+ }
+
+ for (let i = 0; i < 100; ++i) {
+ let tmp = Math.random()
+ expect(random.pick(() => [tmp])).toEqual([tmp])
+ }
+ })
+
+ test('pick() with equal distribution', () => {
+ const N = 1e4
+ const TRIES = 3
+ const XSQ = 5.99 // quantile of chi-square dist. k=2, p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(3)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.pick([
+ 0,
+ [1, 1],
+ () => 2
+ ])
+ expect(tmp).toBeGreaterThanOrEqual(0)
+ expect(tmp).toBeLessThan(bins.length)
+ ++bins[tmp]
+ }
+ let xsq = bins.reduce((a, v) => {
+ let e = N / bins.length
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 2)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": " + tries)
+ return false
+ }
+
+ expect(_test()).toBe(true)
+ })
+
+ test('pick() with unequal distribution', () => {
+ const N = 1e4
+ const TRIES = 3
+ const XSQ = 5.99 // quantile of chi-square dist. k=2, p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(3)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.pick([
+ [0, 1],
+ [1],
+ () => 2
+ ])
+ expect(tmp).toBeGreaterThanOrEqual(0)
+ expect(tmp).toBeLessThan(bins.length)
+ ++bins[tmp]
+ }
+ let xsq =
+ Math.pow(bins[0] - N / 6, 2) / (N / 6) +
+ Math.pow(bins[1] - N / 2, 2) / (N / 2) +
+ Math.pow(bins[2] - N / 3, 2) / (N / 3)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 2)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": " + tries)
+ return false
+ }
+
+ expect(_test()).toBe(true)
+ })
+
+ test('chance(undefined) distribution', () => {
+ const N = 1e4
+ const TRIES = 3
+ const XSQ = 3.84 // quantile of chi-square dist. k=1, p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(2)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.chance()
+ if (tmp === true) {
+ tmp = 1
+ } else if (tmp === false) {
+ tmp = 0
+ } else {
+ throw new Error(`Unexpected random.chance() result: ${tmp}`)
+ }
+ ++bins[tmp]
+ }
+ let xsq = bins.reduce((a, v) => {
+ let e = N / bins.length
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 1)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": " + tries)
+ return false
+ }
+
+ expect(_test()).toBe(true)
+ })
+
+ test('chance(2) distribution', () => {
+ const N = 1e4
+ const TRIES = 3
+ const XSQ = 3.84 // quantile of chi-square dist. k=1, p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(2)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.chance(2)
+ if (tmp === true) {
+ tmp = 1
+ } else if (tmp === false) {
+ tmp = 0
+ } else {
+ throw new Error(`Unexpected random.chance() result: ${tmp}`)
+ }
+ ++bins[tmp]
+ }
+ let xsq = bins.reduce((a, v) => {
+ let e = N / bins.length
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 1)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": " + tries)
+ return false
+ }
+
+ expect(_test()).toBe(true)
+ })
+
+ test('chance(3) distribution', () => {
+ const N = 1e4
+ const TRIES = 3
+ const XSQ = 3.84 // quantile of chi-square dist. k=1, p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(2)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.chance(3)
+ if (tmp === true) {
+ tmp = 0
+ } else if (tmp === false) {
+ tmp = 1
+ } else {
+ throw new Error(`Unexpected random.chance() result: ${tmp}`)
+ }
+ ++bins[tmp]
+ }
+ let xsq =
+ Math.pow(bins[0] - N / 3, 2) / (N / 3) +
+ Math.pow(bins[1] - (2 * N) / 3, 2) / ((2 * N) / 3)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 1)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": " + tries)
+ return false
+ }
+
+ expect(_test()).toBe(true)
+ })
+
+ test('chance(1000) distribution', () => {
+ const N = 1e6
+ const TRIES = 3
+ const XSQ = 3.84 // quantile of chi-square dist. k=1, p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(2)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.chance(1000)
+ if (tmp === true) {
+ tmp = 0
+ } else if (tmp === false) {
+ tmp = 1
+ } else {
+ throw new Error(`Unexpected random.chance() result: ${tmp}`)
+ }
+ ++bins[tmp]
+ }
+ let xsq =
+ Math.pow(bins[0] - N / 1000, 2) / (N / 1000) +
+ Math.pow(bins[1] - (999 * N) / 1000, 2) / ((999 * N) / 1000)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 1)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": " + tries)
+ return false
+ }
+
+ expect(_test()).toBe(true)
+ })
+
+ test('choose() with equal distribution', () => {
+ const N = 1e4
+ const TRIES = 3
+ const XSQ = 5.99 // quantile of chi-square dist. k=2, p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(3)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.choose([[1, 0], [1, 1], [1, 2]])
+ expect(tmp).toBeLessThan(bins.length)
+ ++bins[tmp]
+ }
+ let xsq = bins.reduce((a, v) => {
+ let e = N / bins.length
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 2)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": " + tries)
+ return false
+ }
+
+ expect(_test()).toBe(true)
+ })
+
+ test('choose() with unequal distribution', () => {
+ const N = 1e4
+ const TRIES = 3
+ const XSQ = 5.99 // quantile of chi-square dist. k=2, p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(3)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.choose([[1, 0], [2, 1], [1, 2]])
+ expect(tmp).toBeLessThan(bins.length)
+ ++bins[tmp]
+ }
+ let xsq =
+ Math.pow(bins[0] - N / 4, 2) / (N / 4) +
+ Math.pow(bins[1] - N / 2, 2) / (N / 2) +
+ Math.pow(bins[2] - N / 4, 2) / (N / 4)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 2)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": " + tries)
+ return false
+ }
+
+ expect(_test()).toBe(true)
+ })
+
+ test('choose(flat) equal distribution with types not picked', () => {
+ const N = 1e4
+ const TRIES = 3
+ const XSQ = 5.99 // quantile of chi-square dist. k=2, p=.05
+ const v1 = 1
+ const v2 = [12]
+ const v3 = () => {}
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(3)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.choose([[1, v1], [1, v2], [1, v3]], true)
+ if (tmp === v1) {
+ tmp = 0
+ } else if (tmp === v2) {
+ tmp = 1
+ } else if (tmp === v3) {
+ tmp = 2
+ } else {
+ throw new Error(`Unexpected random.choose() result: ${tmp}`)
+ }
+ ++bins[tmp]
+ }
+ let xsq = bins.reduce((a, v) => {
+ let e = N / bins.length
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 2)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": " + tries)
+ return false
+ }
+
+ expect(_test()).toBe(true)
+ })
+
+ test('weighted() with equal distribution', () => {
+ const N = 1e4
+ const TRIES = 3
+ const XSQ = 5.99 // quantile of chi-square dist. k=2, p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(3)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.item(random.weighted([{ w: 1, v: 0 }, { w: 1, v: 1 }, { w: 1, v: 2 }]))
+ expect(tmp).toBeLessThan(bins.length)
+ ++bins[tmp]
+ }
+ let xsq = bins.reduce((a, v) => {
+ let e = N / bins.length
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 2)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": " + tries)
+ return false
+ }
+
+ expect(_test()).toBe(true)
+ })
+
+ test('choose(flat) with unequal distribution', () => {
+ const N = 1e4
+ const TRIES = 3
+ const XSQ = 5.99 // quantile of chi-square dist. k=2, p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(3)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.choose([[1, 0], [2, 1], [1, 2]], true)
+ expect(tmp).toBeLessThan(bins.length)
+ ++bins[tmp]
+ }
+ let xsq =
+ Math.pow(bins[0] - N / 4, 2) / (N / 4) +
+ Math.pow(bins[1] - N / 2, 2) / (N / 2) +
+ Math.pow(bins[2] - N / 4, 2) / (N / 4)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 2)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": " + tries)
+ return false
+ }
+
+ expect(_test()).toBe(true)
+ })
+
+ test('weighted() with unequal distribution', () => {
+ const N = 1e4
+ const TRIES = 3
+ const XSQ = 5.99 // quantile of chi-square dist. k=2, p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(3)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.item(random.weighted([{ w: 1, v: 0 }, { w: 2, v: 1 }, { w: 1, v: 2 }]))
+ expect(tmp).toBeLessThan(bins.length)
+ ++bins[tmp]
+ }
+ let xsq =
+ Math.pow(bins[0] - N / 4, 2) / (N / 4) +
+ Math.pow(bins[1] - N / 2, 2) / (N / 2) +
+ Math.pow(bins[2] - N / 4, 2) / (N / 4)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 2)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": " + tries)
+ return false
+ }
+
+ expect(_test()).toBe(true)
+ })
+
+ test('weighted() equal distribution with types not picked', () => {
+ const N = 1e4
+ const TRIES = 3
+ const XSQ = 5.99 // quantile of chi-square dist. k=2, p=.05
+ const v1 = 1
+ const v2 = [12]
+ const v3 = () => {}
+
+ random.init(Math.random() * 0x100000000)
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(3)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.item(
+ random.weighted([{ w: 1, v: v1 }, { w: 1, v: v2 }, { w: 1, v: v3 }])
+ )
+ if (tmp === v1) {
+ tmp = 0
+ } else if (tmp === v2) {
+ tmp = 1
+ } else if (tmp === v3) {
+ tmp = 2
+ } else {
+ throw new Error(`Unexpected random.weighted() result: ${tmp}`)
+ }
+ ++bins[tmp]
+ }
+ let xsq = bins.reduce((a, v) => {
+ let e = N / bins.length
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 2)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
+ return false
+ }
+ expect(_test()).toBe(true)
+ })
+
+ test('choose() with unequal distribution and pick', () => {
+ const N = 1e4
+ const TRIES = 3
+ const XSQ = 5.99 // quantile of chi-square dist. k=2, p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(3)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.choose([
+ [1, 0],
+ [2, [1, 2]],
+ [
+ 1,
+ () => 2
+ ]
+ ])
+ expect(tmp).toBeGreaterThanOrEqual(0)
+ expect(tmp).toBeLessThan(bins.length)
+ ++bins[tmp]
+ }
+ let xsq =
+ Math.pow(bins[0] - N / 4, 2) / (N / 4) +
+ Math.pow(bins[1] - N / 4, 2) / (N / 4) +
+ Math.pow(bins[2] - N / 2, 2) / (N / 2)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 2)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
+ return false
+ }
+ expect(_test()).toBe(true)
+ })
+
+ test('weighted() equal distribution with types not picked', () => {
+ const N = 1e4
+ const TRIES = 3
+ const XSQ = 5.99 // quantile of chi-square dist. k=2, p=.05
+ const v1 = 1
+ const v2 = [12]
+ const v3 = () => {}
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(3)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.item(
+ random.weighted([{ w: 1, v: v1 }, { w: 1, v: v2 }, { w: 1, v: v3 }])
+ )
+ if (tmp === v1) {
+ tmp = 0
+ } else if (tmp === v2) {
+ tmp = 1
+ } else if (tmp === v3) {
+ tmp = 2
+ } else {
+ throw new Error(`Unexpected random.weighted() result: ${tmp}`)
+ }
+ ++bins[tmp]
+ }
+ let xsq = bins.reduce((a, v) => {
+ let e = N / bins.length
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 2)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
+ return false
+ }
+ expect(_test()).toBe(true)
+ })
+
+ test('use() distribution', () => {
+ const N = 1e4
+ const TRIES = 3
+ const XSQ = 3.84 // quantile of chi-square dist. k=1, p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(2)
+ for (let i = 0; i < N; ++i) {
+ let rnd = Math.random()
+ let use = random.use(rnd)
+ if (use === rnd) {
+ use = 1
+ } else if (use === '') {
+ use = 0
+ } else {
+ throw new Error(`Unexpected random.use() result: ${use}`)
+ }
+ ++bins[use]
+ }
+ let xsq = bins.reduce((a, v) => {
+ let e = N / bins.length
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 1)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
+ return false
+ }
+ expect(_test()).toBe(true)
+ })
+
+ test('shuffle() distribution', () => {
+ const N = 1e4
+ const M = 10
+ const TRIES = 3
+ const XSQ = 123.23 // quantile of chi-square dist. k=M*M-1, p=.05
+ // XXX: shouldn't k be M! ?
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(M * M)
+ for (let i = 0; i < N; ++i) {
+ let array = []
+ for (let j = 0; j < M; ++j) array.push(j)
+ random.shuffle(array)
+ for (let j = 0; j < M; ++j) ++bins[j * M + array[j]]
+ }
+ let xsq = bins.reduce((a, v) => {
+ let e = N / M
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 99)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
+ return false
+ }
+
+ expect(_test()).toBe(true)
+ })
+
+ test('shuffled() distribution', () => {
+ const N = 1e4
+ const M = 10
+ const TRIES = 3
+ const XSQ = 123.23 // quantile of chi-square dist. k=M*M-1, p=.05
+ // XXX: shouldn't k be M! ?
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(M * M)
+ let array_ref = []
+ for (let j = 0; j < M; ++j) {
+ array_ref.push(j)
+ }
+ for (let i = 0; i < N; ++i) {
+ let array = random.shuffled(array_ref)
+ for (let j = 0; j < M; ++j) {
+ ++bins[j * M + array[j]]
+ expect(array_ref[j]).toEqual(j)
+ }
+ let xsq = bins.reduce((a, v) => {
+ let e = N / M
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 99)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
+ return false
+ }
+
+ expect(_test()).toBe(true)
+ })
+
+ test.skip('subset() with equal distribution', () => {
+ /*
+ * This doesn't specify limit, so length distribution should be even,
+ * and selections should be even within each length.
+ */
+ const N = 1e4
+ const M = 3
+ const TRIES = 3
+ const B0_XSQ = 5.99
+ const B1_XSQ = 15.51
+ const B2_XSQ = 38.89
+ const LEN_XSQ = 7.81 // quantile of chi-square dist. k=[2,8,26,3], p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let bin0_xsq, bin1_xsq, bin2_xsq, length_xsq
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = [new Uint32Array(3), new Uint32Array(9), new Uint32Array(27)]
+ let lengths = new Uint32Array(M + 1)
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.subset([
+ 0,
+ [1, 1],
+ () => 2
+ ])
+ expect(tmp.length).toBeLessThanOrEqual(M)
+ ++lengths[tmp.length]
+ if (tmp.length) {
+ ++bins[tmp.length - 1][tmp.reduce((a, v) => a * 3 + v, 0)]
+ }
+ }
+ bin0_xsq = bins[0].reduce((a, v) => {
+ let e = N / (M + 1) / Math.pow(M, 1)
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ bin1_xsq = bins[1].reduce((a, v) => {
+ let e = N / (M + 1) / Math.pow(M, 2)
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ bin2_xsq = bins[2].reduce((a, v) => {
+ let e = N / (M + 1) / Math.pow(M, 3)
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ length_xsq = lengths.reduce((a, v) => {
+ let e = N / (M + 1)
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 2)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (bin0_xsq < B0_XSQ && bin1_xsq < B1_XSQ && bin2_xsq < B2_XSQ && length_xsq < LEN_XSQ) {
+ console.log(`Expected lengths x^2 to be < ${LEN_XSQ} got ${length_xsq} on attempt #${attempt + 1}`)
+ console.log(`Expected length=1 x^2 to be < ${B0_XSQ} got ${bin0_xsq} on attempt # ${attempt + 1}`)
+ console.log(`Expected length=2 x^2 to be < ${B1_XSQ} got ${bin1_xsq} on attempt #${attempt + 1}`)
+ console.log(`Expected length=3 x^2 to be < ${B2_XSQ} got ${bin2_xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ }
+ console.log(`Expected lengths x^2 to be < ${LEN_XSQ} got ${length_xsq}`)
+ console.log(`Expected length=1 x^2 to be < ${B0_XSQ} got ${bin0_xsq}`)
+ console.log(`Expected length=2 x^2 to be < ${B1_XSQ} got ${bin1_xsq}`)
+ console.log(`Expected length=3 x^2 to be < ${B2_XSQ} got ${bin2_xsq}`)
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq low enough");
+ return false
+ }
+
+ expect(_test()).toBe(true)
+ })
+
+ test.skip('subset(limit) with equal distribution', () => {
+ /*
+ * limit is specified, so length should always == limit, and selections should be even
+ */
+ const N = 1e4
+ const M = 3
+ const TRIES = 3
+ const B0_XSQ = 5.99
+ const B1_XSQ = 15.51
+ const B2_XSQ = 38.89
+ const B3_XSQ = 101.88 // quantile of chi-square dist. k=[2,8,26,80], p=.05
+
+ let bin0_xsq, bin1_xsq, bin2_xsq, bin3_xsq
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ for (let attempt = 0; attempt < 100; ++attempt) {
+ expect(random.subset([1, 2, 3], 0).length).toBe(0)
+ }
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = [
+ new Uint32Array(3),
+ new Uint32Array(9),
+ new Uint32Array(27),
+ new Uint32Array(81)
+ ]
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.subset([0, 1, 2], 1)
+ expect(tmp.length).toBe(1)
+
+ ++bins[0][tmp.reduce((a, v) => a * 3 + v, 0)]
+ tmp = random.subset([0, 1, 2], 2)
+ expect(tmp.length).toBe(2)
+
+ ++bins[1][tmp.reduce((a, v) => a * 3 + v, 0)]
+ tmp = random.subset([0, 1, 2], 3)
+ expect(tmp.length).toBe(3)
+
+ ++bins[2][tmp.reduce((a, v) => a * 3 + v, 0)]
+ tmp = random.subset([0, 1, 2], 4)
+ expect(tmp.length).toBe(4)
+
+ ++bins[3][tmp.reduce((a, v) => a * 3 + v, 0)]
+ }
+ bin0_xsq = bins[0].reduce((a, v) => {
+ let e = N / Math.pow(M, 1)
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ bin1_xsq = bins[1].reduce((a, v) => {
+ let e = N / Math.pow(M, 2)
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ bin2_xsq = bins[2].reduce((a, v) => {
+ let e = N / Math.pow(M, 3)
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ bin3_xsq = bins[3].reduce((a, v) => {
+ let e = N / Math.pow(M, 4)
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 2)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (bin0_xsq < B0_XSQ && bin1_xsq < B1_XSQ && bin2_xsq < B2_XSQ && bin3_xsq < B3_XSQ) {
+ // assert.ok(true, "Expected length=1 x^2 to be < " + B0_XSQ + ", got " + bin0_xsq + " on attempt #" + (attempt + 1));
+ // assert.ok(true, "Expected length=2 x^2 to be < " + B1_XSQ + ", got " + bin1_xsq);
+ // assert.ok(true, "Expected length=3 x^2 to be < " + B2_XSQ + ", got " + bin2_xsq);
+ // assert.ok(true, "Expected length=4 x^2 to be < " + B3_XSQ + ", got " + bin3_xsq);
+ return true
+ }
+ }
+ console.log(`Expected length=1 x^2 to be < ${B0_XSQ} got ${bin0_xsq}`)
+ console.log(`Expected length=2 x^2 to be < ${B1_XSQ} got ${bin1_xsq}`)
+ console.log(`Expected length=3 x^2 to be < ${B2_XSQ} got ${bin2_xsq}`)
+ console.log(`Expected length=4 x^2 to be < ${B3_XSQ} got ${bin3_xsq}`)
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq low enough");
+ return false
+ }
+ expect(_test()).toBe(true)
+ })
+
+ test('pop() distribution', () => {
+ const N = 1e4
+ const TRIES = 3
+ const XSQ = 5.99 // quantile of chi-square dist. k=2, p=.05
+
+ random.init(Math.random() * 0x100000000)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(3)
+ const orig = [99, 100, 101]
+ for (let i = 0; i < N; ++i) {
+ let arr = orig.slice()
+ let tmp = random.pop(arr) - 99
+ expect(tmp).toBeGreaterThanOrEqual(0)
+ expect(tmp).toBeLessThan(bins.length)
+ expect(arr.length).toBe(2)
+ expect(arr.reduce((a, v) => { return a + v }, tmp)).toBe(201)
+ ++bins[tmp]
+ }
+ let xsq = bins.reduce((a, v) => {
+ let e = N / bins.length
+ return a + Math.pow(v - e, 2) / e
+ }, 0)
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 2)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
+ return false
+ }
+ expect(_test()).toBe(true)
+ })
+
+ test('ludOneTo() distribution', () => {
+ const N = 1e5
+ const TRIES = 3
+ const XSQ = 123.22 // quantile of chi-square dist. k=99, p=.05
+ let dist = new Uint32Array(100)
+
+ random.init(Math.random() * 0x100000000)
+
+ /* Build the ideal distribution for comparison
+ * I thought this would be the PDF of the log-normal distribution, but I couldn't get mu & sigma figured out? */
+ for (let i = 0; i < 100 * dist.length; ++i) {
+ dist[Math.floor(Math.exp((i / (100 * dist.length)) * Math.log(dist.length)))] +=
+ N / (dist.length * 100)
+ }
+ expect(dist[0]).toEqual(0)
+
+ const _test = () => {
+ let tries = []
+ for (let attempt = 0; attempt < TRIES; ++attempt) {
+ let bins = new Uint32Array(dist.length)
+ let xsq = 0
+ for (let i = 0; i < N; ++i) {
+ let tmp = random.ludOneTo(bins.length) >>> 0
+ expect(tmp).toBeLessThan(bins.length)
+ ++bins[tmp]
+ }
+ expect(bins[0]).toEqual(0)
+
+ for (let i = 1; i < bins.length; ++i) {
+ xsq += Math.pow(bins[i] - dist[i], 2) / dist[i]
+ }
+ /*
+ * XSQ = scipy.stats.chi2.isf(.05, 99)
+ * if xsq > XSQ, the result is biased at 95% significance
+ */
+ if (xsq < XSQ) {
+ console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
+ return true
+ }
+ tries.push(xsq)
+ }
+ // assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
+ return false
+ }
+ expect(_test()).toBe(true)
+ })
+})
diff --git a/package.json b/package.json
index a79946f..0ef0dc2 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "@mozillasecurity/octo",
"version": "1.0.15",
- "description": "",
+ "description": "A unified shared library which aids in building fuzzers for browsers or as complement for an existing fuzzing framework.",
"keywords": [
"fuzzing",
"browser",
@@ -9,7 +9,7 @@
"node",
"library"
],
- "homepage": "https://github.com/mozillasecurity/octo/tree/es6",
+ "homepage": "https://github.com/mozillasecurity/octo",
"repository": {
"type": "git",
"url": "https://github.com/mozillasecurity/octo.git"
@@ -21,19 +21,18 @@
"author": "Christoph Diehl ",
"license": "MPL-2.0",
"scripts": {
- "test": "grunt test --verbose",
- "test:lint": "cross-env NODE_ENV=test standard --verbose",
- "test:lint:fix": "cross-env NODE_ENV=test standard --fix --verbose",
- "docs": "esdoc -c esdoc.json",
+ "test": "jest --silent",
+ "lint": "cross-env NODE_ENV=test standard --verbose",
+ "lint:fix": "cross-env NODE_ENV=test standard --fix --verbose",
+ "docs": "esdoc",
"build": "webpack -p",
"watch": "webpack --watch",
- "precommit": "npm run test:lint",
- "postinstall": "npm run build",
+ "precommit": "yarn lint",
+ "postinstall": "yarn build",
"release": "np"
},
"standard": {
"ignore": [
- "tests/**",
"dist/"
],
"envs": {
@@ -42,29 +41,42 @@
"es6": true
}
},
+ "jest": {
+ "verbose": true
+ },
+ "esdoc": {
+ "source": "./lib",
+ "destination": "./docs",
+ "plugins": [
+ {
+ "name": "esdoc-standard-plugin",
+ "option": {
+ "lint": {
+ "enable": true
+ },
+ "coverage": {
+ "enable": true
+ }
+ }
+ },
+ {
+ "name": "esdoc-node"
+ }
+ ]
+ },
"devDependencies": {
"cross-env": "^5.1.4",
"esdoc": "^1.1.0",
"esdoc-node": "^1.0.3",
"esdoc-standard-plugin": "^1.0.0",
- "grunt": "*",
- "grunt-karma": "*",
- "grunt-karma-coveralls": "*",
- "grunt-standard": "*",
"husky": "^0.14.3",
- "karma": "*",
- "karma-chrome-launcher": "*",
- "karma-coverage": "*",
- "karma-firefox-launcher": "^1.1.0",
- "karma-qunit": "^2.0.1",
+ "jest": "^23.5.0",
"np": "^3.0.4",
- "qunit": "^2.5.1",
- "qunitjs": "^2.4.1",
- "standard": "^11.0.1"
+ "standard": "^11.0.1",
+ "webpack": "^4.1.1",
+ "webpack-cli": "^3.1.0"
},
"dependencies": {
- "jsesc": "^2.5.1",
- "webpack": "^4.1.1",
- "webpack-cli": "^2.0.12"
+ "jsesc": "^2.5.1"
}
}
diff --git a/tests/index.html b/tests/index.html
deleted file mode 100644
index 3cb6f54..0000000
--- a/tests/index.html
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-
-
-
-
-
- Octo Unit Tests
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tests/random/mersennetwister.js b/tests/random/mersennetwister.js
deleted file mode 100644
index 9f55a6b..0000000
--- a/tests/random/mersennetwister.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-QUnit.test("MersenneTwister test uniform distribution", function(assert) {
- const N = Math.pow(2, 18), TRIES = 10, XSQ = 293.25; // quantile of chi-square dist. k=255, p=.05
- let mt = new MersenneTwister();
- mt.seed(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let data = new Uint32Array(N), sh;
- for (let i = 0; i < data.length; ++i) {
- data[i] = mt.int32();
- }
- for (sh = 0; sh <= 24; ++sh) {
- let bins = new Uint32Array(256);
- for (let b of data) {
- ++bins[(b >>> sh) & 0xFF];
- }
- let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 255)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq >= XSQ)
- break;
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- }
- if (sh == 25) {
- return;
- }
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ);
-});
-
-QUnit.test("MersenneTwister test float distribution", function(assert) {
- const N = Math.pow(2, 18), TRIES = 3, XSQ = 564.7; // quantile of chi-square dist. k=511, p=.05
- let tries = [], mt = new MersenneTwister();
- mt.seed(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(512);
- for (let i = 0; i < N; ++i) {
- let tmp = (mt.real2() * bins.length) >>> 0;
- if (tmp >= bins.length) throw "random.float() >= 1.0";
- ++bins[tmp];
- }
- let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 511)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
diff --git a/tests/random/random.js b/tests/random/random.js
deleted file mode 100644
index bc0a4eb..0000000
--- a/tests/random/random.js
+++ /dev/null
@@ -1,892 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-QUnit.test("random.init() is required", function(assert) {
- assert.throws(random.number, /undefined/, "twister should be uninitialized before random.init()");
- random.init(1);
- random.number();
-});
-
-QUnit.test("random.number() corner cases", function(assert) {
- random.init(Math.random() * 0x100000000);
- let sum = 0;
- for (let i = 0; i < 100; ++i)
- sum += random.number(0);
- assert.equal(sum, 0);
- for (let i = 0; i < 100; ++i)
- sum += random.number(1);
- assert.equal(sum, 0);
- let bins = new Uint32Array(2);
- for (let i = 0; i < 100; ++i)
- ++bins[random.number(2)];
- assert.equal(bins[0] + bins[1], 100);
- assert.ok(bins[0] > 20);
- sum = 0;
- for (let i = 0; i < 15; ++i)
- sum |= random.number();
- assert.equal(sum>>>0, 0xFFFFFFFF);
-});
-
-QUnit.test("random.number() uniform distribution", function(assert) {
- const N = Math.pow(2, 17), TRIES = 3, XSQ = 564.7; // quantile of chi-square dist. k=511, p=.05
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(512);
- for (let i = 0; i < N; ++i) {
- let tmp = random.number(bins.length);
- if (tmp >= bins.length) throw "random.number() >= limit";
- ++bins[tmp];
- }
- let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 511)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.float() uniform distribution", function(assert) {
- const N = Math.pow(2, 17), TRIES = 3, XSQ = 564.7; // quantile of chi-square dist. k=511, p=.05
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(512);
- for (let i = 0; i < N; ++i) {
- let tmp = (random.float() * bins.length) >>> 0;
- if (tmp >= bins.length) throw "random.float() >= 1.0";
- ++bins[tmp];
- }
- let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 511)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.range() uniform distribution", function(assert) {
- const N = 1e4, TRIES = 3, XSQ = 66.34; // quantile of chi-square dist. k=49, p=.05
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(50);
- for (let i = 0; i < N; ++i) {
- let tmp = random.range(0, bins.length - 1);
- if (tmp >= bins.length) throw "random.range() > upper bound";
- ++bins[tmp];
- }
- let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 49)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.range() uniform distribution with offset", function(assert) {
- const N = 1e4, TRIES = 3, XSQ = 66.34; // quantile of chi-square dist. k=49, p=.05
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(50);
- for (let i = 0; i < N; ++i) {
- let tmp = random.range(10, 10 + bins.length - 1) - 10;
- if (tmp < 0) throw "random.range() < lower bound";
- if (tmp >= bins.length) throw "random.range() > upper bound";
- ++bins[tmp];
- }
- let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 49)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.range() PRNG reproducibility", function(assert) {
- let seed, result1, result2;
- seed = Math.random() * 0x100000000;
- for (let t = 0; t < 50; ++t) {
- random.init(seed);
- result1 = random.range(1, 20);
- for (let i = 0; i < 5; ++i) {
- random.init(seed);
- result2 = random.range(1, 20);
- assert.equal(result1, result2, "both results are the same")
- }
- seed = random.number();
- }
-});
-
-QUnit.test("random.ludOneTo() distribution", function(assert) {
- const N = 1e5, TRIES = 3, XSQ = 123.22; // quantile of chi-square dist. k=99, p=.05
- let dist = new Uint32Array(100), tries = [];
- random.init(Math.random() * 0x100000000);
- /* build the ideal distribution for comparison
- * I thought this would be the PDF of the log-normal distribution, but I couldn't get mu & sigma figured out? */
- for (let i = 0; i < (100 * dist.length); ++i) {
- dist[Math.floor(Math.exp(i / (100*dist.length) * Math.log(dist.length)))] += N / (dist.length * 100);
- }
- assert.equal(dist[0], 0);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(dist.length), xsq = 0;
- for (let i = 0; i < N; ++i) {
- let tmp = random.ludOneTo(bins.length)>>>0;
- if (tmp >= bins.length) throw "random.ludOneTo() > upper bound"; // this could happen..
- ++bins[tmp];
- }
- assert.equal(bins[0], 0);
- for (let i = 1; i < bins.length; ++i) {
- xsq += Math.pow(bins[i] - dist[i], 2) / dist[i];
- }
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 99)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.item() exception cases", function(assert) {
- assert.throws(random.item, /received an invalid object/);
- assert.throws(function(){ return random.item(1); }, /received an invalid object/);
- assert.throws(function(){ return random.item("1"); }, /received an invalid object/);
- assert.throws(function(){ return random.item({}); }, /received an invalid object/);
-});
-
-QUnit.test("random.item() distribution with list", function(assert) {
- const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(3);
- for (let i = 0; i < N; ++i) {
- let tmp = random.item([99, 100, 101]) - 99;
- if (tmp < 0) throw "random.item() < lower bound";
- if (tmp >= bins.length) throw "random.item() > upper bound";
- ++bins[tmp];
- }
- let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 2)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.key() distribution", function(assert) {
- const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(3);
- for (let i = 0; i < N; ++i) {
- let tmp = random.key({99: 0, 100: 0, 101: 0}) - 99;
- if (tmp < 0) throw "random.key() < lower bound";
- if (tmp >= bins.length) throw "random.key() > upper bound";
- ++bins[tmp];
- }
- let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 2)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.bool() distribution", function(assert) {
- const N = 1e4, TRIES = 3, XSQ = 3.84; // quantile of chi-square dist. k=1, p=.05
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(2);
- for (let i = 0; i < N; ++i) {
- let tmp = random.bool();
- if (tmp === true)
- tmp = 1;
- else if (tmp === false)
- tmp = 0;
- else
- assert.ok(false, "unexpected random.bool() result: " + tmp);
- ++bins[tmp];
- }
- let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 1)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.pick() cases", function(assert) {
- random.init(Math.random() * 0x100000000);
- for (let i = 0; i < 100; ++i) {
- let tmp = Math.random();
- assert.equal(tmp, random.pick(tmp));
- }
- for (let i = 0; i < 100; ++i) {
- let tmp = (Math.random() * 100) >>> 0;
- assert.equal(tmp, random.pick(tmp));
- }
- for (let i = 0; i < 100; ++i) {
- let tmp = Math.random() + "";
- assert.equal(tmp, random.pick(tmp));
- }
- for (let i = 0; i < 100; ++i) {
- let tmp = Math.random();
- assert.equal(tmp, random.pick([tmp]));
- }
- for (let i = 0; i < 100; ++i) {
- let tmp = Math.random();
- assert.equal(tmp, random.pick(function(){ return tmp; }));
- }
- for (let i = 0; i < 100; ++i) {
- let tmp = Math.random();
- assert.equal(tmp, random.pick(function(){ return [tmp]; }));
- }
-});
-
-QUnit.test("random.pick() with equal distribution", function(assert) {
- const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(3);
- for (let i = 0; i < N; ++i) {
- let tmp = random.pick([0, [1, 1], function(){ return 2; }]);
- if (tmp < 0) throw "random.pick() < lower bound";
- if (tmp >= bins.length) throw "random.pick() > upper bound";
- ++bins[tmp];
- }
- let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 2)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.pick() with unequal distribution", function(assert) {
- const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(3);
- for (let i = 0; i < N; ++i) {
- let tmp = random.pick([[0, 1], [1], function(){ return [2]; }]);
- if (tmp < 0) throw "random.pick() < lower bound";
- if (tmp >= bins.length) throw "random.pick() > upper bound";
- ++bins[tmp];
- }
- let xsq = Math.pow(bins[0] - N / 6, 2) / (N / 6) + Math.pow(bins[1] - N / 2, 2) / (N / 2) + Math.pow(bins[2] - N / 3, 2) / (N / 3);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 2)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.chance(2) distribution", function(assert) {
- const N = 1e4, TRIES = 3, XSQ = 3.84; // quantile of chi-square dist. k=1, p=.05
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(2);
- for (let i = 0; i < N; ++i) {
- let tmp = random.chance(2);
- if (tmp === true)
- tmp = 1;
- else if (tmp === false)
- tmp = 0;
- else
- assert.ok(false, "unexpected random.chance() result: " + tmp);
- ++bins[tmp];
- }
- let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 1)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.chance(undefined) distribution", function(assert) {
- const N = 1e4, TRIES = 3, XSQ = 3.84; // quantile of chi-square dist. k=1, p=.05
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(2);
- for (let i = 0; i < N; ++i) {
- let tmp = random.chance();
- if (tmp === true)
- tmp = 1;
- else if (tmp === false)
- tmp = 0;
- else
- assert.ok(false, "unexpected random.chance() result: " + tmp);
- ++bins[tmp];
- }
- let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 1)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.chance(3) distribution", function(assert) {
- const N = 1e4, TRIES = 3, XSQ = 3.84; // quantile of chi-square dist. k=1, p=.05
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(2);
- for (let i = 0; i < N; ++i) {
- let tmp = random.chance(3);
- if (tmp === true)
- tmp = 0;
- else if (tmp === false)
- tmp = 1;
- else
- assert.ok(false, "unexpected random.chance() result: " + tmp);
- ++bins[tmp];
- }
- let xsq = Math.pow(bins[0] - (N / 3), 2) / (N / 3) + Math.pow(bins[1] - (2 * N / 3), 2) / (2 * N / 3);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 1)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.chance(1000) distribution", function(assert) {
- const N = 1e6, TRIES = 3, XSQ = 3.84; // quantile of chi-square dist. k=1, p=.05
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(2);
- for (let i = 0; i < N; ++i) {
- let tmp = random.chance(1000);
- if (tmp === true)
- tmp = 0;
- else if (tmp === false)
- tmp = 1;
- else
- assert.ok(false, "unexpected random.chance() result: " + tmp);
- ++bins[tmp];
- }
- let xsq = Math.pow(bins[0] - (N / 1000), 2) / (N / 1000) + Math.pow(bins[1] - (999 * N / 1000), 2) / (999 * N / 1000);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 1)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.choose() with equal distribution", function(assert) {
- const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(3);
- for (let i = 0; i < N; ++i) {
- let tmp = random.choose([[1, 0], [1, 1], [1, 2]]);
- if (tmp >= bins.length) throw "random.choose() > upper bound";
- ++bins[tmp];
- }
- let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 2)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.choose() with unequal distribution", function(assert) {
- const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(3);
- for (let i = 0; i < N; ++i) {
- let tmp = random.choose([[1, 0], [2, 1], [1, 2]]);
- if (tmp >= bins.length) throw "random.choose() > upper bound";
- ++bins[tmp];
- }
- let xsq = Math.pow(bins[0] - N / 4, 2) / (N / 4) + Math.pow(bins[1] - N / 2, 2) / (N / 2) + Math.pow(bins[2] - N / 4, 2) / (N / 4);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 2)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.choose() with unequal distribution and pick", function(assert) {
- const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(3);
- for (let i = 0; i < N; ++i) {
- let tmp = random.choose([[1, 0], [2, [1, 2]], [1, function(){ return 2; }]]);
- if (tmp >= bins.length) throw "random.choose() > upper bound";
- ++bins[tmp];
- }
- let xsq = Math.pow(bins[0] - N / 4, 2) / (N / 4) + Math.pow(bins[1] - N / 4, 2) / (N / 4) + Math.pow(bins[2] - N / 2, 2) / (N / 2);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 2)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.choose(flat) with unequal distribution", function(assert) {
- const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(3);
- for (let i = 0; i < N; ++i) {
- let tmp = random.choose([[1, 0], [2, 1], [1, 2]], true);
- if (tmp >= bins.length) throw "random.choose() > upper bound";
- ++bins[tmp];
- }
- let xsq = Math.pow(bins[0] - N / 4, 2) / (N / 4) + Math.pow(bins[1] - N / 2, 2) / (N / 2) + Math.pow(bins[2] - N / 4, 2) / (N / 4);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 2)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.choose(flat) equal distribution with types not picked", function(assert) {
- const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
- const v1 = 1, v2 = [12], v3 = function(){};
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(3);
- for (let i = 0; i < N; ++i) {
- let tmp = random.choose([[1, v1], [1, v2], [1, v3]], true);
- if (tmp === v1)
- tmp = 0;
- else if (tmp === v2)
- tmp = 1;
- else if (tmp === v3)
- tmp = 2;
- else
- assert.ok(false, "unexpected random.choose() result: " + tmp);
- ++bins[tmp];
- }
- let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 2)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.weighted() with equal distribution", function(assert) {
- const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(3);
- for (let i = 0; i < N; ++i) {
- let tmp = random.item(random.weighted([{w: 1, v: 0}, {w: 1, v: 1}, {w: 1, v: 2}]));
- if (tmp >= bins.length) throw "random.weighted() > upper bound";
- ++bins[tmp];
- }
- let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 2)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.weighted() with unequal distribution", function(assert) {
- const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(3);
- for (let i = 0; i < N; ++i) {
- let tmp = random.item(random.weighted([{w: 1, v: 0}, {w: 2, v: 1}, {w: 1, v: 2}]));
- if (tmp >= bins.length) throw "random.weighted() > upper bound";
- ++bins[tmp];
- }
- let xsq = Math.pow(bins[0] - N / 4, 2) / (N / 4) + Math.pow(bins[1] - N / 2, 2) / (N / 2) + Math.pow(bins[2] - N / 4, 2) / (N / 4);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 2)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.weighted() equal distribution with types not picked", function(assert) {
- const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
- const v1 = 1, v2 = [12], v3 = function(){};
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(3);
- for (let i = 0; i < N; ++i) {
- let tmp = random.item(random.weighted([{w: 1, v: v1}, {w: 1, v: v2}, {w: 1, v: v3}]));
- if (tmp === v1)
- tmp = 0;
- else if (tmp === v2)
- tmp = 1;
- else if (tmp === v3)
- tmp = 2;
- else
- assert.ok(false, "unexpected random.weighted() result: " + tmp);
- ++bins[tmp];
- }
- let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 2)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.use() distribution", function(assert) {
- const N = 1e4, TRIES = 3, XSQ = 3.84; // quantile of chi-square dist. k=1, p=.05
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(2);
- for (let i = 0; i < N; ++i) {
- let rnd = Math.random(), use = random.use(rnd);
- if (use === rnd)
- use = 1;
- else if (use === "")
- use = 0;
- else
- assert.ok(false, "unexpected random.use() result: " + use);
- ++bins[use];
- }
- let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 1)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.shuffle() distribution", function(assert) {
- const N = 1e4, M = 10, TRIES = 3, XSQ = 123.23; // quantile of chi-square dist. k=M*M-1, p=.05
- // XXX: shouldn't k be M! ?
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(M * M);
- for (let i = 0; i < N; ++i) {
- let array = [];
- for (let j = 0; j < M; ++j)
- array.push(j);
- random.shuffle(array);
- for (let j = 0; j < M; ++j)
- ++bins[j * M + array[j]];
- }
- let xsq = bins.reduce(function(a, v){ let e = N / M; return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 99)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.shuffled() distribution", function(assert) {
- const N = 1e4, M = 10, TRIES = 3, XSQ = 123.23; // quantile of chi-square dist. k=M*M-1, p=.05
- // XXX: shouldn't k be M! ?
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(M * M);
- let array_ref = [];
- for (let j = 0; j < M; ++j)
- array_ref.push(j);
- for (let i = 0; i < N; ++i) {
- let array = random.shuffled(array_ref);
- for (let j = 0; j < M; ++j) {
- ++bins[j * M + array[j]];
- if (array_ref[j] !== j)
- throw "array modified";
- }
- }
- let xsq = bins.reduce(function(a, v){ let e = N / M; return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 99)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
-
-QUnit.test("random.subset() with equal distribution", function(assert) {
- /*
- * this doesn't specify limit, so length distribution should be even, and selections should be even within each length
- */
- const N = 1e4, M = 3, TRIES = 3, B0_XSQ = 5.99, B1_XSQ = 15.51, B2_XSQ = 38.89, LEN_XSQ = 7.81; // quantile of chi-square dist. k=[2,8,26,3], p=.05
- let bin0_xsq, bin1_xsq, bin2_xsq, length_xsq;
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = [new Uint32Array(3), new Uint32Array(9), new Uint32Array(27)], lengths = new Uint32Array(M+1);
- for (let i = 0; i < N; ++i) {
- let tmp = random.subset([0, [1, 1], function(){ return 2; }]);
- if (tmp.length > M) throw "random.subset() result length > input";
- ++lengths[tmp.length];
- if (tmp.length)
- ++bins[tmp.length-1][tmp.reduce(function(a, v){ return a * 3 + v; }, 0)];
- }
- bin0_xsq = bins[0].reduce(function(a, v){ let e = N / (M + 1) / Math.pow(M, 1); return a + Math.pow(v - e, 2) / e; }, 0);
- bin1_xsq = bins[1].reduce(function(a, v){ let e = N / (M + 1) / Math.pow(M, 2); return a + Math.pow(v - e, 2) / e; }, 0);
- bin2_xsq = bins[2].reduce(function(a, v){ let e = N / (M + 1) / Math.pow(M, 3); return a + Math.pow(v - e, 2) / e; }, 0);
- length_xsq = lengths.reduce(function(a, v){ let e = N / (M + 1); return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 2)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (bin0_xsq < B0_XSQ && bin1_xsq < B1_XSQ && bin2_xsq < B2_XSQ && length_xsq < LEN_XSQ) {
- assert.ok(true, "Expected lengths x^2 to be < " + LEN_XSQ + ", got " + length_xsq + " on attempt #" + (attempt + 1));
- assert.ok(true, "Expected length=1 x^2 to be < " + B0_XSQ + ", got " + bin0_xsq + " on attempt #" + (attempt + 1));
- assert.ok(true, "Expected length=2 x^2 to be < " + B1_XSQ + ", got " + bin1_xsq + " on attempt #" + (attempt + 1));
- assert.ok(true, "Expected length=3 x^2 to be < " + B2_XSQ + ", got " + bin2_xsq + " on attempt #" + (attempt + 1));
- return;
- }
- }
- console.log("Expected lengths x^2 to be < " + LEN_XSQ + ", got " + length_xsq);
- console.log("Expected length=1 x^2 to be < " + B0_XSQ + ", got " + bin0_xsq);
- console.log("Expected length=2 x^2 to be < " + B1_XSQ + ", got " + bin1_xsq);
- console.log("Expected length=3 x^2 to be < " + B2_XSQ + ", got " + bin2_xsq);
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq low enough");
-});
-
-QUnit.test("random.subset(limit) with equal distribution", function(assert) {
- /*
- * limit is specified, so length should always == limit, and selections should be even
- */
- const N = 1e4, M = 3, TRIES = 3, B0_XSQ = 5.99, B1_XSQ = 15.51, B2_XSQ = 38.89, B3_XSQ = 101.88; // quantile of chi-square dist. k=[2,8,26,80], p=.05
- let bin0_xsq, bin1_xsq, bin2_xsq, bin3_xsq;
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < 100; ++attempt) {
- if (random.subset([1,2,3], 0).length !== 0) throw "random.subset(..., 0) returned non-empty array";
- }
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = [new Uint32Array(3), new Uint32Array(9), new Uint32Array(27), new Uint32Array(81)];
- for (let i = 0; i < N; ++i) {
- let tmp = random.subset([0, 1, 2], 1);
- if (tmp.length !== 1) throw "random.subset() result length != limit";
- ++bins[0][tmp.reduce(function(a, v){ return a * 3 + v; }, 0)];
- tmp = random.subset([0, 1, 2], 2);
- if (tmp.length !== 2) throw "random.subset() result length != limit";
- ++bins[1][tmp.reduce(function(a, v){ return a * 3 + v; }, 0)];
- tmp = random.subset([0, 1, 2], 3);
- if (tmp.length !== 3) throw "random.subset() result length != limit";
- ++bins[2][tmp.reduce(function(a, v){ return a * 3 + v; }, 0)];
- tmp = random.subset([0, 1, 2], 4);
- if (tmp.length !== 4) throw "random.subset() result length != limit";
- ++bins[3][tmp.reduce(function(a, v){ return a * 3 + v; }, 0)];
- }
- bin0_xsq = bins[0].reduce(function(a, v){ let e = N / Math.pow(M, 1); return a + Math.pow(v - e, 2) / e; }, 0);
- bin1_xsq = bins[1].reduce(function(a, v){ let e = N / Math.pow(M, 2); return a + Math.pow(v - e, 2) / e; }, 0);
- bin2_xsq = bins[2].reduce(function(a, v){ let e = N / Math.pow(M, 3); return a + Math.pow(v - e, 2) / e; }, 0);
- bin3_xsq = bins[3].reduce(function(a, v){ let e = N / Math.pow(M, 4); return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 2)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (bin0_xsq < B0_XSQ && bin1_xsq < B1_XSQ && bin2_xsq < B2_XSQ && bin3_xsq < B3_XSQ) {
- assert.ok(true, "Expected length=1 x^2 to be < " + B0_XSQ + ", got " + bin0_xsq + " on attempt #" + (attempt + 1));
- assert.ok(true, "Expected length=2 x^2 to be < " + B1_XSQ + ", got " + bin1_xsq);
- assert.ok(true, "Expected length=3 x^2 to be < " + B2_XSQ + ", got " + bin2_xsq);
- assert.ok(true, "Expected length=4 x^2 to be < " + B3_XSQ + ", got " + bin3_xsq);
- return;
- }
- }
- console.log("Expected length=1 x^2 to be < " + B0_XSQ + ", got " + bin0_xsq);
- console.log("Expected length=2 x^2 to be < " + B1_XSQ + ", got " + bin1_xsq);
- console.log("Expected length=3 x^2 to be < " + B2_XSQ + ", got " + bin2_xsq);
- console.log("Expected length=4 x^2 to be < " + B3_XSQ + ", got " + bin3_xsq);
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq low enough");
-});
-
-QUnit.test("random.pop() distribution", function(assert) {
- const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
- let tries = [];
- random.init(Math.random() * 0x100000000);
- for (let attempt = 0; attempt < TRIES; ++attempt) {
- let bins = new Uint32Array(3);
- const orig = [99, 100, 101];
- for (let i = 0; i < N; ++i) {
- let arr = orig.slice(), tmp = random.pop(arr) - 99;
- if (tmp < 0) throw "random.pop() < lower bound";
- if (tmp >= bins.length) throw "random.pop() > upper bound";
- if (arr.length !== 2) throw "random.pop() did not pop";
- if (arr.reduce(function(a, v){ return a + v; }, tmp) !== 201) throw "random.pop() sum error";
- ++bins[tmp];
- }
- let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
- /*
- * XSQ = scipy.stats.chi2.isf(.05, 2)
- * if xsq > XSQ, the result is biased at 95% significance
- */
- if (xsq < XSQ) {
- assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
- return;
- }
- tries.push(xsq);
- }
- assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
-});
From d33e0fd6e4e557a376436842f26b8d1a920b2e9a Mon Sep 17 00:00:00 2001
From: posidron <1614333+posidron@users.noreply.github.com>
Date: Sat, 25 Aug 2018 07:37:02 +0200
Subject: [PATCH 7/9] Fix logger imports in objects.js and random.js
---
lib/random/random.js | 2 +-
lib/utils/objects.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/random/random.js b/lib/random/random.js
index ec87107..8983369 100644
--- a/lib/random/random.js
+++ b/lib/random/random.js
@@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const MersenneTwister = require('./mersennetwister')
-const {logger} = require('../logging')
+const logger = require('../logging')
class random {
/**
diff --git a/lib/utils/objects.js b/lib/utils/objects.js
index ee7ef0e..cbe1388 100644
--- a/lib/utils/objects.js
+++ b/lib/utils/objects.js
@@ -4,7 +4,7 @@
const random = require('../random')
const utils = require('../utils')
-const {logger} = require('../logging')
+const logger = require('../logging')
var o = null // eslint-disable-line no-unused-vars
From 443399bd7a407c01f7f16aa187b09d120b8bccff Mon Sep 17 00:00:00 2001
From: posidron <1614333+posidron@users.noreply.github.com>
Date: Sat, 25 Aug 2018 20:21:40 +0200
Subject: [PATCH 8/9] Add code coverage and coveralls support
---
package.json | 3 +++
1 file changed, 3 insertions(+)
diff --git a/package.json b/package.json
index 0ef0dc2..a4e3f0b 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,8 @@
"license": "MPL-2.0",
"scripts": {
"test": "jest --silent",
+ "coverage": "cross-env NODE_ENV=test jest --silent --coverage --collectCoverageFrom=lib/**/*.js",
+ "coveralls": "yarn coverage && cat ./coverage/lcov.info | coveralls",
"lint": "cross-env NODE_ENV=test standard --verbose",
"lint:fix": "cross-env NODE_ENV=test standard --fix --verbose",
"docs": "esdoc",
@@ -65,6 +67,7 @@
]
},
"devDependencies": {
+ "coveralls": "^3.0.2",
"cross-env": "^5.1.4",
"esdoc": "^1.1.0",
"esdoc-node": "^1.0.3",
From 92d58a58ef74665199c51e8bd907ddebfc23bc32 Mon Sep 17 00:00:00 2001
From: posidron <1614333+posidron@users.noreply.github.com>
Date: Tue, 28 Aug 2018 00:54:24 +0200
Subject: [PATCH 9/9] Fix random seed value
---
lib/random/random.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lib/random/random.js b/lib/random/random.js
index 8983369..8986d47 100644
--- a/lib/random/random.js
+++ b/lib/random/random.js
@@ -13,6 +13,8 @@ class random {
static init (seed) {
if (seed === null || seed === undefined) {
random.seed = new Date().getTime()
+ } else {
+ random.seed = seed
}
random.twister = new MersenneTwister()