In testing the following code:
package logHandler
import (
"ezsoft/apiserver_sdk/context"
"github.com/hsoshiant/web"
)
// Build simply builds a log handler router
//
// Parameters:
//
// - `mainRouter` : the main Router
//
// Returns:
//
// - a sub Router made specifically for logging
func Build(mainRouter *web.Router) *web.Router {
return mainRouter.Subrouter(context.Context{}, "/log").
Post("/", doLog)
}
I hit a panic. context.Context is defined thus:
//BaseContext contains all the base context to be helpful when using the utilities
type BaseContext struct {
Session session.Store
ResponseWriter *web.ResponseWriter
RequestReader *web.Request
}
//Context contains all values needed when using the utilities
type Context struct {
BaseContext
JSONBody map[string]interface{}
tokenHandler *apiToken.APITokenHandlerSt
OAuthInstance *oAuth2.OAuth2St
}
and with testability/flexibility in mind, the developers wrote the middleware functions to take context.ContextIntf, which context.Context implements, which is defined as follows:
//ContextIntf is the interface to use when using the context interface functions.
type ContextIntf interface {
SetUniversalHeaders(header map[string]string) map[string]string
GetInfo() *Context
GetOAuth() *oAuth2.OAuth2St
}
Here's one such middleware func:
//AuthenticationMiddleware Middleware which handles all of the authentication.
func AuthenticationMiddleware(mw AuthenticationMiddlewareIntf, context context.ContextIntf, w web.ResponseWriter, r *web.Request, next web.NextMiddlewareFunc) {
//Check if the url should be public.
for _, url := range mw.GetInfo().nonAuthURLs {
if url.Method == r.Method && strings.Contains(r.URL.Path, url.DomainName) {
key := utilities.GetRemoteAdd(r) + ";" + r.URL.Path
if timeSince, ok := NonAuthSecurityMap[key]; ok {
var (
timeSinceTime, _ = time.Parse(time.UnixDate, timeSince)
timeSinceDuration = time.Since(timeSinceTime)
)
if timeSinceDuration < nonAuthTimeReset {
// will sleep for `nonAuthTimeReset` - `timeSinceDuration` > 0
time.Sleep(-(timeSinceDuration - nonAuthTimeReset))
}
}
NonAuthSecurityMap[key] = time.Now().Format(time.UnixDate)
next(w, r)
return
}
}
if errSt := CheckForAuthorization(mw, context, r, w); errSt != nil {
responses.Write(w, responses.Unauthorized(*errSt))
return
}
defer context.GetInfo().Session.SessionRelease(w)
next(w, r)
}
I am unsure which middleware business functions that package web is checking, let alone what business packages they reside in, and the call stack trace returns no such clues.
The error I get is thus:
* You are adding a handler to a router with context type 'Context'
*
*
* Your handler function can have one of these signatures:
*
* // If you don't need context:
* func YourFunctionName(rw web.ResponseWriter, req *web.Request)
*
* // If you want your handler to accept a context:
* func (c *Context) YourFunctionName(rw web.ResponseWriter, req *web.Request) // or,
* func YourFunctionName(c *Context, rw web.ResponseWriter, req *web.Request)
*
* Unfortunately, your function has this signature: func(context.ContextIntf, web.ResponseWriter, *web.Request)
*
************************************************************************************************************************
Why is this requesting a Context struct, instead of the ContextIntf that it implements?!
The stack trace
Looks like this:
goroutine 20 [running]:
testing.tRunner.func1(0xc04213e1e0)
C:/Go/src/testing/testing.go:742 +0x2a4
panic(0x7633c0, 0xc0421320a0)
C:/Go/src/runtime/panic.go:502 +0x237
github.com/hsoshiant/web.validateHandler(0x778420, 0x80d8f0, 0x13, 0x8405c0, 0x7b7960)
D:/dev2017/GO/src/github.com/hsoshiant/web/router_setup.go:286 +0x242
github.com/hsoshiant/web.(*Router).addRoute(0xc042106680, 0x7eeb93, 0x4, 0x7ee4bd, 0x1, 0x778420, 0x80d8f0, 0xc042051f80)
D:/dev2017/GO/src/github.com/hsoshiant/web/router_setup.go:223 +0x94
github.com/hsoshiant/web.(*Router).Post(0xc042106680, 0x7ee4bd, 0x1, 0x778420, 0x80d8f0, 0xc042106680)
D:/dev2017/GO/src/github.com/hsoshiant/web/router_setup.go:193 +0x6f
ezsoft/apiserver_sdk/logger/logHandler.Build(0xc0421064e0, 0xc042051f40)
D:/dev2017/GO/src/ezsoft/apiserver_sdk/logger/logHandler/handler.go:20 +0xcf
ezsoft/apiserver_sdk/logger/logHandler.TestBuild.func1(0xc04213e1e0)
D:/dev2017/GO/src/ezsoft/apiserver_sdk/logger/logHandler/handler_test.go:16 +0x91
testing.tRunner(0xc04213e1e0, 0x80d8e0)
C:/Go/src/testing/testing.go:777 +0xd7
created by testing.(*T).Run
C:/Go/src/testing/testing.go:824 +0x2e7
UPDATE : It's hitting the private method doLog, which is defined thus:
func doLog(contextIntf context.ContextIntf, rw web.ResponseWriter, req *web.Request) {
var (
logType int = 0
code string = ""
message string = ""
context = contextIntf.GetInfo()
)
if val, OK := context.JSONBody["type"]; OK {
if val1, noErr := val.(float64); noErr {
logType = int(val1)
}
}
if logType == 0 {
responses.Write(rw, responses.FreeUnprocessableEntity("Type"))
return
}
if val, OK := context.JSONBody["code"]; OK {
if val1, noErr := val.(string); noErr {
code = val1
} else {
responses.Write(rw, responses.FreeUnprocessableEntity("Code"))
return
}
}
if val, OK := context.JSONBody["message"]; OK {
if val1, noErr := val.(string); noErr {
message = val1
}
}
if message == "" {
responses.Write(rw, responses.FreeUnprocessableEntity("message"))
return
}
if code > "" {
code = " (" + code + ") "
}
switch logType {
case 1:
logger.Instance.LogError(code + message)
case 2:
logger.Instance.LogWarning(code + message)
case 3:
logger.Instance.LogInfo(code + message)
default:
logger.Instance.LogWarning(code + message)
}
responses.Write(rw, responses.OK(0))
}
I still don't get why that argument needs to be a context.Context, or what I, the unit-tester, can do about it.
Related
Not using testing frameworks like MockK or Mockito seems to be becoming more and more popular. I decided to try this approach. So far so good, returning fake data is simple. But how do I verify that a function (that does not return data) has been called?
Imagine having a calss like this:
class TestToaster: Toaster {
override fun showSuccessMessage(message: String) {
throw UnsupportedOperationException()
}
override fun showSuccessMessage(message: Int) {
throw UnsupportedOperationException()
}
override fun showErrorMessage(message: String) {
throw UnsupportedOperationException()
}
override fun showErrorMessage(message: Int) {
throw UnsupportedOperationException()
}
}
With MockK I would do
verify { toaster.showSuccessMessage() }
I do not want to reinvent a wheel so decided to ask. Finding anything on Google seems to be very difficult.
Since this is a thing, I assume the point would be to totally remove mocking libraries and everything can be done without them.
The old school way to do it before any appearance of the mocking library is to manually create an implementation that is just for testing . The test implementation will store how an method is called to some internal state such that the testing codes can verify if a method is called with expected parameters by checking the related state.
For example , a very simple Toaster implementation for testing can be :
public class MockToaster implements Toaster {
public String showSuccesMessageStr ;
public Integer showSuccesMessageInt;
public String showErrorMessageStr;
public Integer showErrorMessageInt;
public void showSuccessMessage(String msg){
this.showSuccesMessageStr = msg;
}
public void showSuccessMessage(Integer msg){
this.showSuccesMessageInt = msg;
}
public void showErrorMessage(String msg){
this.showErrorMessageStr = msg;
}
public void showErrorMessage(Integer msg){
this.showErrorMessageInt = msg;
}
}
Then in your test codes , you configure the object that you want to test to use MockToaster. To verify if it does really call showSuccessMessage("foo") , you can then assert if its showSuccesMessageStr equal to foo at the end of the test.
A lot of people seem to be suggesting the very straight forward solution for this, which totally makes sense. I decided to go a bit fancy and achieve this syntax:
verify(toaster = toaster, times = 1).showErrorMessage(any<String>()).
I created simple Matchers:
inline fun <reified T> anyObject(): T {
return T::class.constructors.first().call()
}
inline fun <reified T> anyPrimitive(): T {
return when (T::class) {
Int::class -> Int.MIN_VALUE as T
Long::class -> Long.MIN_VALUE as T
Byte::class -> Byte.MIN_VALUE as T
Short::class -> Short.MIN_VALUE as T
Float::class -> Float.MIN_VALUE as T
Double::class -> Double.MIN_VALUE as T
Char::class -> Char.MIN_VALUE as T
String:: class -> "io.readian.readian.matchers.strings" as T
Boolean::class -> false as T
else -> {
throw IllegalArgumentException("Not a primitive type ${T::class}")
}
}
}
Added a map to store call count for each method to my TestToaster where the key is the name of the function and value is the count:
private var callCount: MutableMap<String, Int> = mutableMapOf()
Whenever a function gets called I increase current call count value for a method. I get current method name through reflection
val key = object {}.javaClass.enclosingMethod?.name + param::class.simpleName
addCall(key)
In oder to achieve the "fancy" syntax, I created inner subcalss for TestToaster and a verify function:
fun verify(toaster: Toaster , times: Int = 1): Toaster {
return TestToaster.InnerToaster(toaster, times)
}
That function sends current toaster instance to the inner subclass to create new instance and returns it. When I call a method of the subclass in my above syntax, the check happens. If the check passes, nothing happens and test is passed, if conditions not met - and exception is thrown.
To make it more general and extendable I created this interface:
interface TestCallVerifiable {
var callCount: MutableMap<String, Int>
val callParams: MutableMap<String, CallParam>
fun addCall(key: String, vararg param: Any) {
val currentCountValue = callCount.getOrDefault(key, 0)
callCount[key] = currentCountValue + 1
callParams[key] = CallParam(param.toMutableList())
}
abstract class InnerTestVerifiable(
private val outer: TestCallVerifiable,
private val times: Int = 1,
) {
protected val params: CallParam = CallParam(mutableListOf())
protected fun check(functionName: String) {
val actualTimes = getActualCallCount(functionName)
if (actualTimes != times) {
throw IllegalStateException(
"$functionName expected to be called $times, but actual was $actualTimes"
)
}
val callParams = outer.callParams.getOrDefault(functionName, CallParam(mutableListOf()))
val result = mutableListOf<Boolean>()
callParams.values.forEachIndexed { index, item ->
val actualParam = params.values[index]
if (item == params.values[index] || (item != actualParam && isAnyParams(actualParam))) {
result.add(true)
}
}
if (params.values.isNotEmpty() && !result.all { it } || result.isEmpty()) {
throw IllegalStateException(
"$functionName expected to be called with ${callParams.values}, but actual was with ${params.values}"
)
}
}
private fun isAnyParams(vararg param: Any): Boolean {
param.forEach {
if (it.isAnyPrimitive()) return true
}
return false
}
private fun getActualCallCount(functionName: String): Int {
return outer.callCount.getOrDefault(functionName, 0)
}
}
data class CallParam(val values: MutableList<Any> = mutableListOf())
}
Here is the complete class:
open class TestToaster : TestCallVerifiable, Toaster {
override var callCount: MutableMap<String, Int> = mutableMapOf()
override val callParams: MutableMap<String, TestCallVerifiable.CallParam> = mutableMapOf()
override fun showSuccessMessage(message: String) {
val key = object {}.javaClass.enclosingMethod?.name + message::class.simpleName
addCall(key, message)
}
override fun showSuccessMessage(message: Int) {
val key = object {}.javaClass.enclosingMethod?.name + message::class.simpleName
addCall(key, message)
}
override fun showErrorMessage(message: String) {
val key = object {}.javaClass.enclosingMethod?.name + message::class.simpleName
addCall(key, message)
}
override fun showErrorMessage(message: Int) {
val key = object {}.javaClass.enclosingMethod?.name + message::class.simpleName
addCall(key, message)
}
private class InnerToaster(
verifiable: TestCallVerifiable,
times: Int,
) : TestCallVerifiable.InnerTestVerifiable(
outer = verifiable,
times = times,
), Toaster {
override fun showSuccessMessage(message: String) {
params.values.add(message)
val functionName = object {}.javaClass.enclosingMethod?.name + message::class.simpleName
check(functionName)
}
override fun showSuccessMessage(message: Int) {
params.values.add(message)
val functionName = object {}.javaClass.enclosingMethod?.name + message::class.simpleName
check(functionName)
}
override fun showErrorMessage(message: String) {
params.values.add(message)
val functionName = object {}.javaClass.enclosingMethod?.name + message::class.simpleName
check(functionName)
}
override fun showErrorMessage(message: Int) {
params.values.add(message)
val functionName = object {}.javaClass.enclosingMethod?.name + message::class.simpleName
check(functionName)
}
}
companion object {
fun verify(toaster: Toaster, times: Int = 1): Toaster {
return InnerToaster(toaster as TestCallVerifiable, times)
}
}
}
I have not tested this extensively and it will evolve with time, but so far it works well for me.
I also wrote an article about this on Medium: https://sermilion.medium.com/unit-testing-verify-that-a-method-was-called-without-testing-frameworks-like-mockito-or-mockk-433ef8e1aff4
I have currently the following function in one file:
func pinExported(pin int) bool {
pinPath := fmt.Sprintf("/sys/class/gpio/gpio%d", pin)
if file, err := os.Stat(pinPath); err == nil && len(file.Name()) > 0 {
return true
}
return false
}
and another code part in the same file which uses the above function which looks like this:
func isGpioPinExported(gpioPin int) bool {
exported := pinExported(gpioPin)
for !exported && (timeOut < timeOutForPinExportInMilliseconds) {
timeOut++
time.Sleep(1 * time.Millisecond)
exported = pinExported(gpioPin)
}
...
So now I'm searching for an elegant way to mock/replace somehow the above pinExported function within my unit tests to test the logic inside isGpioPinExported because the function pinExported is hardware dependent (Raspberry PI).
One solution could be to make the pinExported function a parameter of isGpioPinExported
So defining a function type like this:
type pinExported func(int) int
which means I have to define isGpioPinExported like this:
isGpioPinExported(pinExported pinExported, gpioPin int) bool {
exported := pinExported(gpioPin)
for !exported && (timeOut < timeOutForPinExportInMilliseconds) {
...
}
..
}
Now I can write my unit test and define a mock/fake pinExported without a problem. So far so good. But I have about five or six of such functions which means it would result in putting five or six supplemental parameters to a function like isGpioPinExported which is simply wrong. Apart from that the question is where can I define the default implementation which are used if this is not running under test?
So based on the suggestion of mkopriva I have created an interface which looks like this (now with three functions to see how this really works):
type Raspberry interface {
isPinExported(gpioPin int) bool
valueExist(gpioPin int) bool
directionExist(gpioPin int) bool
}
Furthermore defined a structure to make the implementation for real hardware (Raspberry):
type Rasberry3Plus struct {
}
func (raspberry Rasberry3Plus) valueExist(gpioPin int) bool {
pinPath := fmt.Sprintf("%s%d/value", sysClassGPIOPin, gpioPin)
if file, err := os.Stat(pinPath); err == nil && len(file.Name()) > 0 {
return true
}
return false
}
func (raspberry Rasberry3Plus) directionExist(gpioPin int) bool {
pinPath := fmt.Sprintf("%s%d/direction", sysClassGPIOPin, gpioPin)
if file, err := os.Stat(pinPath); err == nil && len(file.Name()) > 0 {
return true
}
return false
}
func (raspberry Rasberry3Plus) isPinExported(gpioPin int) bool {
pinPath := fmt.Sprintf("%s%d", sysClassGPIOPin, gpioPin)
if file, err := os.Stat(pinPath); err == nil && len(file.Name()) > 0 {
return true
}
return false
}
and the function IsGpioPinExported which uses the above functions looks now like this (This is just an example implementation to see how the mocking testing works):
func IsGpioPinExported(raspberry Raspberry, gpioPin int) bool {
pinExported := raspberry.isPinExported(gpioPin)
valueExist := raspberry.valueExist(gpioPin)
directionExist := raspberry.directionExist(gpioPin)
return valueExist && directionExist && pinExported
}
So now the tests look like this. First I have to define a type (btw: I have decided to go with Mock):
import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"testing"
)
type mockRaspberry struct {
mock.Mock
}
func (raspMock mockRaspberry) isPinExported(gpioPin int) bool {
args := raspMock.Called(gpioPin)
return args.Bool(0)
}
func (raspMock mockRaspberry) valueExist(gpioPin int) bool {
args := raspMock.Called(gpioPin)
return args.Bool(0)
}
func (raspMock mockRaspberry) directionExist(gpioPin int) bool {
args := raspMock.Called(gpioPin)
return args.Bool(0)
}
func Test_ValueTrue_DirectionExistTrue(t *testing.T) {
testObj := new(mockRaspberry)
testObj.On("isPinExported", 5).Return(false)
testObj.On("valueExist", 5).Return(true)
testObj.On("directionExist", 5).Return(true)
exported := IsGpioPinExported(testObj, 5)
assert.Equal(t, false, exported)
}
And now it is simple to test the loigic in function IsGpioPinExported with the appropriate mocked functions with wished result. And finally the main program looks like this:
func main() {
rasberry3Plus := gpio.Rasberry3Plus{}
gpio.IsGpioPinExported(rasberry3Plus, 23)
}
I am converting Data bytes to sockaddr for getting sa_family_t
In ObjC, it is as below:
NSData * hostAddress;
- (sa_family_t)hostAddressFamily {
sa_family_t result;
result = AF_UNSPEC;
if ( (self.hostAddress != nil) && (self.hostAddress.length >= sizeof(struct sockaddr)) ) {
result = ((const struct sockaddr *) self.hostAddress.bytes)->sa_family;
}
return result;
}
In swift I am trying to convert it as below:
var hostAddress:Data?
private func hostAddressFamily() -> sa_family_t{
var result: sa_family_t = sa_family_t(AF_UNSPEC)
if (hostAddress != nil) && ((hostAddress?.count ?? 0) >= MemoryLayout<sockaddr>.size) {
// Generic parameter 'ContentType' could not be inferred
self.hostAddress!.withUnsafeBytes({ bytes in
bytes.withMemoryRebound(to: sockaddr.self, capacity: 1, {sockBytes in
result = sockBytes.pointee.sa_family
})
})
}
return result
}
Getting error : Generic parameter ‘ContentType’ could not be inferred
Look at the signature of Data.withUnsafeBytesType:
func withUnsafeBytes<ResultType, ContentType>(_ body: (Swift.UnsafePointer<ContentType>) throws -> ResultType) rethrows -> ResultType
This method is generic over ResultType and ContentType, and the ContentType is used in the argument of the closure body.
What compiler is trying to say is that it does not know what type bytes is of. Generally, to fix this type of errors, you'll want to annotate the type in the closure:
data.withUnsafeBytes { (_ bytes: UnsafePointer<...>) -> Void in ... }
Also, it's unlikely you'll need to bind the memory twice since NSData is untyped, and you already specifying a type to bind it to.
Putting it all together:
func hostAddressFamily() -> sa_family_t {
var result = sa_family_t(AF_UNSPEC)
guard
let hostAddress = hostAddress,
hostAddress.count >= MemoryLayout<sockaddr>.size
else {
return result
}
hostAddress.withUnsafeBytes { (_ bytes: UnsafePointer<sockaddr>) in
result = bytes.pointee.sa_family
}
return result
}
I can't understand, how I should use UnsafeMutablePointer in Swift 3. Especially in AURenderCallback.
I try below code:
import Foundation
import AudioToolbox
let sineFrequency = 880.0
// MARK: User data struct
struct SineWavePlayer {
var outputUnit: AudioUnit? = nil
var startingFrameCount: Double = 0
}
// MARK: Callback function
let SineWaveRenderProc: AURenderCallback = {(inRefCon, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData) -> OSStatus in
var player = UnsafeMutablePointer<SineWavePlayer>(inRefCon)
var j = player.pointee.startingFrameCount
let cycleLength = 44100 / sineFrequency
for frame in 0..<inNumberFrames {
var buffers = UnsafeMutableAudioBufferListPointer(ioData)
UnsafeMutablePointer<Float32>(buffers[0].mData)[Int(frame)] = Float32(sin(2 * M_PI * (j / cycleLength)))
UnsafeMutablePointer<Float32>(buffers[1].mData)[Int(frame)] = Float32(sin(2 * M_PI * (j / cycleLength)))
// Or iterate through array:
// for buffer in buffers {
// UnsafeMutablePointer<Float32>(buffer.mData)[Int(frame)] = Float32(sin(2 * M_PI * (j / cycleLength)))
// }
j++
if j > cycleLength {
j -= cycleLength
}
}
player.pointee.startingFrameCount = j
return noErr
}
// MARK: Utility function
func CheckError(_ error: OSStatus, operation: String) {
guard error != noErr else {
return
}
var result: String = ""
var char = Int(error.bigEndian)
for _ in 0..<4 {
guard isprint(Int32(char&255)) == 1 else {
result = "\(error)"
break
}
result.append(String(describing: UnicodeScalar(char&255)))
char = char/256
}
print("Error: \(operation) (\(result))")
exit(1)
}
func CreateAndConnectOutputUnit(_ player: inout SineWavePlayer) {
// Generate a description that matches the output device (speakers)
var outputcd = AudioComponentDescription(componentType: kAudioUnitType_Output, componentSubType: kAudioUnitSubType_DefaultOutput, componentManufacturer: kAudioUnitManufacturer_Apple, componentFlags: 0, componentFlagsMask: 0)
let comp = AudioComponentFindNext(nil, &outputcd)
if comp == nil {
print("Can't get output unit")
exit(-1)
}
CheckError(AudioComponentInstanceNew(comp!, &player.outputUnit),
operation: "Couldn't open component for outputUnit")
// Register the render callback
var input = AURenderCallbackStruct(inputProc: SineWaveRenderProc, inputProcRefCon: &player)
CheckError(AudioUnitSetProperty(player.outputUnit!, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, UInt32(MemoryLayout<AURenderCallbackStruct>.size)),
operation: "AudioUnitSetProperty failed")
// Initialize the unit
CheckError(AudioUnitInitialize(player.outputUnit!),
operation: "Couldn't initialize output unit")
}
func main() {
var player = SineWavePlayer()
// Set up output unit and callback
CreateAndConnectOutputUnit(&player)
// Start playing
CheckError(AudioOutputUnitStart(player.outputUnit!),
operation: "Couldn't start output unit")
// Play for 5 seconds
sleep(5)
// Clean up
AudioOutputUnitStop(player.outputUnit!)
AudioUnitUninitialize(player.outputUnit!)
AudioComponentInstanceDispose(player.outputUnit!)
}
main()
But this line of code
var player = UnsafeMutablePointer<SineWavePlayer>(inRefCon)
is not working. How to translate this line to Swift 3?
Please, help me.
In Swift 3, initializers cannot be used to convert pointer types. In your case, the type of inRefCon is UnsafeMutableRawPointer, so you need to use assumingMemoryBound(to:) method.
And one more, the address of player passed to the callback needs to be stable all while the sound is playing, addresses taken from inout arguments (specified by & prefix) does not fulfil this requirement.
The two things above fixed, your code would be something like this:
import Foundation
import AudioToolbox
let sineFrequency = 880.0
// MARK: User data struct
struct SineWavePlayer {
var outputUnit: AudioUnit? = nil
var startingFrameCount: Double = 0
}
// MARK: Callback function
let SineWaveRenderProc: AURenderCallback = {(inRefCon, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData) -> OSStatus in
var player = inRefCon.assumingMemoryBound(to: SineWavePlayer.self)
var j = player.pointee.startingFrameCount
let cycleLength = 44100 / sineFrequency
for frame in 0..<inNumberFrames {
var buffers = UnsafeMutableAudioBufferListPointer(ioData)
buffers?[0].mData?.assumingMemoryBound(to: Float32.self)[Int(frame)] = Float32(sin(2 * M_PI * (j / cycleLength)))
buffers?[1].mData?.assumingMemoryBound(to: Float32.self)[Int(frame)] = Float32(sin(2 * M_PI * (j / cycleLength)))
j += 1
if j > cycleLength {
j -= cycleLength
}
}
player.pointee.startingFrameCount = j
return noErr
}
// MARK: Utility function
func CheckError(_ error: OSStatus, operation: String) {
guard error != noErr else {
return
}
var result: String = ""
var char = Int(error.bigEndian)
for _ in 0..<4 {
guard isprint(Int32(char&255)) == 1 else {
result = "\(error)"
break
}
result.append(String(describing: UnicodeScalar(char&255)))
char = char/256
}
print("Error: \(operation) (\(result))")
exit(1)
}
func CreateAndConnectOutputUnit(_ playerPtr: UnsafeMutablePointer<SineWavePlayer>) {
// Generate a description that matches the output device (speakers)
var outputcd = AudioComponentDescription(componentType: kAudioUnitType_Output, componentSubType: kAudioUnitSubType_DefaultOutput, componentManufacturer: kAudioUnitManufacturer_Apple, componentFlags: 0, componentFlagsMask: 0)
let comp = AudioComponentFindNext(nil, &outputcd)
if comp == nil {
print("Can't get output unit")
exit(-1)
}
CheckError(AudioComponentInstanceNew(comp!, &playerPtr.pointee.outputUnit),
operation: "Couldn't open component for outputUnit")
// Register the render callback
var input = AURenderCallbackStruct(inputProc: SineWaveRenderProc, inputProcRefCon: playerPtr)
CheckError(AudioUnitSetProperty(playerPtr.pointee.outputUnit!, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, UInt32(MemoryLayout<AURenderCallbackStruct>.size)),
operation: "AudioUnitSetProperty failed")
// Initialize the unit
CheckError(AudioUnitInitialize(playerPtr.pointee.outputUnit!),
operation: "Couldn't initialize output unit")
}
func main() {
let playerPtr = UnsafeMutablePointer<SineWavePlayer>.allocate(capacity: 1)
defer {playerPtr.deallocate(capacity: 1)}
playerPtr.initialize(to: SineWavePlayer())
defer {playerPtr.deinitialize()}
// Set up output unit and callback
CreateAndConnectOutputUnit(playerPtr)
// Start playing
CheckError(AudioOutputUnitStart(playerPtr.pointee.outputUnit!),
operation: "Couldn't start output unit")
// Play for 5 seconds
sleep(5)
// Clean up
AudioOutputUnitStop(playerPtr.pointee.outputUnit!)
AudioUnitUninitialize(playerPtr.pointee.outputUnit!)
AudioComponentInstanceDispose(playerPtr.pointee.outputUnit!)
}
I have a very basic question. Is it possible to convert a string into a closure? I tried evaluate() but it didn't work.
evaluate( "myFunction = function(val){ return dollarFormat( val ); }" );
What I have in mind is to save custom functions in the database as string and then run it as needed.
Thank you!
Edit: Just to clarify: I want to be able to save "function(val){ return dollarFormat( val ); }" as a string in database and be able to convert it into a functioning closure.
I would go with user2943775 answer:
<cfscript>
FileWrite("/ram/UDFs.cfm", "<cfset myFunction = function(val){ return dollarFormat( val ); }>")
include template="/ram/UDFs.cfm";
writedump(myFunction(10));
</cfscript>
And in your Application.cfc
component {
this.mappings["/ram"] = "ram://";
...
}
I came across a similar solution, though I was unable to use the in-memory filesystem due to security restrictions. In my Application.cfc, I added the following mapping:
this.mappings = {
"/models" = "#APP_ROOT_PATH#cfcs/models",
"/utils" = "#APP_ROOT_PATH#cfcs/utils",
"/modules" = "#APP_ROOT_PATH#_modules",
"/components" = "#APP_ROOT_PATH#cfcs",
"/udfs" = "#APP_ROOT_PATH#includes/udfs" // path for global (and temporary) UDFs
};
The UDF I created is as follows:
/**
* Takes a string representation of a function and returns it as a Closure
* #output false
* #return Closure
*/
private any function toClosure (required string closure) {
local.id = replace(createUUID(), "-", "", "all");
local.udfpath = "/udfs/udf#id#.cfm";
local.script = "<cfscript>local.fn#id# = #closure#;</cfscript>";
try {
fileWrite(expandPath(udfPath), script);
include udfpath;
} catch (any e) {
} finally {
try {
fileDelete(expandPath(udfPath));
} catch (any e) {}
}
if (!structkeyExists(local, "fn#id#") || !isClosure(local["fn#id#"])) {
throw (message="Unable to compile closure");
}
// return the closure
return local["fn#id#"];
}
And the result:
myFn = toClosure("function (num) { return num + 1; }");
myFn(1); // returns 2