Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typescript conversion of core/Util.js and core/LOUtil.js #11009

Merged
merged 18 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions browser/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -235,19 +235,19 @@ COOL_JS_LST =\
src/app/DocEvents.ts \
src/app/GraphicSelectionMiddleware.ts \
src/app/SearchService.ts \
src/app/Rectangle.ts \
src/app/Util.ts \
src/app/LOUtil.ts \
src/Leaflet.js \
src/errormessages.js \
src/unocommands.js \
src/UNO/Key.js \
src/core/Log.js \
src/core/Util.js \
src/core/LOUtil.js \
src/core/geometry.ts \
src/core/Rectangle.ts \
src/core/Class.js \
src/core/Events.js \
src/core/Socket.js \
src/core/Matrix.js \
src/core/Debug.js \
src/geometry/Point.ts \
src/geometry/Bounds.ts \
Expand Down
144 changes: 144 additions & 0 deletions browser/mocha_tests/LOUtil.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/// <reference path="./refs/globals.ts"/>
/// <reference path="./helper/util.ts"/>
/// <reference path="../src/core/geometry.ts"/>
/// <reference path="../src/geometry/Point.ts"/>
/// <reference path="../src/geometry/Bounds.ts"/>
/// <reference path="../src/app/Rectangle.ts"/>
/// <reference path="../src/app/LOUtil.ts"/>
/// <reference path="./data/LOUtilTestData.ts"/>

var assert = require('assert').strict;

describe('LOUtil static class members', function () {

describe('stringToBounds()', function () {
it('parse from string with separaters and whitespaces', function () {
const bounds = LOUtil.stringToBounds('1, 2, \n3, \t4 ');
const expected = cool.Bounds.toBounds([[1, 2], [4, 6]])
assert.deepEqual(expected, bounds);
});

it('parse from string with more than 4 numbers', function () {
const bounds = LOUtil.stringToBounds('1, 2, 3, 4, 5 ');
const expected = cool.Bounds.toBounds([[1, 2], [4, 6]])
assert.deepEqual(expected, bounds);
});
});

describe('stringToRectangles()', function () {

it('parse one rectangle from string with separaters and whitespaces', function () {
const rectangles = LOUtil.stringToRectangles('1, 2, \n3, \t4 ');
const bottomLeft = cool.Point.toPoint(1, 6);
const bottomRight = cool.Point.toPoint(4, 6);
const topLeft = cool.Point.toPoint(1, 2);
const topRight = cool.Point.toPoint(4, 2);
const expected = [[bottomLeft, bottomRight, topLeft, topRight],]
assert.deepEqual(expected, rectangles);
});

it('parse two rectangles from string with separaters and whitespaces', function () {
const rectangles = LOUtil.stringToRectangles('1, 2, \n3, \t4 ; 101, 202, \t3, \n4; ');
const bottomLeft = cool.Point.toPoint(1, 6);
const bottomRight = cool.Point.toPoint(4, 6);
const topLeft = cool.Point.toPoint(1, 2);
const topRight = cool.Point.toPoint(4, 2);
const offset = cool.Point.toPoint(100, 200);
const first = [bottomLeft, bottomRight, topLeft, topRight];
const second: cool.Point[] = [];
for (let idx = 0; idx < 4; ++idx) {
second.push(first[idx].add(offset));
}
const expected = [first, second];
assert.deepEqual(expected, rectangles);
});
});

describe('findItemWithAttributeRecursive()', function () {
it('match at depth 0', function () {
const expected = LOUtilTestData.tree;
assert.deepEqual(expected, LOUtil.findItemWithAttributeRecursive(LOUtilTestData.tree, 'id', 'level0'));
});

it('match at depth 1', function () {
const expected = LOUtilTestData.tree.children[1];
assert.deepEqual(expected, LOUtil.findItemWithAttributeRecursive(LOUtilTestData.tree, 'id', 'level1_2'));
});

it('match at depth 2', function () {
const expected = LOUtilTestData.tree.children[0].children[0];
assert.deepEqual(expected, LOUtil.findItemWithAttributeRecursive(LOUtilTestData.tree, 'id', 'level2'));
});
it('match at depth 3', function () {
const expected = LOUtilTestData.tree.children[0].children[0].children[1];
assert.deepEqual(expected, LOUtil.findItemWithAttributeRecursive(LOUtilTestData.tree, 'id', 'level3'));
});

it('no match in empty tree', function () {
assert.deepEqual(null, LOUtil.findItemWithAttributeRecursive({}, 'id', 'level0'));
});

it('no match for value', function () {
assert.deepEqual(null, LOUtil.findItemWithAttributeRecursive(LOUtilTestData.tree, 'id', 'level100'));
});

it('no match for key', function () {
assert.deepEqual(null, LOUtil.findItemWithAttributeRecursive(LOUtilTestData.tree, 'somekey', 'level3'));
});
});


describe('findIndexInParentByAttribute()', function () {
it('empty tree no match', function () {
assert.equal(-1, LOUtil.findIndexInParentByAttribute({}, 'class', 'xyz'));
});

it('non empty tree no match', function () {
assert.equal(-1, LOUtil.findIndexInParentByAttribute(LOUtilTestData.shortTree, 'class', 'xyz'));
});

it('multiple matches; get first', function () {
assert.equal(2, LOUtil.findIndexInParentByAttribute(LOUtilTestData.shortTree, 'class', 'bac'));
});

it('unique match', function () {
assert.equal(2, LOUtil.findIndexInParentByAttribute(LOUtilTestData.shortTree, 'name', 'BAC'));
});
});

describe('_doRectanglesIntersect()', function () {

it('rectangle intersects with itself', function () {
assert.ok(LOUtil._doRectanglesIntersect([10, 20, 100, 200], [10, 20, 100, 200]));
});

it('A contains B, there is intersection', function () {
assert.ok(LOUtil._doRectanglesIntersect([10, 20, 100, 200], [11, 21, 90, 190]));
});

it('B contains A, there is intersection', function () {
assert.ok(LOUtil._doRectanglesIntersect([11, 21, 90, 190], [10, 20, 100, 200]));
});

it('A meets B tangentially (vertical)', function () {
assert.ok(LOUtil._doRectanglesIntersect([10, 20, 100, 200], [110, 20, 10, 200]));
});

it('A meets B tangentially (horizontal)', function () {
assert.ok(LOUtil._doRectanglesIntersect([10, 20, 100, 200], [10, 220, 100, 20]));
});

it('A meets B tangentially (single point)', function () {
assert.ok(LOUtil._doRectanglesIntersect([10, 20, 100, 200], [110, 220, 10, 20]));
});

it('disjoint (bug in the function)', function () {
assert.ok(LOUtil._doRectanglesIntersect([10, 20, 100, 200], [111, 221, 100, 200]));
});

it('disjoint (rectangles very far away)', function () {
assert.ok(!LOUtil._doRectanglesIntersect([10, 20, 10, 20], [400, 500, 10, 20]));
});
});

});
4 changes: 2 additions & 2 deletions browser/mocha_tests/Rectangle.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// <reference path="./refs/globals.ts"/>
/// <reference path="./helper/util.ts"/>
/// <reference path="../src/core/Rectangle.ts"/>
/// <reference path="../src/app/Rectangle.ts"/>

