-
Notifications
You must be signed in to change notification settings - Fork 999
Modernize test/bench runners #3038
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
base: master
Are you sure you want to change the base?
Changes from all commits
bf56533
8b017a9
53c16a3
9a3052c
3c49de8
21148ba
d0f7ad3
b88c3d0
47d54f0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,9 +17,9 @@ const JS_PACKAGES = []; // projects that use javascript/rollup to build | |
| const MAIN_PACKAGE = "@turf/turf"; | ||
|
|
||
| const TAPE_PACKAGES = []; // projects that have tape tests | ||
| const NODE_TEST_PACKAGES = []; // projects that use node's native test runner | ||
| const TYPES_PACKAGES = []; // projects that have types tests | ||
| const TSTYCHE_PACKAGES = []; // projects that use tstyche for type tests. | ||
| const BENCH_PACKAGES = []; // projects that have benchmarks | ||
| const TSTYCHE_PACKAGES = []; // projects that use tstyche for type tests | ||
|
|
||
| // iterate all the packages and figure out what buckets everything falls into | ||
| const packagesPath = path.join(process.cwd(), "packages"); | ||
|
|
@@ -38,8 +38,16 @@ for (const pk of await fs.readdir(packagesPath)) { | |
| JS_PACKAGES.push(name); | ||
| } | ||
|
|
||
| if (existsSync(path.join(pk, "test.js"))) { | ||
| TAPE_PACKAGES.push(name); | ||
| if (existsSync(path.join(packagesPath, pk, "test.ts"))) { | ||
| const testFileContents = await fs.readFile( | ||
| path.join(packagesPath, pk, "test.ts"), | ||
| "utf-8" | ||
| ); | ||
| if (testFileContents.includes(`from "tape"`)) { | ||
| TAPE_PACKAGES.push(name); | ||
| } else { | ||
| NODE_TEST_PACKAGES.push(name); | ||
| } | ||
| } | ||
|
|
||
| if (existsSync(path.join(packagesPath, pk, "types.ts"))) { | ||
|
|
@@ -51,13 +59,6 @@ for (const pk of await fs.readdir(packagesPath)) { | |
| } | ||
| } | ||
|
|
||
| const TS_TAPE_PACKAGES = TAPE_PACKAGES.filter( | ||
| (pkg) => -1 !== TS_PACKAGES.indexOf(pkg) | ||
| ); | ||
| const JS_TAPE_PACKAGES = TAPE_PACKAGES.filter( | ||
| (pkg) => -1 !== JS_PACKAGES.indexOf(pkg) | ||
| ); | ||
|
|
||
| export default { | ||
| rules: [ | ||
| packageOrder({ | ||
|
|
@@ -211,9 +212,21 @@ export default { | |
| scripts: { | ||
| bench: "tsx bench.ts", | ||
| "test:tape": "tsx test.ts", | ||
| "test:node": REMOVE, | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just in case we ever migrate from node native back to tape. |
||
| }, | ||
| }, | ||
| includePackages: [...TS_TAPE_PACKAGES, ...JS_TAPE_PACKAGES], | ||
| includePackages: TAPE_PACKAGES, | ||
| }), | ||
|
|
||
| packageScript({ | ||
| options: { | ||
| scripts: { | ||
| bench: "node bench.ts", | ||
| "test:node": "node --test", | ||
| "test:tape": REMOVE, | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handles swapping bench from |
||
| }, | ||
| }, | ||
| includePackages: NODE_TEST_PACKAGES, | ||
| }), | ||
|
|
||
| packageScript({ | ||
|
|
@@ -246,6 +259,43 @@ export default { | |
| }, | ||
| }, | ||
| includePackages: [...TS_PACKAGES, ...JS_PACKAGES], | ||
| excludePackages: NODE_TEST_PACKAGES, | ||
| }), | ||
|
|
||
| requireDependency({ | ||
| options: { | ||
| devDependencies: { | ||
| tape: "^5.9.0", | ||
| "@types/tape": "^5.8.1", | ||
| }, | ||
| }, | ||
| includePackages: TAPE_PACKAGES, | ||
| }), | ||
|
|
||
| requireDependency({ | ||
| options: { | ||
| devDependencies: { | ||
| "@types/benchmark": REMOVE, | ||
| "@types/tape": REMOVE, | ||
| benchmark: REMOVE, | ||
| "load-json-file": REMOVE, | ||
| tape: REMOVE, | ||
| tsx: REMOVE, | ||
| "write-json-file": REMOVE, | ||
| }, | ||
| }, | ||
| includePackages: NODE_TEST_PACKAGES, | ||
| }), | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When we switch to node native testing and use the shared fixture runner, we get to remove a lot of dependencies in favor of the builtin tooling. |
||
|
|
||
| requireDependency({ | ||
| options: { | ||
| devDependencies: { | ||
| "@types/benchmark": "^2.1.5", | ||
| benchmark: "^2.1.4", | ||
| }, | ||
| }, | ||
| includePackages: TS_PACKAGES, | ||
| excludePackages: NODE_TEST_PACKAGES, | ||
| }), | ||
|
|
||
| requireDependency({ | ||
|
|
@@ -254,8 +304,6 @@ export default { | |
| tslib: "^2.8.1", | ||
| }, | ||
| devDependencies: { | ||
| "@types/benchmark": "^2.1.5", | ||
| "@types/tape": "^5.8.1", | ||
| typescript: "^5.8.3", | ||
| }, | ||
| }, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,8 +36,10 @@ | |
| "@monorepolint/config": "0.6.0-alpha.6", | ||
| "@monorepolint/core": "0.6.0-alpha.6", | ||
| "@monorepolint/rules": "0.6.0-alpha.6", | ||
| "@types/benchmark": "^2.1.5", | ||
| "@types/node": "22.15.3", | ||
| "acorn": "^8.14.1", | ||
| "benchmark": "^2.1.4", | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is required because of shared/benchFixtures.mts, but we get to remove it from each package. |
||
| "camelcase": "^8.0.0", | ||
| "d3-queue": "*", | ||
| "decamelize": "^6.0.0", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,48 +1,12 @@ | ||
| import path from "path"; | ||
| import { fileURLToPath } from "url"; | ||
| import { glob } from "glob"; | ||
| import { loadJsonFileSync } from "load-json-file"; | ||
| import Benchmark from "benchmark"; | ||
| import { center } from "./index.js"; | ||
|
|
||
| const __dirname = path.dirname(fileURLToPath(import.meta.url)); | ||
|
|
||
| const fixtures = glob | ||
| .sync(path.join(__dirname, "test", "in", "*.geojson")) | ||
| .map((input) => { | ||
| return { | ||
| name: path.parse(input).name, | ||
| geojson: loadJsonFileSync(input), | ||
| }; | ||
| }); | ||
|
|
||
| /** | ||
| * Single Process Benchmark | ||
| * | ||
| * feature-collection: 0.445ms | ||
| * imbalanced-polygon: 0.051ms | ||
| * linestring: 0.027ms | ||
| * point: 0.011ms | ||
| * polygon: 0.013ms | ||
| */ | ||
| for (const { name, geojson } of fixtures) { | ||
| console.time(name); | ||
| center(geojson); | ||
| console.timeEnd(name); | ||
| } | ||
|
|
||
| /** | ||
| * Benchmark Results | ||
| * | ||
| * feature-collection x 2,786,700 ops/sec ±1.50% (83 runs sampled) | ||
| * imbalanced-polygon x 1,364,145 ops/sec ±3.33% (76 runs sampled) | ||
| * linestring x 4,104,106 ops/sec ±4.16% (81 runs sampled) | ||
| * point x 4,901,692 ops/sec ±5.23% (81 runs sampled) | ||
| * polygon x 2,862,759 ops/sec ±1.14% (86 runs sampled) | ||
| */ | ||
| const suite = new Benchmark.Suite("turf-center"); | ||
| for (const { name, geojson } of fixtures) { | ||
| suite.add(name, () => center(geojson)); | ||
| } | ||
|
|
||
| suite.on("cycle", (e) => console.log(String(e.target))).run(); | ||
| import { center } from "./index.ts"; | ||
| import { benchFixtures } from "../../support/benchFixtures.mts"; | ||
|
|
||
| // Benchmark Results | ||
| // feature-collection.geojson x 27,241,658 ops/sec ±0.34% (99 runs sampled) | ||
| // imbalanced-polygon.geojson x 14,679,583 ops/sec ±0.27% (98 runs sampled) | ||
| // linestring.geojson x 34,199,495 ops/sec ±0.52% (95 runs sampled) | ||
| // point.geojson x 52,230,993 ops/sec ±0.70% (96 runs sampled) | ||
| // points-with-weights.geojson x 24,802,237 ops/sec ±0.33% (100 runs sampled) | ||
| // polygon-without-weights.geojson x 18,423,881 ops/sec ±0.28% (100 runs sampled) | ||
| // polygon.geojson x 24,990,920 ops/sec ±0.45% (99 runs sampled) | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hilariously this is almost exactly 10x the original speed due to hardware progression over the years. |
||
| await benchFixtures("turf-center", (input) => center(input)); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| import { BBox, Feature, GeoJsonProperties, Point } from "geojson"; | ||
| import type { BBox, Feature, GeoJsonProperties, Point } from "geojson"; | ||
| import { bbox } from "@turf/bbox"; | ||
| import { point, Id, AllGeoJSON } from "@turf/helpers"; | ||
| import { point, type Id, type AllGeoJSON } from "@turf/helpers"; | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These |
||
|
|
||
| /** | ||
| * Takes a {@link Feature} or {@link FeatureCollection} and returns the absolute center point of all features. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,61 +1,47 @@ | ||
| import test from "tape"; | ||
| import { glob } from "glob"; | ||
| import path from "path"; | ||
| import { fileURLToPath } from "url"; | ||
| import { loadJsonFileSync } from "load-json-file"; | ||
| import { writeJsonFileSync } from "write-json-file"; | ||
| import { bboxPolygon } from "@turf/bbox-polygon"; | ||
| import { bbox } from "@turf/bbox"; | ||
| import { featureEach, coordEach } from "@turf/meta"; | ||
| import { lineString, featureCollection } from "@turf/helpers"; | ||
| import { center } from "./index.js"; | ||
| import test from "node:test"; | ||
| import center from "./index.ts"; | ||
| import { featureCollection, lineString } from "@turf/helpers"; | ||
| import { coordEach, featureEach } from "@turf/meta"; | ||
| import bboxPolygon from "@turf/bbox-polygon"; | ||
| import bbox from "@turf/bbox"; | ||
| import type { Geometry } from "geojson"; | ||
| import { testFixtures } from "../../support/testFixtures.mts"; | ||
| import assert from "assert"; | ||
|
|
||
| const __dirname = path.dirname(fileURLToPath(import.meta.url)); | ||
| await test("center fixtures", async (t) => { | ||
| await testFixtures(t, (geojson) => { | ||
| const options = geojson.options || {}; | ||
| options.properties = { "marker-symbol": "star", "marker-color": "#F00" }; | ||
| const centered = center(geojson, options); | ||
|
|
||
| test("turf-center", (t) => { | ||
| glob | ||
| .sync(path.join(__dirname, "test", "in", "*.geojson")) | ||
| .forEach((filepath) => { | ||
| const geojson = loadJsonFileSync(filepath); | ||
| const options = geojson.options || {}; | ||
| options.properties = { "marker-symbol": "star", "marker-color": "#F00" }; | ||
| const centered = center(geojson, options); | ||
| // Display Results | ||
| const results = featureCollection<Geometry>([centered]); | ||
| featureEach(geojson, (feature) => results.features.push(feature)); | ||
| const extent = bboxPolygon(bbox(geojson)); | ||
| extent.properties = { | ||
| stroke: "#00F", | ||
| "stroke-width": 1, | ||
| "fill-opacity": 0, | ||
| }; | ||
| coordEach(extent, (coord) => | ||
| results.features.push( | ||
| lineString([coord, centered.geometry.coordinates], { | ||
| stroke: "#00F", | ||
| "stroke-width": 1, | ||
| }) | ||
| ) | ||
| ); | ||
| results.features.push(extent); | ||
|
|
||
| // Display Results | ||
| const results = featureCollection([centered]); | ||
| featureEach(geojson, (feature) => results.features.push(feature)); | ||
| const extent = bboxPolygon(bbox(geojson)); | ||
| extent.properties = { | ||
| stroke: "#00F", | ||
| "stroke-width": 1, | ||
| "fill-opacity": 0, | ||
| }; | ||
| coordEach(extent, (coord) => | ||
| results.features.push( | ||
| lineString([coord, centered.geometry.coordinates], { | ||
| stroke: "#00F", | ||
| "stroke-width": 1, | ||
| }) | ||
| ) | ||
| ); | ||
| results.features.push(extent); | ||
|
|
||
| const out = filepath.replace( | ||
| path.join("test", "in"), | ||
| path.join("test", "out") | ||
| ); | ||
| if (process.env.REGEN) writeJsonFileSync(out, results); | ||
| t.deepEqual(results, loadJsonFileSync(out), path.parse(filepath).name); | ||
| }); | ||
| t.end(); | ||
| return results; | ||
| }); | ||
| }); | ||
|
|
||
| test("turf-center -- properties", (t) => { | ||
| test("turf-center -- properties", () => { | ||
| const line = lineString([ | ||
| [0, 0], | ||
| [1, 1], | ||
| ]); | ||
| const pt = center(line, { properties: { foo: "bar" } }); | ||
| t.equal(pt.properties.foo, "bar", "translate properties"); | ||
| t.end(); | ||
| assert.strictEqual(pt.properties.foo, "bar", "translate properties"); | ||
| }); |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import path from "path"; | ||
| import { readdir, readFile } from "node:fs/promises"; | ||
| import Benchmark from "benchmark"; | ||
|
|
||
| export async function benchFixtures(pkgName: string, fn: (input: any) => void) { | ||
| const suite = new Benchmark.Suite(pkgName); | ||
| const fixturesPath = path.join(process.cwd(), "test", "in"); | ||
| for (const file of await readdir(fixturesPath)) { | ||
| const inputPath = path.join(fixturesPath, file); | ||
| const inputData = JSON.parse(await readFile(inputPath, "utf-8")); | ||
| suite.add(file, () => fn(inputData)); | ||
| } | ||
|
|
||
| suite.on("cycle", (e: any) => console.log(String(e.target))).run(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Automatically differentiate if test.ts is
tapeor node native