I am trying to build a unit test like so:
// region is a (Double, Double) tuple
XCTAssertEqual(region, (0.0, 200.0))
But Xcode is giving me an error: Cannot invoke 'XCTAssertEqual' with an argument list of type ((Double, Double), (Double, Double))
Is there a different way to test tuples without extracting their members and testing individually?
XCTAssertEqual requires that the two parameters passed to it are Equatable, which you can see from the method signature. Note that expression1 returns T?, and T must be Equatable:
func XCTAssertEqual<T : Equatable>(_ expression1: #autoclosure () throws -> T?, _ expression2: #autoclosure () throws -> T?, _ message: #autoclosure () -> String = default, file: StaticString = #file, line: UInt = #line)
But Swift tuples aren't Equatable, so you can't use them with XCTAssertEqual.
Tuples do have an == method — they just don't conform to the protocol — so you could do something like this:
let eql = region == (0.0, 200.0)
XCTAssertTrue(eql)
Or even:
XCTAssertTrue(region == (0.0, 200.0))
Edit: I've expanded on this answer in a blog post, How to Make Specialized Test Assertions in Swift
A disadvantage of using
XCTAssertTrue(region == (0.0, 200.0))
is the inadequate reporting it gives upon failure:
XCTAssertTrue failed -
Now you have to track down what the actual values are, to understand what went wrong.
But you can add diagnostic information to the assertion like this:
XCTAssertTrue(region == (0.0, 200.0), "was \(region)")
For example:
XCTAssertTrue failed - was (1.0, 2.0)
If you plan to have several tests that compare this tuple, I wouldn't want to have to repeat this everywhere. Instead, create a custom assertion:
private func assertRegionsEqual(actual: (_: Double, _: Double), expected: (_: Double, _: Double), file: StaticString = #file, line: UInt = #line) {
if actual != expected {
XCTFail("Expected \(expected) but was \(actual)", file: file, line: line)
}
}
Now the test assertion is
assertRegionsEqual(actual: region, expected: (0.0, 200.0))
Upon failure, this yields a message like
failed - Expected (0.0, 200.0) but was (1.0, 2.0)
Related
Trying to generate a random number from the Standard Normal distribution. Need to multiply the value by 0.1 to get the number range i'm looking for. I tried using the documentation from rand_dist you can find here: https://docs.rs/rand_distr/0.3.0/rand_distr/struct.StandardNormal.html
My Cargo.toml is the following:
[package]
name = "test_rng"
version = "0.1.0"
authors = ["Jack"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rand = "0.7.3"
rand_distr = "0.3.0"
The starting rust code is the example provided in the rand_dist docs from above:
use rand::prelude::*;
use rand_distr::StandardNormal;
fn main() {
let val: f64 = thread_rng().sample(StandardNormal);
println!("{}", val);
}
When I run this it works as expected and the output is:
C:\Users\Jack\Desktop\projects\software\rust\test_rng>cargo run
Compiling test_rng v0.1.0 (C:\Users\Jack\Desktop\projects\software\rust\test_rng)
Finished dev [unoptimized + debuginfo] target(s) in 2.11s
Running `target\debug\test_rng.exe`
0.48398855288705356
C:\Users\Jack\Desktop\projects\software\rust\test_rng>
This is where I'm hitting an issue, when I try to multiply the number by 0.1 in the following code I get the resulting error:
fn main() {
let val: f64 = 0.1 * thread_rng().sample(StandardNormal);
println!("{}", val);
}
C:\Users\Jack\Desktop\projects\software\rust\test_rng>cargo run
Compiling test_rng v0.1.0 (C:\Users\Jack\Desktop\projects\software\rust\test_rng)
error[E0284]: type annotations needed: cannot satisfy `<f64 as std::ops::Mul<_>>::Output == f64`
--> src\main.rs:5:24
|
5 | let val: f64 = 0.1 * thread_rng().sample(StandardNormal);
| ^ cannot satisfy `<f64 as std::ops::Mul<_>>::Output == f64`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0284`.
error: could not compile `test_rng`.
To learn more, run the command again with --verbose.
C:\Users\Jack\Desktop\projects\software\rust\test_rng>
I tried to change 0.1 to 0.1_f64 but that gave the same error.
I tried to convert random number to f64 (which it should already be) with as f64 but that resulted in the following:
fn main() {
let val: f64 = 0.1 * thread_rng().sample(StandardNormal) as f64;
println!("{}", val);
}
C:\Users\Jack\Desktop\projects\software\rust\test_rng>cargo run
Compiling test_rng v0.1.0 (C:\Users\Jack\Desktop\projects\software\rust\test_rng)
error[E0282]: type annotations needed
--> src\main.rs:5:39
|
5 | let val: f64 = 0.1 * thread_rng().sample(StandardNormal) as f64;
| ^^^^^^ cannot infer type for type parameter `T` declared on the associated function `sample`
|
= note: type must be known at this point
help: consider specifying the type arguments in the method call
|
5 | let val: f64 = 0.1 * thread_rng().sample::<T, D>(StandardNormal) as f64;
| ^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0282`.
error: could not compile `test_rng`.
To learn more, run the command again with --verbose.
C:\Users\Jack\Desktop\projects\software\rust\test_rng>
Thought it was a precedence issue so I tried wrapping second half in parenthesis but got the same error.
I can get it to work by making the variable mutable and separating the line into two operations like the following:
fn main() {
let mut val: f64 = thread_rng().sample(StandardNormal);
val *= 0.1;
println!("{}", val);
}
C:\Users\Jack\Desktop\projects\software\rust\test_rng>cargo run
Compiling test_rng v0.1.0 (C:\Users\Jack\Desktop\projects\software\rust\test_rng)
Finished dev [unoptimized + debuginfo] target(s) in 1.62s
Running `target\debug\test_rng.exe`
-0.034993448117065
C:\Users\Jack\Desktop\projects\software\rust\test_rng>
Any idea what is going on with the multiplication of the f64 with the output of the random number?
You can use the following:
fn main() {
let val: f64 = 0.1 * thread_rng().sample::<f64,_>(StandardNormal);
println!("{}", val);
}
This explicitly forces the sample function to return a f64. What was likely going on is that the rust type inference doesn't realize that the RHS needs to be f64, though I'm not sure exactly why.
Edit:
I think some the blame here goes to the definition of sample, in that it uses an unrestricted type parameter. An MVE for this would be:
pub trait Marker{}
impl Marker for f64{}
impl Marker for f32{}
fn does_not_work<T>() -> T{
unimplemented!()
}
fn does_work<T: Marker>() -> T{
unimplemented!()
}
fn main() {
let val: f64 = 0.1 * does_work();
let val: f64 = 0.1 * does_not_work();
}
It's somewhat understandable that the compiler can't infer types for does_not_work, b/c how is it meant to know about every possible type that could multiply with f64? However of we restrict things to only certain types with a trait, then the list of possible types becomes finite and type inference works again.
Consider the following code, where we take chunks of a list, join them and print to stdout:
val l = listOf("1", "2", "3", "4", "5", "6", "7")
l.chunked(3, { a -> a.joinToString()}).forEach(::println)
The code works without a problem. I wanted to change the lambda call ({ a -> a.joinToString()}) to the method reference, like this:
l.chunked(3, l::joinToString).forEach(::println)
The code that uses method reference does not compile and the errors given are:
Error:(4, 7) Kotlin: Type inference failed: fun
Iterable.chunked(size: Int, transform: (List) -> R): List
cannot be applied to receiver: List arguments:
(Int,KFunction6<#ParameterName CharSequence, #ParameterName
CharSequence, #ParameterName CharSequence, #ParameterName Int,
#ParameterName CharSequence, #ParameterName(name = "transform")
((String) -> CharSequence)?, String>)
Error:(4, 18) Kotlin: Type mismatch: inferred type is
KFunction6<#ParameterName CharSequence, #ParameterName CharSequence,
#ParameterName CharSequence, #ParameterName Int, #ParameterName
CharSequence, #ParameterName(name = "transform") ((String) ->
CharSequence)?, String> but (List) -> ??? was expected
Error:(4, 21) Kotlin: Type inference failed: fun
Iterable.joinToString(separator: CharSequence = ..., prefix:
CharSequence = ..., postfix: CharSequence = ..., limit: Int = ...,
truncated: CharSequence = ..., transform: ((T) -> CharSequence)? =
...): String cannot be applied to receiver: List arguments:
()
Is there a way to compile the code with method references instead of lambda call? I am beginning to learn Kotlin, but suppose that the errors stem from the fact that joinToString uses a number of default arguments?
There's an open feature request in the Kotlin issue tracker with the title "Support function references with default values as other function types", which seems to be what's missing for your use-case to work.
The feature currently has a target version of 1.3.
Update
The 1.3 Kotlin release does not contain this feature, the target version is updated to 1.4
This is my code and I don't know why it's not working. The title is what the error says. I'm working with Swift in Xcode and the code is supposed to create a function with as many parameters as I tell it to have/unlimited.
func addMyAccountBalances(balances : Double) -> Double {
var result : Double = 0
for balance in balances {
result += balance
}
}
the code is supposed to create a function with as many parameters as i tell it
What you probably want is a function taking a variable number of arguments,
this is indicated by ... following the type:
func addMyAccountBalances(balances : Double ...) -> Double {
var result : Double = 0
for balance in balances {
result += balance
}
return result
}
print(addMyAccountBalances(1.0, 2.0, 3.0))
print(addMyAccountBalances(4.5, 5.6))
Inside the function, balances has the array type [Double] so that
you can iterate over its elements.
Note that this can be written more compactly with reduce():
func addMyAccountBalances(balances : Double ...) -> Double {
let result = balances.reduce(0.0, combine: +)
return result
}
Your code does not compile because balances : Double is just
a double number, not an array or sequence.
I am writing an OS X app that should maintain a custom Keychain, I am trying to use the Security framework's API to create the Keychain, however, I can't seem to get it to compile under Swift.
Here's what I have, assume that path contains a path to a potentially existing Keychain:
let pathName = (path as NSString).UTF8String
var keychain: Unmanaged<SecKeychain>?
var status = withUnsafeMutablePointer(&keychain) { pointer in
SecKeychainOpen(pathName, pointer)
}
if status != errSecSuccess {
status = withUnsafeMutablePointer(&keychain) { pointer in
SecKeychainCreate(pathName, UInt32(0), nil, false, nil, pointer)
}
}
The compiler is complaining about the types in the SecKeychainCreate call, however, I fail to understand what am I doing wrong.
Cannot invoke 'withUnsafeMutablePointer' with an argument list of type '(inout Unmanaged<SecKeychain>?, (_) -> _)'
If I modify the second closure slightly, I get this compiler error:
Cannot invoke 'SecKeychainCreate' with an argument list of type '(UnsafePointer<Int8>, UInt32, nil, Bool, nil, (UnsafeMutablePointer<Unmanaged<SecKeychain>?>))'
I appreciate all suggestions.
The promptUser parameter of SecKeychainCreate() has the type
Boolean, which is a "Mac OS historic type" and an alias to UInt8,
so it is different from the Swift Bool in Swift 1.2.
(Compare Type 'Boolean' does not conform to protocol 'BooleanType' for a similar issue.)
This means that you have to
pass Boolean(0) instead of false:
SecKeychainCreate(pathName, UInt32(0), nil, Boolean(0), nil, pointer)
Additional remarks:
withUnsafeMutablePointer() is not needed, you can pass &keychain
to the keychain functions.
(path as NSString).UTF8String is not needed, you can pass a Swift
string to a C function expecting a const char * parameter,
compare String value to UnsafePointer<UInt8> function parameter behavior.
Passing nil as password to SecKeychainCreate() is only allowed
if promptUser is TRUE, otherwise it causes a
"parameter error (-50)".
SecKeychainOpen() succeeds even if the keychain file does not
exists. According to the documentation, you have to check
SecKeychainGetStatus(). Alternatively, you can try to create
the keychain file first, as for example in Open Local Items Keychain?.
Together:
let path = "/path/to/my.keychain"
var keychain: Unmanaged<SecKeychain>?
var status = SecKeychainCreate(path, 0, "", Boolean(0), nil, &keychain)
if status == OSStatus(errSecDuplicateKeychain) {
status = SecKeychainOpen(path, &keychain)
}
As of Swift 2 / Xcode 7 beta 5, the Mac type Boolean is mapped
to Swift as Bool, and the key chain functions do no longer return
unmanaged objects:
let path = "/path/to/my.keychain"
var keychain: SecKeychain?
var status = SecKeychainCreate(path, 0, "", false, nil, &keychain)
if status == OSStatus(errSecDuplicateKeychain) {
status = SecKeychainOpen(path, &keychain)
}
I get a rust compiler error:
src/main.rs:33:31: 33:35 error: can't capture dynamic environment in a fn item; use the || { ... } closure form instead
The error occurs because I have a function in which I declare a variable using let, and then have an inner function in which I try to use this variable that is closed over.
I am fairly certain that this is a beginner question, so sorry in advance if this has a very straight forward answer!
Note that I am using this inner function as a callback somewhere, and thus using a closure, like
let closure_fn = | args | -> () { do stuff };
... is not going to be an appropriate solution for me.
extern crate nickel;
use std::io::net::ip::Ipv4Addr;
use nickel::{ Nickel, Request, Response };
fn stub_3rd_party_function() -> String {
"hello world".to_string()
}
fn main() {
let mut server = Nickel::new();
// assume that the variable **must** be instantiated like this
let hello_text : String = stub_3rd_party_function();
fn hello_handler (_request: &Request, response: &mut Response) -> () {
response.send(hello_text.as_slice());
}
server.get("/hello", hello_handler);
server.listen(Ipv4Addr(0,0,0,0), 6767);
}
Results in the following error:
src/test.rs:12:23: 12:33 error: can't capture dynamic environment in a fn item; use the || { ... } closure form instead
src/test.rs:12 response.send(hello_text);
^~~~~~~~~~
src/test.rs:12:23: 12:33 error: unresolved name `hello_text`.
src/test.rs:12 response.send(hello_text);
^~~~~~~~~~
error: aborting due to 2 previous errors
Now, I switch from a standard function to a closure function instead:
extern crate nickel;
use std::io::net::ip::Ipv4Addr;
use nickel::{ Nickel, Request, Response };
fn stub_3rd_party_function() -> String {
"hello world".to_string()
}
fn main() {
let mut server = Nickel::new();
// assume that the variable **must** be instantiated like this
let hello_text : String = stub_3rd_party_function();
let hello_handler = |_request: &Request, response: &mut Response| -> () {
response.send(hello_text.as_slice());
};
server.get("/hello", hello_handler);
server.listen(Ipv4Addr(0,0,0,0), 6767);
}
Results in a different error:
src/test.rs:21:30: 21:43 error: mismatched types: expected `fn(&nickel::request::Request<'_>, &mut nickel::response::Response<'_,'_>)` but found `|&nickel::request::Request<'_>, &mut nickel::response::Response<'_,'_>|` (expected extern fn but found fn)
src/test.rs:21 server.get("/hello", hello_handler);
^~~~~~~~~~~~~
error: aborting due to previous error
Is there perhaps a way to "wrap" the closed over function with a normal one?
Since the library that I am using expects a standard function instead of a closure,
I cannot use a closure.
But if I do not use a closure, I cannot close over variables that are defined within the outer function, fn main () { ... }... and thus getting stuck here.
Note that above, I am using a string, hello_text, for the purposes of providing a concise code example.
In this case using a static variable would suffice. However, static variables will not fix it for me, as I need to be able to assign a variable from within a fn main() the result of a function call, and then use that within my inner handler function.
It says that because it’s the simple truth: a function cannot capture variables; if you put a function inside another function, that the function is inside the function rather than outside is purely a matter of namespacing and making it absolutely private and inaccessible to anything else. If you want such variable capturing, you must use a closure.
In your specific case, functions are the only way. You should consider your code to be this (I would write it this way, too, to reduce indentation if nothing else):
fn hello_handler(_request: &Request, response: &mut Response) {
response.send(hello_text);
}
fn main() {
let mut server = Nickel::new();
let hello_text = "hello world";
server.get("/hello", hello_handler);
server.listen(Ipv4Addr(0, 0, 0, 0), 6767);
}
As you can see with this way of expressing it, hello_text is evidently inaccessible from hello_handler. There are sound technical reasons why it must be so, also—each request is handled in its own task. In this particular case, a static is the solution:
static HELLO_TEXT: &'static str = "hello world";