var assert = require('assert').strict;

Expand Down Expand Up @@ -350,4 +350,4 @@ describe('coordinate API tests', function () {

}); // coords.forEach

}); // root describe
}); // root describe
215 changes: 215 additions & 0 deletions browser/mocha_tests/Util.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
/// <reference path="./refs/globals.ts"/>
/// <reference path="./helper/util.ts"/>
/// <reference path="../src/app/Util.ts"/>

var assert = require('assert');

describe('Util static members tests', function () {

describe('stamp()', function () {
const obj1 = { _leaflet_id: -1 };
const obj2 = { _leaflet_id: -1 };
let obj1Id = Util.stamp(obj1);
let obj2Id = Util.stamp(obj2);
it('first: id must be > 0', function() {
assert.ok(obj1Id > 0);
});

it('second: id must be > 0', function() {
assert.ok(obj2Id > 0);
});

it('first objects id must be less than id of second object', function() {
assert.ok(obj1Id < obj2Id);
});

it('first: id must not change', function () {
assert.equal(obj1Id, Util.stamp(obj1));
});

it('second: id must not change', function () {
assert.equal(obj2Id, Util.stamp(obj2));
});

});

describe('formatNum()', function() {
it('integer with no decimal places', function () {
assertFloat(Util.formatNum(5, 0), 5, 1e-5, '');
});

it('integer with 4 decimal places', function () {
assertFloat(Util.formatNum(5, 4), 5, 1e-5, '');
});

it('decimal with 1 decimal places no-round', function () {
assertFloat(Util.formatNum(5.30333333, 1), 5.3, 1e-5, '');
});

it('decimal with 4 decimal places no-round', function () {
assertFloat(Util.formatNum(5.30333333, 4), 5.3033, 1e-5, '');
});

it('decimal with 1 decimal places round', function () {
assertFloat(Util.formatNum(5.35333333, 1), 5.4, 1e-5, '');
});

it('decimal with 4 decimal places round', function () {
assertFloat(Util.formatNum(5.30335333, 4), 5.3034, 1e-5, '');
});
});

describe('trimStart()', function () {
it('whole string is prefix', function () {
assert.strictEqual(Util.trimStart('ABC', 'ABC'), '');
});

it('whole string shorter than prefix', function () {
assert.strictEqual(Util.trimStart('ABC', 'ABCD'), 'ABC');
});

it('No prefix', function () {
assert.strictEqual(Util.trimStart('XYZ', 'ABCD'), 'XYZ');
});

it('Multi prefix', function () {
assert.strictEqual(Util.trimStart('ABCDABCDXYZ', 'ABCD'), 'ABCDXYZ');
});
});

describe('trimEnd()', function () {
it('whole string is suffix', function () {
assert.strictEqual(Util.trimEnd('ABC', 'ABC'), '');
});

it('whole string shorter than suffix', function () {
assert.strictEqual(Util.trimEnd('ABC', 'ABCD'), 'ABC');
});

it('No suffix', function () {
assert.strictEqual(Util.trimEnd('XYZ', 'ABCD'), 'XYZ');
});

it('Multi suffix', function () {
assert.strictEqual(Util.trimEnd('XYZABCDABCD', 'ABCD'), 'XYZABCD');
});
});

describe('trim()', function () {
it('trim() with no prefix or suffix argument', function () {
assert.strictEqual(Util.trim('\t \tCONTENT \t\t \t'), 'CONTENT');
});

it('whole string is prefix', function () {
assert.strictEqual(Util.trim('ABC', 'ABC'), '');
});

it('whole string shorter than prefix', function () {
assert.strictEqual(Util.trim('ABC', 'ABCD'), 'ABC');
});

it('whole string is suffix', function () {
assert.strictEqual(Util.trim('ABC', ' ', 'ABC'), '');
});

it('whole string shorter than suffix', function () {
assert.strictEqual(Util.trim('ABC', '', 'ABCD'), 'ABC');
});

it('No prefix', function () {
assert.strictEqual(Util.trim('XYZ', 'ABCD'), 'XYZ');
});

it('No suffix', function () {
assert.strictEqual(Util.trim('XYZ', '', 'ABCD'), 'XYZ');
});

it('Multi prefix and suffix', function () {
assert.strictEqual(Util.trim('ABCDABCDXYZABCDABCD', 'ABCD', 'ABCD'), 'ABCDXYZABCD');
});

it('Overlapping prefix and suffix', function () {
assert.strictEqual(Util.trim('ABCDAB', 'ABCD', 'CDAB'), 'AB');
});
});

describe('splitWords()', function () {
it('split empty string', function () {
assert.deepEqual(Util.splitWords(''), ['']);
});

it('split string with white spaces', function () {
assert.deepEqual(Util.splitWords(' \t \t\t '), ['']);
});

it('split string with single word', function () {
assert.deepEqual(Util.splitWords('ABC'), ['ABC']);
});

it('split string with single word surrounded by multi white-spaces', function () {
assert.deepEqual(Util.splitWords(' \t \t \t\t ABC\t \t\t \t'), ['ABC']);
});

it('split string with two words', function () {
assert.deepEqual(Util.splitWords(' \t \t \t\t ABC\t \t\t \tXYZ \t\t \t'), ['ABC', 'XYZ']);
});
});

describe('round()', function() {
it('integer with no decimal places', function () {
assertFloat(Util.round(5), 5, 1e-5, '');
});

it('integer with 4 decimal places', function () {
assertFloat(Util.round(5, 1e-4), 5, 1e-5, '');
});

it('decimal with 1 decimal places no-round', function () {
assertFloat(Util.round(5.30333333, 0.1), 5.3, 1e-5, '');
});

it('decimal with 4 decimal places no-round', function () {
assertFloat(Util.round(5.30333333, 0.0001), 5.3033, 1e-5, '');
});

it('decimal with 1 decimal places round', function () {
assertFloat(Util.round(5.35333333, 0.1), 5.4, 1e-5, '');
});

it('decimal with 4 decimal places round', function () {
assertFloat(Util.round(5.30335333, 0.0001), 5.3034, 1e-5, '');
});
});

describe('template()', function () {
it('empty string', function () {
assert.strictEqual(Util.template('', {}), '');
});

it('no substitutions', function () {
assert.strictEqual(Util.template('cool apps', {'cool': 32}), 'cool apps');
});

it('one key one substitution', function () {
assert.strictEqual(Util.template('cool { app } abcd', {'cool': 32, 'app': 'calc'}), 'cool calc abcd');
});

it('one key two substitutions', function () {
assert.strictEqual(Util.template('A {app } cool { app} abcd', {'cool': 32, 'app': 'calc'}), 'A calc cool calc abcd');
});

it('two keys multiple substitutions', function () {
assert.strictEqual(Util.template('A) { app1}, B) {app2 }, C) { app2}, D) { app1 } ', {'cool': 32, 'app': 'calc', 'app1': 'draw', 'app2': 'impress'}), 'A) draw, B) impress, C) impress, D) draw ');
});

it('key function', function () {
assert.strictEqual(Util.template('{fkey }, { key }', {
'key': '1234',
'fkey': function(data: any) {
return data['key'] + '_999';
},
}), '1234_999, 1234');
});
});

});
Loading