babelacc

compare different implementations of the text alternative computation  https://p.ce9e.org/babelacc/
git clone https://git.ce9e.org/babelacc.git

commit
434471f76b74a99fb75dc8d1bab409c5f11cdb48
parent
1ef3a8d2e8f9b96feb82b43aba3ef374121ddc13
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2019-03-25 19:44
Merge branch 'feature-fuzz'

Diffstat

M Makefile 11 +++++++++++
A fuzz.html 38 ++++++++++++++++++++++++++++++++++++++
A fuzz/fuzzer.js 48 ++++++++++++++++++++++++++++++++++++++++++++++++
A fuzz/html.js 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A fuzz/index.js 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M package.json 1 +

6 files changed, 311 insertions, 0 deletions


diff --git a/Makefile b/Makefile

@@ -1,3 +1,14 @@
   -1     1 all: babel.js fuzz.js
   -1     2 
    1     3 babel.js: src/babel.js src/axs.js src/eval.patch
    2     4 	browserify $< -o $@
    3     5 	patch $@ src/eval.patch
   -1     6 
   -1     7 fuzz.js: fuzz/index.js fuzz/*.js node_modules/aria-api/instrumented.js node_modules/aria-api/lib/name-inst.js
   -1     8 	browserify $< -o $@
   -1     9 
   -1    10 node_modules/aria-api/instrumented.js: node_modules/aria-api/index.js
   -1    11 	cat $< | sed 's/name\.js/name-inst\.js/' > $@
   -1    12 
   -1    13 node_modules/aria-api/lib/name-inst.js: node_modules/aria-api/lib/name.js
   -1    14 	npx nyc instrument $< > $@

diff --git a/fuzz.html b/fuzz.html

@@ -0,0 +1,38 @@
   -1     1 <!DOCTYPE html>
   -1     2 <html>
   -1     3 <head>
   -1     4 	<meta charset="utf-8" />
   -1     5 	<title>Babelacc fuzzer</title>
   -1     6 	<link rel="stylesheet" href="style.css" />
   -1     7 </head>
   -1     8 <body>
   -1     9 	<table>
   -1    10 		<thead>
   -1    11 			<tr>
   -1    12 				<th>tested paths</th>
   -1    13 				<th>errors found</th>
   -1    14 			</tr>
   -1    15 		</thead>
   -1    16 		<tbody>
   -1    17 			<tr>
   -1    18 				<td id="ba-fingerprints">0</td>
   -1    19 				<td id="ba-errors">0</td>
   -1    20 			</tr>
   -1    21 		</tbody>
   -1    22 	</table>
   -1    23 
   -1    24 	<table>
   -1    25 		<thead>
   -1    26 			<tr>
   -1    27 				<th>HTML</th>
   -1    28 				<th>accdc</th>
   -1    29 				<th>aria-api</th>
   -1    30 			</tr>
   -1    31 		</thead>
   -1    32 		<tbody id="ba-reports"></tbody>
   -1    33 	</table>
   -1    34 	<div id="ba-preview"></div>
   -1    35 
   -1    36 	<script src="fuzz.js"></script>
   -1    37 </body>
   -1    38 </html>

diff --git a/fuzz/fuzzer.js b/fuzz/fuzzer.js

@@ -0,0 +1,48 @@
   -1     1 var getFingerprint = function(covPath) {
   -1     2 	var coverage = window.__coverage__[covPath].b;
   -1     3 	var fingerprint = Object.values(coverage).map(x => x.join(':')).join('-');
   -1     4 	for (var key in coverage) {
   -1     5 		for (var i = 0; i < coverage[key].length; i++) {
   -1     6 			coverage[key][i] = 0;
   -1     7 		}
   -1     8 	}
   -1     9 	return fingerprint;
   -1    10 };
   -1    11 
   -1    12 var run = function(corpus, oracle, covPath, onFingerprint, onReport, done) {
   -1    13 	var fingerprints = [];
   -1    14 	var queue = [];
   -1    15 	var count = 0;
   -1    16 
   -1    17 	corpus.forEach(function(item) {
   -1    18 		queue.push(item);
   -1    19 	});
   -1    20 
   -1    21 	var step = function() {
   -1    22 		if (queue.length) {
   -1    23 			var item = queue.shift();
   -1    24 			var report = oracle(item);
   -1    25 			var fingerprint = getFingerprint(covPath);
   -1    26 
   -1    27 			if (!fingerprints.includes(fingerprint)) {
   -1    28 				fingerprints.push(fingerprint);
   -1    29 				item.mutate().forEach(mutation => queue.push(mutation));
   -1    30 				onFingerprint(fingerprint, fingerprints.length);
   -1    31 
   -1    32 				if (report) {
   -1    33 					onReport(report);
   -1    34 				}
   -1    35 			}
   -1    36 
   -1    37 			setTimeout(step);
   -1    38 		} else {
   -1    39 			done();
   -1    40 		}
   -1    41 	};
   -1    42 
   -1    43 	step();
   -1    44 };
   -1    45 
   -1    46 module.exports = {
   -1    47 	'run': run,
   -1    48 };

diff --git a/fuzz/html.js b/fuzz/html.js

@@ -0,0 +1,147 @@
   -1     1 var constants = require('aria-api/lib/constants');
   -1     2 
   -1     3 var attributes = [
   -1     4 	['role',             Array.prototype.concat.apply([], Object.values(constants.subRoles)).filter((v, i, a) => a.indexOf(v) === i)],
   -1     5 	['hidden',           ['']],
   -1     6 	['aria-hidden',      ['', 'true', 'false']],
   -1     7 	['aria-label',       ['', '__random__']],
   -1     8 	['title',            ['', '__random__']],
   -1     9 	['value',            ['', '__random__']],
   -1    10 	['placeholder',      ['', '__random__']],
   -1    11 	['alt',              ['', '__random__']],
   -1    12 	['aria-valuenow',    ['', '__random__']],
   -1    13 	['aria-valuetext',   ['', '__random__']],
   -1    14 	['aria-labelledby',  ['__randint__']],
   -1    15 	['aria-owns',        ['__randint__']],
   -1    16 	['list',             ['__randint__']],
   -1    17 	['for',              ['__randint__']],
   -1    18 	['type',             ['', '__random__', 'hidden', 'checkbox', 'text', 'password', 'color', 'reset']],
   -1    19 	['style',            ['', '__random__', 'display: none', 'display: block', 'display: inline-block', 'display: inline', 'visibility: hidden']],
   -1    20 ];
   -1    21 
   -1    22 var tags = ['a', 'button', 'form', 'label', 'input', 'article', 'table', 'td', 'tr', 'th', 'pre', 'legend', 'h1', 'div', 'span', 'fieldset', 'img', 'abbr', 'strong', 'br', 'hr', 'select', 'option', 'datalist'];
   -1    23 
   -1    24 var randomInt = function(n) {
   -1    25 	return Math.floor(Math.random() * n);
   -1    26 };
   -1    27 
   -1    28 var randomChoice = function(list) {
   -1    29 	return list[randomInt(list.length)];
   -1    30 };
   -1    31 
   -1    32 var randomString = function(len) {
   -1    33 	var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 -_.,#';
   -1    34 	var result = '';
   -1    35 	for (var i = 0; i < len; i++) {
   -1    36 		result += randomChoice(chars);
   -1    37 	}
   -1    38 	return result;
   -1    39 };
   -1    40 
   -1    41 function AttributeList(len) {
   -1    42 	this.value = [];
   -1    43 	for (var i = 0; i < len; i++) {
   -1    44 		var attr = randomChoice(attributes);
   -1    45 		var value = randomChoice(attr[1]);
   -1    46 		if (value === '__random__') {
   -1    47 			// shortcut: always use fixed string length
   -1    48 			value = randomString(10);
   -1    49 		} else if (value === '__randint__') {
   -1    50 			value = randomInt(len);
   -1    51 		}
   -1    52 		this.value.push(attr[0] + '="' + value + '"');
   -1    53 	}
   -1    54 }
   -1    55 
   -1    56 AttributeList.prototype.shrink = function() {
   -1    57 	var result = [];
   -1    58 	for (var i = 0; i < this.value.length; i++) {
   -1    59 		var item = new AttributeList(0);
   -1    60 		for (var j = 0; j < this.value.length; j++) {
   -1    61 			if (j !== i) {
   -1    62 				item.value.push(this.value[j]);
   -1    63 			}
   -1    64 		}
   -1    65 		result.push(item);
   -1    66 	}
   -1    67 	return result;
   -1    68 };
   -1    69 
   -1    70 function Element(len, ctx) {
   -1    71 	ctx = ctx || {k: 0};
   -1    72 	this.tag = randomChoice(tags);
   -1    73 	this.id = ctx.k;
   -1    74 	this.content = ctx.k;
   -1    75 	ctx.k += 1;
   -1    76 	this.attrs = new AttributeList(randomInt(len));
   -1    77 	this.children = new Children(randomInt(len), ctx);
   -1    78 }
   -1    79 
   -1    80 Element.prototype.shrink = function() {
   -1    81 	var result = [];
   -1    82 	var tag = this.tag;
   -1    83 	var id = this.id;
   -1    84 	var content = this.content;
   -1    85 	var attrsList = [this.attrs].concat(this.attrs.shrink());
   -1    86 	var childrenList = [this.children].concat(this.children.shrink());
   -1    87 	attrsList.forEach(function(attrs) {
   -1    88 		childrenList.forEach(function(children) {
   -1    89 			if (attrs !== this.attrs || children !== this.children) {
   -1    90 				var item = new Element(0, {});
   -1    91 				item.tag = tag;
   -1    92 				item.id = id;
   -1    93 				item.content = content;
   -1    94 				item.attrs = attrs;
   -1    95 				item.children = children;
   -1    96 				result.push(item);
   -1    97 			}
   -1    98 		});
   -1    99 	});
   -1   100 	return result;
   -1   101 };
   -1   102 
   -1   103 Element.prototype.mutate = function() {
   -1   104 	return this.shrink();
   -1   105 };
   -1   106 
   -1   107 Element.prototype.toString = function() {
   -1   108 	var s = '<' + this.tag + ' id="' + this.id + '"';
   -1   109 	this.attrs.value.forEach(function(attr) {
   -1   110 		s += ' ' + attr;
   -1   111 	});
   -1   112 	s += '>' + this.content;
   -1   113 	this.children.value.forEach(function(child) {
   -1   114 		s += child.toString();
   -1   115 	});
   -1   116 	s += '</' + this.tag + '>';
   -1   117 	return s;
   -1   118 };
   -1   119 
   -1   120 function Children(len, ctx) {
   -1   121 	this.value = [];
   -1   122 	for (var i = 0; i < len; i++) {
   -1   123 		this.value.push(new Element(randomInt(len), ctx));
   -1   124 	}
   -1   125 }
   -1   126 
   -1   127 Children.prototype.shrink = function() {
   -1   128 	var result = [];
   -1   129 	for (var i = 0; i < this.value.length; i++) {
   -1   130 		var item = new Children(0, {});
   -1   131 		for (var j = 0; j < this.value.length; j++) {
   -1   132 			if (j !== i) {
   -1   133 				// shortcut: pick random shrink result
   -1   134 				var shrunken = this.value[j].shrink();
   -1   135 				if (shrunken.length) {
   -1   136 					item.value.push(randomChoice(shrunken));
   -1   137 				}
   -1   138 			}
   -1   139 		}
   -1   140 		result.push(item);
   -1   141 	}
   -1   142 	return result;
   -1   143 };
   -1   144 
   -1   145 module.exports = {
   -1   146 	'Element': Element,
   -1   147 };

diff --git a/fuzz/index.js b/fuzz/index.js

@@ -0,0 +1,66 @@
   -1     1 var ariaApi = require('aria-api/instrumented.js');
   -1     2 var accdc = require('w3c-alternative-text-computation');
   -1     3 
   -1     4 var fuzzer = require('./fuzzer');
   -1     5 var html = require('./html');
   -1     6 
   -1     7 var preview = document.querySelector('#ba-preview');
   -1     8 var fingerprints = document.querySelector('#ba-fingerprints');
   -1     9 var errors = document.querySelector('#ba-errors');
   -1    10 var reports = document.querySelector('#ba-reports');
   -1    11 
   -1    12 var oracle = function(input) {
   -1    13 	preview.innerHTML = input.toString();
   -1    14 	var el = preview.querySelector('#test') || preview.children[0] || preview;
   -1    15 	var v1, v2;
   -1    16 
   -1    17 	try {
   -1    18 		v1 = accdc.calcNames(el).name;
   -1    19 	} catch (error) {
   -1    20 		v1 = error;
   -1    21 	}
   -1    22 
   -1    23 	try {
   -1    24 		v2 = ariaApi.getName(el);
   -1    25 	} catch (error) {
   -1    26 		v2 = error;
   -1    27 	}
   -1    28 
   -1    29 	if (v1 !== v2) {
   -1    30 		return {
   -1    31 			'html': preview.innerHTML,
   -1    32 			'v1': v1,
   -1    33 			'v2': v2,
   -1    34 		};
   -1    35 	}
   -1    36 };
   -1    37 
   -1    38 var renderReport = function(report) {
   -1    39 	var tr = document.createElement('tr');
   -1    40 	var td1 = document.createElement('td');
   -1    41 	td1.textContent = report.html;
   -1    42 	tr.append(td1);
   -1    43 	var td2 = document.createElement('td');
   -1    44 	td2.textContent = report.v1;
   -1    45 	tr.append(td2);
   -1    46 	var td3 = document.createElement('td');
   -1    47 	td3.textContent = report.v2;
   -1    48 	tr.append(td3);
   -1    49 	return tr;
   -1    50 };
   -1    51 
   -1    52 document.addEventListener('DOMContentLoaded', function() {
   -1    53 	var covPath = 'node_modules/aria-api/lib/name.js';
   -1    54 	var corpus = [];
   -1    55 	for (var i = 0; i < 10; i++) {
   -1    56 		corpus.push(new html.Element(10));
   -1    57 	}
   -1    58 	fuzzer.run(corpus, oracle, covPath, function(fingerprint, c) {
   -1    59 		fingerprints.textContent = c;
   -1    60 	}, function(report) {
   -1    61 		reports.append(renderReport(report));
   -1    62 		errors.textContent = reports.children.length;
   -1    63 	}, function() {
   -1    64 		preview.innerHTML = 'DONE';
   -1    65 	});
   -1    66 });

diff --git a/package.json b/package.json

@@ -6,6 +6,7 @@
    6     6     "accessibility-developer-tools": "^2.12.0",
    7     7     "aria-api": "^0.2.5",
    8     8     "axe-core": "^3.1.2",
   -1     9     "nyc": "^13.3.0",
    9    10     "w3c-alternative-text-computation": "github:accdc/w3c-alternative-text-computation"
   10    11   },
   11    12   "repository": {