From 23dd40ea4c7d5340bdd18e9c3b2107a179e23850 Mon Sep 17 00:00:00 2001 From: Jonathan Buchanan Date: Mon, 7 Jun 2021 19:46:48 -0400 Subject: continue implementing node wrapper & tests --- .gitmodules | 3 + Taler.xcodeproj/project.pbxproj | 4 + Taler/AppDelegate.swift | 25 +++--- Taler/ContentView.swift | 22 +++-- Taler/NodeWrapper.swift | 106 +++++++++++++++++++----- Taler/SceneDelegate.swift | 22 +++-- Taler/Taler-Bridging-Header.h | 16 ++++ Taler/node_wrapper.cpp | 170 +++++++++++++++++++------------------- Taler/node_wrapper.h | 44 ++++++---- TalerTests/NodeWrapperTests.swift | 56 ++++++++++--- TalerTests/TalerTests.swift | 22 +++-- TalerUITests/TalerUITests.swift | 22 +++-- bootstrap | 19 +++++ ios-node-v8 | 1 + 14 files changed, 358 insertions(+), 174 deletions(-) create mode 100755 bootstrap create mode 160000 ios-node-v8 diff --git a/.gitmodules b/.gitmodules index acf60f4..7cfee13 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "wallet-kotlin"] path = wallet-kotlin url = https://git.taler.net/wallet-kotlin.git +[submodule "ios-node-v8"] + path = ios-node-v8 + url = git://git.taler.net/ios-node-v8.git diff --git a/Taler.xcodeproj/project.pbxproj b/Taler.xcodeproj/project.pbxproj index 71ac395..539c072 100644 --- a/Taler.xcodeproj/project.pbxproj +++ b/Taler.xcodeproj/project.pbxproj @@ -791,7 +791,9 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = TalerTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.6; LD_RUNPATH_SEARCH_PATHS = ( @@ -812,7 +814,9 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = TalerTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.6; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Taler/AppDelegate.swift b/Taler/AppDelegate.swift index e5e6bcd..1f07a98 100644 --- a/Taler/AppDelegate.swift +++ b/Taler/AppDelegate.swift @@ -1,10 +1,18 @@ -// -// AppDelegate.swift -// Taler -// -// Created by Jonathan Buchanan on 7/29/20. -// Copyright © 2020 Taler. All rights reserved. -// +/* + * This file is part of GNU Taler + * (C) 2021 Taler Systems S.A. + * + * GNU Taler is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3, or (at your option) any later version. + * + * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * GNU Taler; see the file COPYING. If not, see + */ import UIKit @@ -15,9 +23,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. - var iono = Iono(); - print(iono.evalJS(source: "1 + 1")) - iono.evalJS(source: "console.log(\"test!\");"); return true } diff --git a/Taler/ContentView.swift b/Taler/ContentView.swift index aa94941..4406fc3 100644 --- a/Taler/ContentView.swift +++ b/Taler/ContentView.swift @@ -1,10 +1,18 @@ -// -// ContentView.swift -// Taler -// -// Created by Jonathan Buchanan on 7/29/20. -// Copyright © 2020 Taler. All rights reserved. -// +/* + * This file is part of GNU Taler + * (C) 2021 Taler Systems S.A. + * + * GNU Taler is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3, or (at your option) any later version. + * + * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * GNU Taler; see the file COPYING. If not, see + */ import SwiftUI diff --git a/Taler/NodeWrapper.swift b/Taler/NodeWrapper.swift index 60ca92b..ec0ba58 100644 --- a/Taler/NodeWrapper.swift +++ b/Taler/NodeWrapper.swift @@ -1,49 +1,111 @@ -// -// NodeWrapper.swift -// Taler -// -// Created by Jonathan Buchanan on 1/14/21. -// Copyright © 2021 Taler. All rights reserved. -// +/* + * This file is part of GNU Taler + * (C) 2021 Taler Systems S.A. + * + * GNU Taler is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3, or (at your option) any later version. + * + * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * GNU Taler; see the file COPYING. If not, see + */ import Foundation +protocol IonoMessageHandler { + func handleMessage(message: String) +} + +func notification_callback(payload: Optional>, + userdata: Optional) { + let native = Unmanaged.fromOpaque(userdata!).takeUnretainedValue() + let string = String(cString: payload!) + native.internalOnNotify(payload: string) +} + class Iono { - var __instance: OpaquePointer - var messageHandler: ((String) -> ())? + var instance: OpaquePointer! + var work_queue: DispatchQueue + var initialization_group: DispatchGroup + var messageHandler: IonoMessageHandler? init() { - __instance = __new_instance() + work_queue = DispatchQueue(label: "NodeQueue", qos: .userInitiated) + initialization_group = DispatchGroup() + initialization_group.notify(queue: work_queue) { + self.instance = __initNative() + __setNotifyHandler(self.instance, notification_callback, Unmanaged.passUnretained(self).toOpaque()) + } } deinit { - __free_instance(__instance) + __destroyNative(instance) + } + + private func scheduleNodeThreadAsync(block: @escaping () -> Void) { + initialization_group.wait() + work_queue.async(execute: block) + notifyNative() + } + + private func scheduleNodeThreadSync(block: @escaping () -> Void) { + initialization_group.wait() + work_queue.sync(execute: block) + notifyNative() + } + + func internalOnNotify(payload: String) { + if let handler = messageHandler { + handler.handleMessage(message: payload) + } } func notifyNative() { - + initialization_group.wait() + __notifyNative(instance) } - func evalJS(source: String) -> String { - var result_cstr: UnsafeMutablePointer = __eval_js(source.cString(using: .utf8), __instance) - var result = String(cString: result_cstr) - free(result_cstr) - return result + func evalSimpleJs(source: String) -> String { + var result: String? + scheduleNodeThreadSync { + let cResult = __evalJs(self.instance, source.cString(using: .utf8)) + if let cStr = cResult { + result = String(cString: cStr) + free(cResult) + } + } + return result! } func evalNodeCode(source: String) { - __make_callback(source.cString(using: .utf8), __instance) + scheduleNodeThreadAsync { + __makeCallbackNative(self.instance, source.cString(using: .utf8)) + } } func sendMessage(message: String) { - + let encoded = message.data(using: .utf8)!.base64EncodedString() + let source = """ + if (global.__iono_onMessage) { + const msg = (new Buffer('\(encoded)', 'base64')).toString('ascii'); + global.__iono_onMessage(msg); + } else { + console.log("WARN: no __iono_onMessage defined"); + } + """ + evalNodeCode(source: source) } - func waitUntilStopped() { + func waitStopped() { } - func putModuleCode(moduleName: String, code: String) { - __put_module_code(moduleName.cString(using: .utf8), code.cString(using: .utf8), __instance) + func putModuleCode(modName: String, code: String) { + __putModuleCodeNative(instance, modName.cString(using: .utf8), + code.cString(using: .utf8)) } } diff --git a/Taler/SceneDelegate.swift b/Taler/SceneDelegate.swift index 0bdc1e4..a895f65 100644 --- a/Taler/SceneDelegate.swift +++ b/Taler/SceneDelegate.swift @@ -1,10 +1,18 @@ -// -// SceneDelegate.swift -// Taler -// -// Created by Jonathan Buchanan on 7/29/20. -// Copyright © 2020 Taler. All rights reserved. -// +/* + * This file is part of GNU Taler + * (C) 2021 Taler Systems S.A. + * + * GNU Taler is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3, or (at your option) any later version. + * + * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * GNU Taler; see the file COPYING. If not, see + */ import UIKit import SwiftUI diff --git a/Taler/Taler-Bridging-Header.h b/Taler/Taler-Bridging-Header.h index f4a0414..e7e117f 100644 --- a/Taler/Taler-Bridging-Header.h +++ b/Taler/Taler-Bridging-Header.h @@ -1,3 +1,19 @@ +/* + * This file is part of GNU Taler + * (C) 2021 Taler Systems S.A. + * + * GNU Taler is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3, or (at your option) any later version. + * + * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * GNU Taler; see the file COPYING. If not, see + */ + // // Use this file to import your target's public headers that you would like to expose to Swift. // diff --git a/Taler/node_wrapper.cpp b/Taler/node_wrapper.cpp index 7899281..cb7462d 100644 --- a/Taler/node_wrapper.cpp +++ b/Taler/node_wrapper.cpp @@ -1,10 +1,19 @@ -// -// node_wrapper.cpp -// Taler -// -// Created by Jonathan Buchanan on 12/31/20. -// Copyright © 2020 Taler. All rights reserved. -// +/* + * This file is part of GNU Taler + * (C) 2021 Taler Systems S.A. + * + * GNU Taler is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3, or (at your option) any later version. + * + * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * GNU Taler; see the file COPYING. If not, see + */ +#include "node_wrapper.h" #include #include @@ -14,24 +23,30 @@ struct __IonoInstance { + /* Node/V8 */ static std::unique_ptr platform; std::unique_ptr setup; v8::Isolate *isolate; node::Environment *env; uv_async_t async_notify; + bool break_requested; std::map modmap; + /* Notifications to swift */ + __NotifyHandler notification_handler; + void *notification_userdata; + __IonoInstance(); char * - eval_js(const char *js); + evalJs(const char *js); void - run_node(); + runNode(); void - make_callback(const char *callback); + makeCallback(const char *callback); }; #ifdef __cplusplus @@ -39,46 +54,54 @@ extern "C" { #endif struct __IonoInstance * -__new_instance() +__initNative() { __IonoInstance *instance = new __IonoInstance(); return instance; } void -__free_instance(struct __IonoInstance *instance) +__destroyNative(struct __IonoInstance *instance) { delete instance; } char * -__eval_js(const char *js, struct __IonoInstance *instance) +__evalJs(struct __IonoInstance *instance, const char *js) +{ + return instance->evalJs(js); +} + +void +__putModuleCodeNative(struct __IonoInstance *instance, + const char *modName, const char *modCode) { - return instance->eval_js(js); + instance->modmap[std::string(modName)] = std::string(modCode); } void -__notify_instance(struct __IonoInstance *instance) +__notifyNative(struct __IonoInstance *instance) { uv_async_send(&instance->async_notify); } void -__run_node(struct __IonoInstance *instance) +__runNode(struct __IonoInstance *instance) { - instance->run_node(); + instance->runNode(); } void -__make_callback(const char *callback, struct __IonoInstance *instance) +__makeCallbackNative(struct __IonoInstance *instance, const char *source) { - instance->make_callback(callback); + instance->makeCallback(source); } void -__put_module_code(const char *module_name, const char *module_code, struct __IonoInstance *instance) +__setNotifyHandler(struct __IonoInstance *instance, __NotifyHandler handler, void *userdata) { - instance->modmap[std::string(module_name)] = std::string(module_code); + instance->notification_handler = handler; + instance->notification_userdata = userdata; } #ifdef __cplusplus @@ -88,18 +111,28 @@ __put_module_code(const char *module_name, const char *module_code, struct __Ion std::unique_ptr __IonoInstance::platform = nullptr; static void -notify_callback(uv_async_t *async); +notifyCallback(uv_async_t *async); static void -send_message_callback(const v8::FunctionCallbackInfo &args); +sendMessageCallback(const v8::FunctionCallbackInfo &args); + +static const std::string main_code = "global.__node_run = (x) => {" + " 0 && console.log('running code', x);" + " global.eval(x);" + "};" + "" + "global.__iono_onMessage = (x) => {" + " 0 && console.log('got __iono_onMessage', x);" + "};"; __IonoInstance::__IonoInstance() : break_requested(false), - modmap() + modmap(), + notification_handler(nullptr) { { uv_loop_t *loop = uv_default_loop(); - uv_async_init(loop, &async_notify, ¬ify_callback); + uv_async_init(loop, &async_notify, ¬ifyCallback); async_notify.data = this; } @@ -138,15 +171,7 @@ __IonoInstance::__IonoInstance() : v8::HandleScope handle_scope(isolate); v8::Context::Scope context_scope(setup->context()); - v8::MaybeLocal loadenv_ret = node::LoadEnvironment( - env, - "const publicRequire =" - " require('module').createRequire(process.cwd() + '/');" - "globalThis.require = publicRequire;" - "global.__node_run = (x) => {" - " 0 && console.log('running code', x);" - " global.eval(x);" - "};"); + node::LoadEnvironment(env, main_code.c_str()); v8::Local data_template = v8::ObjectTemplate::New(isolate); data_template->SetInternalFieldCount(1); @@ -154,7 +179,7 @@ __IonoInstance::__IonoInstance() : data_object->SetAlignedPointerInInternalField(0, this); v8::Local sendMessageFunction = v8::Function::New(setup->context(), - send_message_callback, + sendMessageCallback, data_object).ToLocalChecked(); v8::Local global = setup->context()->Global(); @@ -166,40 +191,36 @@ __IonoInstance::__IonoInstance() : } char * -__IonoInstance::eval_js(const char *js) +__IonoInstance::evalJs(const char *js) { v8::Locker locker(isolate); v8::Isolate::Scope isolate_scope(isolate); v8::HandleScope handle_scope(isolate); v8::Context::Scope context_scope(setup->context()); - { - // Create a string containing the JavaScript source code. - v8::Local source = - v8::String::NewFromUtf8(isolate, js, v8::NewStringType::kNormal).ToLocalChecked(); + // Create a string containing the JavaScript source code. + v8::Local source = + v8::String::NewFromUtf8(isolate, js, v8::NewStringType::kNormal).ToLocalChecked(); - // Compile the source code. - v8::Local script; - - if (!v8::Script::Compile(setup->context(), source).ToLocal(&script)) { - return nullptr; - } - - // Run the script to get the result. - v8::Local result; - if (!script->Run(setup->context()).ToLocal(&result)) { - return nullptr; - } - - // Convert the result to an UTF8 string and print it. - v8::String::Utf8Value utf8(isolate, result); + // Compile the source code. + v8::Local script; + if (!v8::Script::Compile(setup->context(), source).ToLocal(&script)) { + return nullptr; + } - return strdup(*utf8); + // Run the script to get the result. + v8::Local result; + if (!script->Run(setup->context()).ToLocal(&result)) { + return nullptr; } + + // Convert the result to an UTF8 string and print it. + v8::String::Utf8Value utf8(isolate, result); + return strdup(*utf8); } void -__IonoInstance::run_node() { +__IonoInstance::runNode() { v8::Locker locker(isolate); v8::Isolate::Scope isolate_scope(isolate); v8::HandleScope handle_scope(isolate); @@ -214,7 +235,7 @@ __IonoInstance::run_node() { } void -__IonoInstance::make_callback(const char *callback) +__IonoInstance::makeCallback(const char *callback) { v8::Locker locker(isolate); v8::Isolate::Scope isolate_scope(isolate); @@ -229,16 +250,17 @@ __IonoInstance::make_callback(const char *callback) } static void -notify_callback(uv_async_t *async) { +notifyCallback(uv_async_t *async) { __IonoInstance *instance = (__IonoInstance *)async->data; instance->break_requested = true; } static void -send_message_callback(const v8::FunctionCallbackInfo &args) { +sendMessageCallback(const v8::FunctionCallbackInfo &args) { v8::Isolate *isolate = args.GetIsolate(); v8::Locker locker(isolate); - if (args.Length() < 1) return; + if (args.Length() < 1) + return; v8::HandleScope scope(isolate); v8::Local arg = args[0]; v8::String::Utf8Value value(isolate, arg); @@ -246,29 +268,5 @@ send_message_callback(const v8::FunctionCallbackInfo &args) { v8::Local data = v8::Local::Cast(args.Data()); __IonoInstance *instance = (__IonoInstance *)data->GetAlignedPointerFromInternalField(0); - - /*JNIEnv *env = myInstance->currentJniEnv; - - if (env == nullptr) { - mylog("FATAL: JNI env is nullptr"); - return; - } - - jclass clazz = env->FindClass("akono/AkonoJni"); - - if (clazz == nullptr) { - mylog("FATAL: class not found"); - return; - } - - jstring payloadStr = env->NewStringUTF(*value); - - jmethodID meth = env->GetMethodID(clazz, "internalOnNotify", "(Ljava/lang/String;)V"); - - if (meth == nullptr) { - mylog("FATAL: method not found"); - return; - } - - env->CallVoidMethod(myInstance->currentJniThiz, meth, payloadStr);*/ + instance->notification_handler(*value, instance->notification_userdata); } diff --git a/Taler/node_wrapper.h b/Taler/node_wrapper.h index 164b95e..4b9a4a1 100644 --- a/Taler/node_wrapper.h +++ b/Taler/node_wrapper.h @@ -1,11 +1,18 @@ -// -// node_wrapper.h -// Taler -// -// Created by Jonathan Buchanan on 12/31/20. -// Copyright © 2020 Taler. All rights reserved. -// - +/* + * This file is part of GNU Taler + * (C) 2021 Taler Systems S.A. + * + * GNU Taler is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3, or (at your option) any later version. + * + * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * GNU Taler; see the file COPYING. If not, see + */ #ifndef node_wrapper_h #define node_wrapper_h @@ -16,26 +23,31 @@ extern "C" { struct __IonoInstance; struct __IonoInstance * -__new_instance(); +__initNative(); void -__free_instance(struct __IonoInstance *instance); +__destroyNative(struct __IonoInstance *instance); -// result must be freed! char * -__eval_js(const char *js, struct __IonoInstance *instance); +__evalJs(struct __IonoInstance *instance, const char *source); + +void +__putModuleCodeNative(struct __IonoInstance *instance, + const char *modName, const char *modCode); void -__notify_instance(struct __IonoInstance *instance); +__notifyNative(struct __IonoInstance *instance); void -__run_node(struct __IonoInstance *instance); +__runNode(struct __IonoInstance *instance); void -__make_callback(const char *callback, struct __IonoInstance *instance); +__makeCallbackNative(struct __IonoInstance *instance, const char *source); + +typedef void (* __NotifyHandler)(const char *payload, void *userdata); void -__put_module_code(const char *module_name, const char *module_code, struct IonoInstance *instance); +__setNotifyHandler(struct __IonoInstance *instance, __NotifyHandler handler, void *userdata); #ifdef __cplusplus } diff --git a/TalerTests/NodeWrapperTests.swift b/TalerTests/NodeWrapperTests.swift index e01f1e9..63ed937 100644 --- a/TalerTests/NodeWrapperTests.swift +++ b/TalerTests/NodeWrapperTests.swift @@ -1,19 +1,45 @@ -// -// NodeWrapperTests.swift -// TalerTests -// -// Created by Jonathan Buchanan on 1/14/21. -// Copyright © 2021 Taler. All rights reserved. -// +/* + * This file is part of GNU Taler + * (C) 2021 Taler Systems S.A. + * + * GNU Taler is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3, or (at your option) any later version. + * + * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * GNU Taler; see the file COPYING. If not, see + */ import XCTest @testable import Taler +class MessageHandler: IonoMessageHandler { + var lastMessage: String? + var messageSemaphore: DispatchSemaphore + + init() { + messageSemaphore = DispatchSemaphore(value: 0) + } + + func handleMessage(message: String) { + lastMessage = message + messageSemaphore.signal() + } +} + class NodeWrapperTests: XCTestCase { var iono: Iono! + var handler: MessageHandler! override func setUpWithError() throws { iono = Iono() + handler = MessageHandler() + + iono.messageHandler = handler } override func tearDownWithError() throws { @@ -21,11 +47,17 @@ class NodeWrapperTests: XCTestCase { } func testEvalJS() throws { - XCTAssert("2" == iono.evalJS(source: "1 + 1")) - XCTAssert("36" == iono.evalJS(source: "6 * 6")) - XCTAssert("42" == iono.evalJS(source: "(()=>{let x = 42; return x;})()")) - XCTAssert("undefined" == iono.evalJS(source: "const myVal = 42")) - XCTAssert("43" == iono.evalJS(source: "myVal + 1")) + XCTAssert("2" == iono.evalSimpleJs(source: "1 + 1")) + XCTAssert("36" == iono.evalSimpleJs(source: "6 * 6")) + XCTAssert("42" == iono.evalSimpleJs(source: "(()=>{let x = 42; return x;})()")) + XCTAssert("undefined" == iono.evalSimpleJs(source: "const myVal = 42")) + XCTAssert("43" == iono.evalSimpleJs(source: "myVal + 1")) + + iono.evalNodeCode(source: "global.__iono_onMessage = (x) => { global.__iono_sendMessage(x); }") + let message = "Hello IONO" + iono.sendMessage(message: message) + handler.messageSemaphore.wait() + XCTAssert(message == handler.lastMessage) } } diff --git a/TalerTests/TalerTests.swift b/TalerTests/TalerTests.swift index 1197835..3200278 100644 --- a/TalerTests/TalerTests.swift +++ b/TalerTests/TalerTests.swift @@ -1,10 +1,18 @@ -// -// TalerTests.swift -// TalerTests -// -// Created by Jonathan Buchanan on 7/29/20. -// Copyright © 2020 Taler. All rights reserved. -// +/* + * This file is part of GNU Taler + * (C) 2021 Taler Systems S.A. + * + * GNU Taler is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3, or (at your option) any later version. + * + * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * GNU Taler; see the file COPYING. If not, see + */ import XCTest @testable import Taler diff --git a/TalerUITests/TalerUITests.swift b/TalerUITests/TalerUITests.swift index dacb17c..f99587f 100644 --- a/TalerUITests/TalerUITests.swift +++ b/TalerUITests/TalerUITests.swift @@ -1,10 +1,18 @@ -// -// TalerUITests.swift -// TalerUITests -// -// Created by Jonathan Buchanan on 7/29/20. -// Copyright © 2020 Taler. All rights reserved. -// +/* + * This file is part of GNU Taler + * (C) 2021 Taler Systems S.A. + * + * GNU Taler is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3, or (at your option) any later version. + * + * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * GNU Taler; see the file COPYING. If not, see + */ import XCTest diff --git a/bootstrap b/bootstrap new file mode 100755 index 0000000..793b682 --- /dev/null +++ b/bootstrap @@ -0,0 +1,19 @@ +#!/bin/sh + +# Bootstrap the repository. Used when the repository is checked out from git. +# When using the source tarball, running this script is not necessary. + +set -eu + +if ! git --version >/dev/null; then + echo "git not installed" + exit 1 +fi + +git submodule sync --recursive +git submodule update --init --recursive + +cd ios-node-v8 +./taler-ios-build/x64 +./taler-ios-build/arm64 +cd .. diff --git a/ios-node-v8 b/ios-node-v8 new file mode 160000 index 0000000..e046b41 --- /dev/null +++ b/ios-node-v8 @@ -0,0 +1 @@ +Subproject commit e046b4133c98e830c445f36554030a0656567bcf -- cgit v1.2.3