When I try to run the following test:
import 'package:my_project/my_file.dart';
import 'package:test/test.dart';
void main() {
group('int extensions:', () {
expect(1.digits(), 1);
expect(10.digits(), 2);
expect(100.digits(), 3);
});
}
I get the following error message:
Failed to load "test/my_file_test.dart": Instance of 'OutsideTestException'
The answer is probably obvious most people coming here now, but it took me a while to realize what was wrong. I'm adding my answer below for other people with the same problem.
You need to call test and not just group:
void main() {
group('int extensions:', () {
test('digits', () {
expect(1.digits(), 1);
expect(10.digits(), 2);
expect(100.digits(), 3);
});
});
}
Related
This is the first time I'm trying the bridging of react-native and a native iOS app.
In my react-native iOS project, I've created a swift file (that created a bridging header) and in that swift file I've created a sample method to test first:
import Foundation
#objc(MyModule)
class MyModule: NSObject {
#objc
func testFunctionWithPromiseResolve(frame: Frame,
resolver resolve: #escaping RCTPromiseResolveBlock,
rejecter reject: #escaping RCTPromiseRejectBlock) {
var resp = [String:Any]() //Init Dictionary
resp.updateValue(frame, forKey: "frame");
resolve(resp);
}
#objc
static func requiresMainQueueSetup() -> Bool {
return true
}
}
In the bridging header file I have imports only:
#import "React/RCTBridgeModule.h"
#import <VisionCamera/FrameProcessorPlugin.h>. //from react-native-vision-camera
#import <VisionCamera/Frame.h> //from react-native-vision-camera
Then I created an objective-c file named MyModule.m and in it, I've added:
#import <Foundation/Foundation.h>
#import "React/RCTBridgeModule.h"
#interface
RCT_EXTERN_MODULE(MyModule, NSObject);
RCT_EXTERN_METHOD(testFunctionWithPromiseResolve:
(Frame *)frame
resolver:(RCTPromiseResolveBlock *)resolve
rejecter:(RCTPromiseRejectBlock *)reject);
#end
Then in react-native, I have a Home.js where I'm going to access this method.
import React from 'react';
import { Text, StyleSheet, ScrollView, NativeModules } from 'react-native';
import { Camera, useCameraDevices, useFrameProcessor } from 'react-native-vision-camera';
import 'react-native-reanimated'
function Home(props) {
const devices = useCameraDevices();
const device = devices.back;
const { MyModule } = NativeModules;
const frameProcessor = useFrameProcessor((frame) => {
'worklet';
let res = MyModule.testFunctionWithPromiseResolve(frame);
console.log(res);
// .then((res) => {
// console.log(res);
// }).catch((e) => {
// console.log(e);
// })
})
//... My other code is just UI-related in which I'm calling the frameProcessor in <Camera... using its prop frameProcessor={frameProcessor} as per react-native-vision-camera documentation.
As per my understanding, we handle a Promise with then and catch as I assume this is what we'll be getting from RCTPromiseResolveBlock but that was not working so I just simply tried console.log(res); and it prints undefined.
The error I'm getting is:
Tried to synchronously call function {promiseMethodWrapper} from a different thread.
Possible solutions are:
a) If you want to synchronously execute this method, mark it as a Worklet
b) If you want to execute this method on the JS thread, wrap it using runOnJS
reanimated::REAIOSErrorHandler::raiseSpec()
REAIOSErrorHandler.mm:18
reanimated::ErrorHandler::raise()::'lambda'()::operator()()
decltype(static_cast<reanimated::ErrorHandler::raise()::'lambda'()&>(fp)()) std::__1::__invoke<reanimated::ErrorHandler::raise()::'lambda'()&>(reanimated::ErrorHandler::raise()::'lambda'()&)
void std::__1::__invoke_void_return_wrapper<void, true>::__call<reanimated::ErrorHandler::raise()::'lambda'()&>(reanimated::ErrorHandler::raise()::'lambda'()&)
std::__1::__function::__alloc_func<reanimated::ErrorHandler::raise()::'lambda'(), std::__1::allocator<reanimated::ErrorHandler::raise()::'lambda'()>, void ()>::operator()()
std::__1::__function::__func<reanimated::ErrorHandler::raise()::'lambda'(), std::__1::allocator<reanimated::ErrorHandler::raise()::'lambda'()>, void ()>::operator()()
std::__1::__function::__value_func<void ()>::operator()() const
std::__1::function<void ()>::operator()() const
invocation function for block in vision::VisionCameraScheduler::scheduleOnUI(std::__1::function<void ()>)
F14F0161-E0DE-3D9C-851E-AD12F95A3073
F14F0161-E0DE-3D9C-851E-AD12F95A3073
F14F0161-E0DE-3D9C-851E-AD12F95A3073
F14F0161-E0DE-3D9C-851E-AD12F95A3073
F14F0161-E0DE-3D9C-851E-AD12F95A3073
_pthread_wqthread
start_wqthread
I've worklet defined in the useFrameProcessor.
UPDATE:
I've updated the obj-c method to:
#objc(testFunctionWithPromiseResolve:resolver:rejecter:)
func testFunctionWithPromiseResolve(_ frame: Frame,
resolver resolve: #escaping RCTPromiseResolveBlock,
rejecter reject: #escaping RCTPromiseRejectBlock) {...
and the in JS I did:
let module = NativeModules.MyModule;
const frameProcessor = useFrameProcessor((frame) => {
'worklet';
//let module = NativeModules.MyModule; //didnt work either
console.log(module.testFunctionWithPromiseResolve(frame));
})
But I get the same error:
Luckily I found the problem.
Custom Frame Processor Plugins need to be completed according to the document, the document address is Creating Frame Processor Plugins, native-side customize code that you need to use the VISION_EXPORT_FRAME_PROCESSOR export definition plugin, and using RCT_EXTERN_MODULE and RCT_EXTERN_METHOD will fails.
You need to export custom plug-in methods on the js side, the document address is Expose your Frame Processor Plugin to JS, as follows:
import type { Frame } from 'react-native-vision-camera'
/**
* Scans QR codes.
*/
export function scanQRCodes(frame: Frame): string[] {
'worklet'
return __scanQRCodes(frame)
}
but now ,this will be __scanQRCodes:
module.exports = {
plugins: [
[
'react-native-reanimated/plugin',
{
globals: ['__scanQRCodes'],
},
],
you have to restart metro-bundler for changes in the babel.config.js file to take effect.
3: you must be restarted project to take effect.
My code is as follows:
I customized a Ojective-C frame Processor Plugins named MyModuleFrameProcessPlugin.m, the code is implemented as follows:
#import <VisionCamera/FrameProcessorPlugin.h>
#import <VisionCamera/Frame.h>
#interface MyModuleFrameProcessPlugin : NSObject
#end
#implementation MyModuleFrameProcessPlugin
static inline id myCustomPlugin(Frame* frame, NSArray* arguments) {
CVPixelBufferRef imageBuffer = CMSampleBufferGetImageBuffer(frame.buffer);
NSLog(#"myCustomPlugin: %zu x %zu Image. Logging %lu parameters:", CVPixelBufferGetWidth(imageBuffer), CVPixelBufferGetHeight(imageBuffer), (unsigned long)arguments.count);
for (id param in arguments) {
NSLog(#"myCustomPlugin: -> %# (%#)", param == nil ? #"(nil)" : [param description], NSStringFromClass([param classForCoder]));
}
return #{
#"myCustomPlugin_str": #"Test",
#"myCustomPlugin_bool": #true,
#"myCustomPlugin_double": #5.3,
#"myCustomPlugin_array": #[
#"Hello",
#true,
#17.38
]
};
}
VISION_EXPORT_FRAME_PROCESSOR(myCustomPlugin)
#end
Create a new js plugin named ExamplePlugin.ts, the code is as follows:
/* global __myCustomPlugin */
import type { Frame } from 'react-native-vision-camera';
declare let _WORKLET: true | undefined;
export function cusPlugin(frame: Frame): string[] {
'worklet';
if (!_WORKLET) throw new Error('my_custom_plugin must be called from a frame processor!');
// #ts-expect-error because this function is dynamically injected by VisionCamera
return __myCustomPlugin(frame, 'hello my_custom_plugin!', 'parameter2', true, 42, { test: 0, second: 'test' }, ['another test', 500]);
}
The babel.config.js file is as follows:
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'react-native-reanimated/plugin',
{
globals: ['__myCustomPlugin']
}
]
],
};
The plugin import code is as follows:
import {cusPlugin} from './ExamplePlugin';
The calling code is as follows:
const frameProcessor = useFrameProcessor((frame) => {
'worklet';
const value = cusPlugin(frame);
console.log(`Return Values: ${JSON.stringify(value)}`);
}, []);
//Use in Camera is frameProcessor={frameProcessor}
I tested my code and it is ok, I hope it can help you.
I am trying to use dart isolate library to improve my application performance.
Look at following code:
import 'dart:isolate';
import 'package:dbcrypt/dbcrypt.dart';
main() {
var pwConPort = new ReceivePort();
pwConPort.listen((data) {
print(data);
pwConPort.close();
}, onError: (err) {
print(err);
});
Isolate.spawn(generatePasswordConcurrency, pwConPort.sendPort);
}
void generatePasswordConcurrency(SendPort sendPort) {
sendPort.send(_generateHashPassword('Passsowr1222!'));
}
String _generateHashPassword(String password) {
var regex = new RegExp(r'^.*(?=.{7,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).*$');
if (!regex.hasMatch(password)) {
throw new StateError('Errors');
}
return new DBCrypt().hashpw(password, new DBCrypt().gensalt());
}
Everything works fine but i can only pass a static password, or better to say, i don't know, how to pass something dynamically. Here you can see, password is hardcoded, but i want to pass a variable for example.
void generatePasswordConcurrency(SendPort sendPort) {
sendPort.send(_generateHashPassword('Passsowr1222!'));
}
If the method _generateHashPassword will throw an error, how can I handling this error? I try to catch the error on listen method from ReceivePort
pwConPort.listen((data) {
print(data);
pwConPort.close();
}, onError: (err) {
print(err);
});
but still got unhandling exceptions message.
Observatory listening on http://127.0.0.1:51433
in ShutdownIsolate: Unhandled exception:
Bad state: Errors
#0 _generateHashPassword (file:///D:/Dart/samples/bin/isolate_error.dart:26:9)
#1 generatePasswordConcurrency (file:///D:/Dart/samples/bin/isolate_error.dart:19:40)
#2 _startIsolate.isolateStartHandler (dart:isolate-patch/isolate_patch.dart:221)
#3 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:124)
Conclusion my question:
How can I pass a variable to called method on isolate?
How can I handling error on isolate?
First of all,
Isolate are not thread, they are independant process more like a fork() than a thread
dartApi: Isolate
Concurrent programming using isolates:
independent workers that are similar to threads but don't share memory, communicating only via
messages.
So, you can't access to the same variable than your parent process. It's a choice made by the dart team, because it's a mechanism usable when you compile your dart code in js. So it need to be possible in JS
How can I pass a variable to called method on isolate?
To do this, you need to see ReceivePort() like a unidirectionnal way of communication, so to pass variable in two way, you need two.
So on you main process:
pwConPort.listen((data) {
if (isolateSendPort == null && data is SendPort) {
isolateSendPort = data; // Receive the communication object of the isolate
isolateSendPort.send("Passsowr1222!");
} else {
print("Generated password: ${data}");
pwConPort.close();
}
}, onError: (err) {
print("SendPortError: ${err}");
});
});
In you isolate entry point :
sendPort.send(isolateConPort.sendPort);
isolateConPort.listen((data) {
// code ....
});
Note: be careful of what message you send. message send between one process and another need to respect some rules
DartApi: SendPort
The content of message can be: primitive values (null, num, bool,
double, String), instances of SendPort, and lists and maps whose
elements are any of these. List and maps are also allowed to be
cyclic.
How can I handling error on isolate?
Isolate get one method to listen throw error send by the isolate : addErrorListner
That is a useful function.
BUT ! this method is not implement in every plate-forme, so you need to do this in a others.
The way i chose is to send 2 SendPort in the entry point function :
One for the communication
One for the error.
So the spawn function looks like :
Isolate.spawn(generatePasswordConcurrency, [pwConPort.sendPort, errorPort.sendPort])
and the generatePasswordConcurrency :
void generatePasswordConcurrency(List<SendPort> commList) {
var sendPort = commList[0];
var errorPort = commList[1];
var isolateConPort = new ReceivePort();
sendPort.send(isolateConPort.sendPort);
isolateConPort.listen((data) {
try {
sendPort.send(_generateHashPassword(data));
} catch (e) {
errorPort.send("error: ${e.toString()}");
}
});
}
Here the full code :
import 'dart:isolate';
import 'package:dbcrypt/dbcrypt.dart';
main() {
var pwConPort = new ReceivePort();
var errorPort = new ReceivePort();
SendPort isolateSendPort = null;
Isolate.spawn(generatePasswordConcurrency, [pwConPort.sendPort, errorPort.sendPort])
.then((Isolate pcs) {
errorPort.listen((err) {
print("Error: ${err}");
pwConPort.close();
errorPort.close();
});
print(pcs);
pwConPort.listen((data) {
if (isolateSendPort == null && data is SendPort) {
isolateSendPort = data;
isolateSendPort.send("Passsowr1222!");
} else {
print("Generated password: ${data}");
pwConPort.close();
errorPort.close();
//pcs.kill();
}
}, onError: (err) {
print("SendPortError: ${err}");
});
});
}
void generatePasswordConcurrency(List<SendPort> commList) {
var sendPort = commList[0];
var errorPort = commList[1];
var isolateConPort = new ReceivePort();
sendPort.send(isolateConPort.sendPort);
isolateConPort.listen((data) {
try {
sendPort.send(_generateHashPassword(data));
} catch (e) {
errorPort.send("error: ${e.toString()}");
}
});
}
String _generateHashPassword(String password) {
var regex = new RegExp(r'^.*(?=.{7,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).*$');
if (!regex.hasMatch(password)) {
throw new StateError('Errors');
}
return new DBCrypt().hashpw(password, new DBCrypt().gensalt());
}
i am trying to understand, how dart future exception works. I read a very good article about it link. But when i have nested future and the first of them throw an error, how can i handle this error on the second future.
To clarify, what i mean look at the following sample.
import 'dart:async';
void main() {
var fur1 = new Future<int>(() => 45);
fur1.then((value) {
throw new StateError('Hello error');
});
var fur2 = new Future<int>(() => 24);
fur2.then((value) {
fur1.then((value1) {
print(value1);
});
print(value);
}).catchError((err) => print(err));
}
In the fur1, i throw an exception and expected to catch the error in the fur2, but the compiler show message
Unhandled exception: Bad state: Hello error
It is possible to handle nested error in future? I know, i could use here the completer class, maybe it would be the solution?
I'm not sure what you actually try to accomplish.
but for me it works this way
import 'dart:async';
void main() {
var fur1 = new Future<int>(() => 45);
// fur1.then((value) {
// throw new StateError('Hello error');
// });
var fur2 = new Future<int>(() => 24);
fur2.then((value) {
var x = fur1.then((value1) {
print(value1);
throw new StateError('Hello error'); // <= inner exception
});
print(value);
return x; // <= return future
}).catchError((err) => print('catchError: ${err}'));
}
or this way
import 'dart:async';
void main() {
var fur1 = new Future<int>(() => 45);
fur1.then((value) {
throw new StateError('Hello1 error');
}).catchError((err) => print('catchError1: ${err}'));
var fur2 = new Future<int>(() => 24);
fur2.then((value) {
var x = fur1.then((value1) {
print(value1);
throw new StateError('Hello2 error'); // <= inner exception
});
print(value);
return x; // <= return future
}).catchError((err) => print('catchError2: ${err}'));
}
catchError1: Bad state: Hello1 error
24
45
catchError2: Bad state: Hello2 error
Here is a very simple code that I run using command line dart to demonstrate my point:
import 'dart:isolate';
void isolateMain() {
throw new Exception("ouch");
}
bool handleException(IsolateUnhandledException e) {
print("EXCEPTION in isolate: " + e.toString());
return true;
}
void main() {
SendPort sendPort = spawnFunction(isolateMain, handleException);
sendPort.call("Hello").then((e) {
print("Main received " + e);
});
}
and the output:
Exception: ouch
#0 isolateMain (file:///Users/salomon/Workspaces/eclipse/Deployer_Server/bin/deployer_server.dart:7:3)
So, turns out the unhandledExceptionCallback is never called whereas the isolate does throw an exception.
For the record :
> dart --version
Dart VM version: 0.5.20.4_r24275 (Fri Jun 21 05:02:50 2013) on "macos_x64"
So, can someone explain me what did I do wrong ?
Thanks ;)
I don't know if you did wrong, it could be a bug. But it seems exceptions thrown in the isolate's main function aren't caught by the handler. If you change it like this:
import 'dart:isolate';
void isolateMain() {
port.receive((whatever, mahPort) {
throw new Exception("$whatever");
});
}
bool handleException(IsolateUnhandledException e) {
print("EXCEPTION in isolate: ${e.toString()}");
return true;
}
void main() {
SendPort sendPort = spawnFunction(isolateMain, handleException);
sendPort.call("Hello").then((e) {
print("Main received $e");
});
}
... then handleException() will be called.
I'm trying to use Salesforce's sforce library to place an Ajax call to salesforce. Here is the example javascript that is working:
function setupPage() {
var state = { //state that you need when the callback is called
output : document.getElementById("output"),
startTime : new Date().getTime()};
var callback = {
//call layoutResult if the request is successful
onSuccess: layoutResults,
//call queryFailed if the api request fails
onFailure: queryFailed,
source: state};
sforce.connection.query(
"Select Id, Name, Industry From Account order by Industry",
callback);
}
function queryFailed(error, source) {
// not shown function code
}
function layoutResults(queryResult, source) {
// not shown function code
}
Here's my dart implementation:
import 'dart:html';
import 'package:js/js.dart' as js;
import 'dart:json';
void main() {
js.scoped(() {
var sforce = js.context.sforce;
var callbackSuccess = new js.Callback.once(success);
var callbackFailed = new js.Callback.once(failure);
var sfdc = new js.Proxy(sforce.connection.query("Select Id, Name, Industry From Account order by Industry"),
js.map({"onSuccess" : callbackSuccess, "onFailure" : callbackFailed}));
});
}
void success(queryResult) {
print("queryResult is: " + queryResult);
}
void failure(error) {
print("error is: " + error);
}
The Ajax call is being placed, as I see the POST request being made and returning data. However, I always seem to get this error (and I've tried countless different combinations):
Uncaught TypeError: object is not a function (program):370
construct (program):370
ReceivePortSync.dispatchCall darttest:178
$$._JsSendPortSync.callSync$1 minidartjs:4929
$.Proxy_Proxy$withArgList minidartjs:8194
$.Proxy_Proxy minidartjs:8183
$$.main_anon.call$0 minidartjs:6057
$.scoped minidartjs:8136
$.main minidartjs:8066
$$._IsolateContext.eval$1 minidartjs:276
$.startRootIsolate minidartjs:6533
(anonymous function)
Any help would be greatly appreciated, as I'm not sure where to turn at this point.
You get this error because you try to create a js.Proxy (sfdc) with the result of sforce.connection.query(...) . When you use new js.Proxy(f), f must be a js.Proxy of a js function. Here you get an object and that's why you get the error.
Here's the code that should work.
import 'dart:html';
import 'package:js/js.dart' as js;
import 'dart:json';
void main() {
js.scoped(() {
var sforce = js.context.sforce;
var callbackSuccess = new js.Callback.once(success);
var callbackFailed = new js.Callback.once(failure);
sforce.connection.query("Select Id, Name, Industry From Account order by Industry",
js.map({"onSuccess" : callbackSuccess, "onFailure" : callbackFailed}));
});
}
void success(queryResult, source) {
print("queryResult is: " + queryResult);
}
void failure(error, source) {
print("error is: " + error);
}