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

Add tests #27

Merged
merged 28 commits into from
Jun 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
14536c8
add base_util tests
vixalien Jan 17, 2024
9b187a2
add ffipp tests
vixalien Jan 17, 2024
a2e14cb
test: add test_deps.ts file
vixalien Mar 12, 2024
c5375f1
tests: add unit/base_utils/types
vixalien Mar 12, 2024
e5530e0
tests: add types/argument/array getTypeSize
vixalien Mar 12, 2024
9f9ef61
deno: use `--unstable-ffi` instead of ambigous `--unstable`
vixalien Mar 18, 2024
f6ff1af
test: add types/argument/array.ts
vixalien May 23, 2024
716a63f
chore: use local deno_gi when imported
vixalien May 26, 2024
8d4e530
chore: add everything test
vixalien May 26, 2024
e34b2e2
chore: fix everything build generating empty file
vixalien May 26, 2024
0383f55
chore: add sample test
vixalien May 26, 2024
ff0de3c
test: add most test cases to everything.ts
vixalien May 26, 2024
4644a42
chore: add various tests for everything
vixalien May 27, 2024
0a27704
chore: rename `test` to `tests`
vixalien May 29, 2024
760efaa
chore: move everything tests to `gi` folder
vixalien May 29, 2024
9fb7e9d
tests/regress: add base regress tests
vixalien May 29, 2024
ac9d1c0
chore: dont camelCase methods in everything tests
vixalien Jun 9, 2024
a969b75
chore: dont camelCase methods in regress tests
vixalien Jun 9, 2024
1675887
chore: add range check for number arguments
vixalien Jun 10, 2024
aa244c6
chore: add implicit conversion tests
vixalien Jun 10, 2024
9ad0edd
fix: edge cases for setting numbers
vixalien Jun 10, 2024
0ab6632
ci: add CI test file
vixalien Jun 10, 2024
5551596
chore: use reflect-metadata from esm.sh
vixalien Jun 10, 2024
1d4cc21
tests: remove everything tests
vixalien Jun 10, 2024
e1b64ea
chore: fix fmt and lint
vixalien Jun 10, 2024
aa6e106
update deno.json
ahgilak Jun 15, 2024
3d5ea23
fix
ahgilak Jun 15, 2024
cf56ea0
fix deno.json
ahgilak Jun 15, 2024
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
41 changes: 41 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Meson Tests

on:
workflow_dispatch:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: denoland/setup-deno@v1
with:
deno-version: v1.x

- name: Install Dependencies
run: |
sudo apt-get update
sudo apt-get install meson libglib2.0-dev

- name: Create Build Environment
run: meson setup ${{github.workspace}}/build

- name: Build
working-directory: ${{github.workspace}}/build
shell: bash
run: ninja

- name: Stylecheck
run: deno fmt --check

- name: Lint
run: deno lint

- name: Test
working-directory: ${{github.workspace}}/build
shell: bash
run: meson test --suite deno-gi --print-errorlogs
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.vscode/

deno.json
deno.jsonc
deno.lock
/subprojects
11 changes: 11 additions & 0 deletions deno.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"unstable": ["ffi"],
"lock": false,
"tasks": {
"test": "deno test --unstable-ffi --allow-ffi --allow-read test/unit/**/*"
},
"imports": {
"https://github.com/ahgilak/deno_gi/raw/main/mod.ts": "./mod.ts"
},
"exclude": ["subprojects", "build"]
}
12 changes: 12 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
project(
'deno-gi',
'c',
version: 'master',
)

gnome = import('gnome')
fs = import('fs')

deno = find_program('deno', required: true)

subdir('tests')
4 changes: 4 additions & 0 deletions src/base_utils/ffipp.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// deno-lint-ignore-file no-explicit-any
type ReplaceNestedObjectType<T> = {
[K in keyof T]: T[K] extends FFIFunc<infer R, infer A>
? (...args: { [a in keyof A]: ArgType<A[a]> }) => R
Expand Down Expand Up @@ -25,6 +26,9 @@ type FFIPPType<I, O> = {
...args: { [a in keyof A]: FFIPPType<A[a], A[a]> }
): FFIFunc<O, typeof args>;
symbol: string;
size: number;
serilize: (arg_0: I) => any;
deserilize: (arg_0: any) => O;
};

type FFIFunc<R, A extends FFIPPType<any, any>[]> = {
Expand Down
2 changes: 1 addition & 1 deletion src/base_utils/ffipp.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// <reference types="./ffipp.d.ts"/>

import "npm:reflect-metadata";
import "https://esm.sh/reflect-metadata@0.2.2";
vixalien marked this conversation as resolved.
Show resolved Hide resolved

export function createType({
symbol,
Expand Down
43 changes: 43 additions & 0 deletions src/bindings/ranges.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { GITypeTag } from "https://raw.githubusercontent.com/ahgilak/deno_gi/main/src/bindings/enums.js";

export const NumberRanges = {
[GITypeTag.INT8]: [-128, 127],
[GITypeTag.INT16]: [-32_768, 32_767],
[GITypeTag.INT32]: [-2_147_483_648, 2_147_483_647],
[GITypeTag.INT64]: [-9_223_372_036_854_775_808n, 9_223_372_036_854_775_807n],
[GITypeTag.UINT8]: [0, 255],
[GITypeTag.UINT16]: [0, 65_535],
[GITypeTag.UINT32]: [0, 4_294_967_295],
[GITypeTag.UINT64]: [0, 18_446_744_073_709_551_615n],
// TODO: not sure about these, will probably not be precise
[GITypeTag.FLOAT]: [-3.4e38, 3.4e38],
[GITypeTag.DOUBLE]: [-1.8e308, 1.8e308],
// not sure
[GITypeTag.GTYPE]: [0, 18_446_744_073_709_551_615n],
};

export function ensure_number_range(
type: number,
value: number | bigint,
): void {
const range = NumberRanges[type];
if (!range) return;

// check if the number is in the given range
const [min, max] = range;
if (value >= min && value <= max) return;

// doubles & floats accept Infinity and NaN
if (type === GITypeTag.DOUBLE || type === GITypeTag.FLOAT) {
if ([Infinity, -Infinity, NaN].includes(value as number)) return;
}

// check if the type supports BigInts
if (typeof value === "bigint" && !(typeof max === "bigint")) {
throw new TypeError("can't convert BigInt to number");
}

const tag = Object.entries(GITypeTag)
.find(([_, name]) => name === type)?.[0]?.toLowerCase() ?? "type";
throw new RangeError(`value is out of range for ${tag}`);
}
88 changes: 64 additions & 24 deletions src/types/argument.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { objectByInfo } from "../utils/gobject.js";
import { boxArray, unboxArray } from "./argument/array.js";
import { boxInterface, unboxInterface } from "./argument/interface.js";
import { unboxList } from "./argument/list.js";
import { ensure_number_range } from "../bindings/ranges.ts";

export function initArgument(type) {
const tag = g.type_info.get_tag(type);
Expand Down Expand Up @@ -115,7 +116,6 @@ export function unboxArgument(type, buffer, offset) {

export function boxArgument(type, value) {
const buffer = new ArrayBuffer(8);
if (!value) return buffer;
const dataView = new ExtendedDataView(buffer);
const tag = g.type_info.get_tag(type);

Expand All @@ -124,53 +124,83 @@ export function boxArgument(type, value) {
dataView.setInt32(value);
break;

case GITypeTag.UINT8:
dataView.setUint8(value);
case GITypeTag.UINT8: {
const normalized = normalizeNumber(value);
ensure_number_range(GITypeTag.UINT8, normalized);
dataView.setUint8(normalized);
break;
}

case GITypeTag.UNICHAR:
dataView.setUint32(String(value).codePointAt(0));
break;

case GITypeTag.INT8:
dataView.setInt8(value);
case GITypeTag.INT8: {
const normalized = normalizeNumber(value);
ensure_number_range(GITypeTag.INT8, normalized);
dataView.setInt8(normalized);
break;
}

case GITypeTag.UINT16:
dataView.setUint16(value);
case GITypeTag.UINT16: {
const normalized = normalizeNumber(value);
ensure_number_range(GITypeTag.UINT16, normalized);
dataView.setUint16(normalized);
break;
}

case GITypeTag.INT16:
dataView.setInt16(value);
case GITypeTag.INT16: {
const normalized = normalizeNumber(value);
ensure_number_range(GITypeTag.INT16, normalized);
dataView.setInt16(normalized);
break;
}

case GITypeTag.UINT32:
dataView.setUint32(value);
case GITypeTag.UINT32: {
const normalized = normalizeNumber(value);
ensure_number_range(GITypeTag.UINT32, normalized);
dataView.setUint32(normalized);
break;
}

case GITypeTag.INT32:
dataView.setInt32(value);
case GITypeTag.INT32: {
const normalized = normalizeNumber(value);
ensure_number_range(GITypeTag.INT32, normalized);
dataView.setInt32(normalized);
break;
}

case GITypeTag.UINT64:
case GITypeTag.UINT64: {
const normalized = normalizeNumber(value);
ensure_number_range(GITypeTag.UINT64, normalized);
dataView.setBigUint64(
typeof value === "bigint" ? value : Math.trunc(value),
typeof normalized === "bigint" ? normalized : Math.trunc(normalized),
);
break;
}

case GITypeTag.INT64:
case GITypeTag.INT64: {
const normalized = normalizeNumber(value);
ensure_number_range(GITypeTag.INT64, normalized);
dataView.setBigInt64(
typeof value === "bigint" ? value : Math.trunc(value),
typeof normalized === "bigint" ? normalized : Math.trunc(normalized),
);
break;
}

case GITypeTag.FLOAT:
dataView.setFloat32(value);
case GITypeTag.FLOAT: {
const normalized = normalizeNumber(value, true);
ensure_number_range(GITypeTag.FLOAT, normalized);
dataView.setFloat32(normalized);
break;
}

case GITypeTag.DOUBLE:
dataView.setFloat64(value);
case GITypeTag.DOUBLE: {
const normalized = normalizeNumber(value, true);
ensure_number_range(GITypeTag.DOUBLE, normalized);
dataView.setFloat64(normalized);
break;
}

case GITypeTag.UTF8:
case GITypeTag.FILENAME:
Expand All @@ -180,6 +210,7 @@ export function boxArgument(type, value) {
break;

case GITypeTag.GTYPE:
ensure_number_range(GITypeTag.GTYPE, value);
dataView.setBigUint64(value);
break;

Expand All @@ -190,9 +221,12 @@ export function boxArgument(type, value) {
value = boxArray(type, value);
}

dataView.setBigUint64(
cast_ptr_u64(cast_buf_ptr(value)),
);
if (value) {
dataView.setBigUint64(
cast_ptr_u64(cast_buf_ptr(value)),
);
}

break;
}

Expand All @@ -208,3 +242,9 @@ export function boxArgument(type, value) {

return buffer;
}

function normalizeNumber(value, allowNaN = false) {
if (value === undefined) return 0;
if (allowNaN && isNaN(value)) return NaN;
return value || 0;
}
17 changes: 16 additions & 1 deletion src/types/argument/array.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import { GITypeTag } from "../../bindings/enums.js";
import g from "../../bindings/mod.js";
import { boxArgument, unboxArgument } from "../argument.js";

function getTypeSize(typeTag) {
/**
* @param {number} typeTag
* @returns {number}
*/
export function getTypeSize(typeTag) {
switch (typeTag) {
case GITypeTag.BOOLEAN:
return 1 << 2;
Expand Down Expand Up @@ -35,6 +39,12 @@ function getTypeSize(typeTag) {
}
}

/**
* @param {Deno.PointerValue} type
* @param {number | bigint} pointer
* @param {number} length
* @returns {import("../../base_utils/ffipp.d.ts").TypedArray}
*/
export function unboxArray(type, pointer, length) {
if (!pointer) {
return null;
Expand Down Expand Up @@ -64,6 +74,11 @@ export function unboxArray(type, pointer, length) {
return result;
}

/**
* @param {Deno.PointerValue} typeInfo
* @param {any[]} values
* @returns {Uint8Array}
*/
export function boxArray(typeInfo, values) {
const isZeroTerminated = g.type_info.is_zero_terminated(typeInfo);

Expand Down
23 changes: 17 additions & 6 deletions src/types/callable.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { createCallback } from "./callback.js";

export function createArg(info) {
const type = g.arg_info.get_type(info);
const name = g.base_info.get_name(info);
const arrLength = g.type_info.get_array_length(type);
const isSkip = g.arg_info.is_skip(info);
const direction = g.arg_info.get_direction(info);
Expand All @@ -24,6 +25,7 @@ export function createArg(info) {
const isReturn = g.arg_info.is_return_value(info);
return {
type,
name,
arrLength,
isSkip,
direction,
Expand Down Expand Up @@ -58,12 +60,21 @@ export function parseCallableArgs(info) {

for (let i = 0; i < inArgsDetail.length; i++) {
const detail = inArgsDetail[i];
const value = args.shift();
const pointer = new ExtendedDataView(boxArgument(detail.type, value))
.getBigUint64();
inArgs[i] = pointer;
if (detail.lengthArg >= 0) {
inArgs[detail.lengthArg] = value.length || value.byteLength || 0;

try {
const value = args.shift();
const pointer = new ExtendedDataView(boxArgument(detail.type, value))
.getBigUint64();
inArgs[i] = pointer;
if (detail.lengthArg >= 0) {
inArgs[detail.lengthArg] = value.length || value.byteLength || 0;
}
} catch (error) {
if (error instanceof RangeError) {
error.message = `Argument ${detail.name}: ${error.message}`;
}

throw error;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/types/interface.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export function createInterface(info, gType) {
};

Object.defineProperty(ObjectClass, "name", {
value: getDisplayName(gType),
value: getDisplayName(info),
});

Reflect.defineMetadata("gi:gtype", gType, ObjectClass);
Expand Down
8 changes: 8 additions & 0 deletions subprojects/gobject-introspection.wrap
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[wrap-git]
directory = gobject-introspection
url = https://gitlab.gnome.org/GNOME/gobject-introspection.git
revision = 1.80.1
depth = 1

[provide]
program_names = g-ir-scanner, g-ir-compiler
3 changes: 3 additions & 0 deletions tests/gi/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
gi_dep = subproject('gobject-introspection')

subdir('regress')
Loading