Testing an executable with Swift - swift

I created an executable with Swift via swift package init --type executable and would now like to write a few tests for it. This doesn't appear to be an issue at all for library packages, in that case Swift also populates the Tests directory with a tests module which runs nicely via swift test. For an executable only an empty Tests directory is created.
On trying to run tests for my executable from within Xcode or via swift test I'm running into linker issues though that seem to specify that Swift is unable to link the contents of my main.swift to the tests. I'm not sure what I can do here. I've tried playing around within Xcode to create new framework targets to be linked, but none of that would be picked up by swift test anyways as far as I can tell. I didn't manage to get it working via Xcode either. The following is the output from swift test.
Compile Swift Module 'swifttest' (1 sources)
Linking ./.build/debug/swifttest
Compile Swift Module 'swifttestTests' (1 sources)
Linking ./.build/debug/swifttestPackageTests.xctest/Contents/MacOS/swifttestPackageTests
Undefined symbols for architecture x86_64:
"__TF9swifttest3fooFT_SS", referenced from:
__TFFC14swifttestTests14SwifttestTests7testFooFT_T_u0_KzT_SS in swifttestTests.swift.o
ld: symbol(s) not found for architecture x86_64
<unknown>:0: error: link command failed with exit code 1 (use -v to see invocation)
<unknown>:0: error: build had 1 command failures
error: exit(1): /Applications/Xcode-beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-build-tool -f /Users/kilian/Desktop/swifttest/.build/debug.yaml test
These are the contents of my files for reference. It's a minimal example project.
main.swift
public func foo() -> String {
return "bar"
}
print(foo())
swifttestTests.swift
import Foundation
import XCTest
import swifttest
class SwifttestTests: XCTestCase {
func testFoo() {
XCTAssertEqual("bar", foo())
}
}
Directory Layout
.
├── Package.swift
├── Sources
│   └── main.swift
└── Tests
└── swifttestTests
└── swifttestTests.swift

Whilst not exactly a solution to not being able to test an executable I was made aware of a workaround. The basic idea is to move more or less everything into a second module inside the same project and minimizing the executable target to a call to an entry function.
A basic structure following the given example would look like this:
.
├── Package.swift
├── Sources
│ └── swifttest
│ │ └── main.swift
│ └── SwiftTestLib
│ └── foo.swift
└── Tests
└── SwiftTestLibTests
└── SwiftTestLibTests.swift
This makes it necessary however to specify the targets in the Package.swift.
import PackageDescription
let package = Package(
name: "swifttest",
targets: [
Target(name: "swifttest", dependencies: ["SwiftTestLib"]),
Target(name: "SwiftTestLib", dependencies: []),
],
dependencies: []
)

Related

Building a package with generated Python files

Problem statement
When building a Python package I want the build tool to automatically execute the steps to generate the necessary Python files and include them in the package.
Here are some details about the project:
the project repository contains only the hand-written Python and YAML files
to have a fully functional package the YAML files must be compiled into Python scripts
once the Python files are generated from YAMLs, the program needed to compile them is no longer necessary (build dependency).
the hand-written and generated Python files are then packaged together.
The package would then be uploaded to PyPI.
I want to achieve the following:
When the user installs the package from PyPI, all necessary files required for the package to function are included and it is not necessary to perform any compile steps
When the user checks-out the repository and builds the package with python -m build . --wheel, the YAML files are automatically compiled into Python and included in the package. Compiler is required.
When the user checks-out the repository and installs the package from source, the YAML files are automatically compiled into Python and installed. Compiler is required.
(nice to have) When the user checks-out the repository and installs in editable mode, the YAML files are compiled into Python. The user is free to make modifications to both generated and hand-written Python files. Compiler is required.
I have a repository with the following layout:
├── <project>
│ └── <project>
│ ├── __init__.py
│ ├── hand_written.py
│ └── specs
│ └── file.ksc (YAML file)
└── pyproject.toml
And the functional package should look something like this
├── <project>
│ └── <project>
│ ├── __init__.py
│ ├── hand_written.py
│ └── generated
│ └── file.py
├── pyproject.toml
└── <other package metadata>
How can I achieve those goals?
What I have so far
As I am very fresh to Python packaging, I have been struggling to understand the relations between the pyproject.toml, setup.cfg and setup.py and how I can use them to achieve the goals I have outlined above. So far I have a pyproject.toml with the following content:
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[project]
name = "<package>"
version = "xyz"
description = "<description>"
authors = [ <authors> ]
dependencies = [
"kaitaistruct",
]
From reading the setuptools documentation, I understand that there are the build commands, such as:
build_py -- simply copies Python files into the package (no compiling; works differently in editable mode)
build_ext -- builds C/C++ modules (not relevant here?)
I suppose adding the compile steps for the YAML files will involve writing a setup.py file and overwriting a command, but I don't know if this is the right approach, whether it will even work, or if there are better methods, such as using a different build backend.
Alternative approaches
A possible alternative approach would be to manually compile the YAML files prior to starting the installation or build of the package.

How to integrate Imebra v5 to a swift command line project

I'm trying to import Imebra into a basic swift 5 command line project using Xcode 12. I followed the official steps but I failed. I can summarise the whole structure:
The structure of the project is just
./
├── main.swift
├── Data
└── DX_0.dcm
├── Imebra
└── CMakeLists.txt
└── docs
└── examples
└── library
└── test
└── wrappers
└── build_imebra_macos
The main swift file is
// main.swift
import Foundation
print("Hello, Imebra!")
do {
let pDataSet = try ImebraCodecFactory.load(fromFile: "PathToDicomFileFromExecutable")
let pImage = try pDataSet.getImageApplyModalityTransform(0)
print("The image width is", pImage.width)
} catch {
print(error)
}
Following the documentation, I compile the library by going to the build_imebra_macos folder and running
build_imebra_macos % cmake -GXcode -DCMAKE_BUILD_TYPE=Release ..
build_imebra_macos % cmake --build . --config Release
The build is successful and the new folder Release has the dynamic library. Now in Xcode project of the CL Swift application, SwiftyImebra.xcodeproj, I followed the next instruction "open the target Build Settings and under “Swift Compiler/ObjectiveC Bridging Header” specify the path to imebra_location/wrappers/objectivec/include/imebraobjc/imebra.h.”, with Imebra_location changed to Imebra.
Then when I build I get the error
Showing All Messages
Undefined symbol: _OBJC_CLASS_$_ImebraCodecFactory
I'm new in Swift and I guess I need to specify somewhere in Xcode where the source or the dynamic library is. However, I am not sure about this either as we have generated a cpp dynamic library so this can only interact with objective-C (?). I apologise if this is a basic question...
In addition, I'd like to learn how to use Imebra as a static library with swift.
The imebra dynamic library must be added to the project.
Drag the imebra.dylib (generated into your build folder build_imebra_macos) into your project.
Additionally, specify the folder containing the dylib into the "Library search path" in the compiler options.

Create a Swift framework with submodules

I have an Xcode project with a main app and a Swift Framework called Networking. Now I'd like to split that Networking module into a submodule with only some utility classes so that they are available to the main app only when explicitly imported. So the usage I'd like to achieve would be
import Networking
import Networking.Utils
// Public class in Networking
MyNetworking.doStuff()
// Public class in Networking.Utils
// Should not compile unless Networking.Utils is imported
MyNetworkingUtils.doSomething()
So my module has the following file structure
.
├── Core
│   ├── MyNetworking.swift
│   └── Networking.h
├── Info.plist
├── Utils
│   ├── NetworkingUtils.h
│   └── Utils.swift
└── module.modulemap
I created a custom module.modulemap with this content:
framework module Networking {
umbrella header "Networking.h"
export *
module * { export * }
explicit module Utils {
header "NetworkingUtils.h"
}
}
This creates the Networking module but the problem is that the Utils classes are available in the main Networking module.
The question is, how can I specify in the module map which Swift files (ideally subfolders) belong to which module.
The Networking has only Swift files so the umbrella .h files are basically empty.
It looks like it's good option here to have two different modules: Networking and NetworkingUtils (second could have dependency to first).

What is the simplest way to create an importable file in Scala?

TLDR: What is the simplest way to create an importable file in Scala?
This is a beginner's question.
I've been learning Scala for a few weeks and now have some code that I would like to share between a couple of files/different projects. I have tried a lot of import structures but none of them worked. The requirements are:
File to be imported should reside in a totally different directory.
File to be imported should be importable by independent projects.
File to be imported is a single .scala file.
(Optional) file to be imported should contain defs, objects and case classes.
Example:
File to be imported location: /some/path/to_be_imported.scala.
File using project (1) location: /abc/def/will_import01.scala.
File using project (2) location: /xyz/rst/will_import02.scala.
I'm not trying to create a package or distribute it.
See how I would address this considering the programming language I already know:
Since I'm versed in Python I'll give an expected version of the answer should this problem refer o Python:
In that case you could:
Put your file on the same directory of your executed file then just run: python3 ./your_file.py. For instance:
➜ another_path|$ python3 ./main_module/main_file.py
1
self printing
➜ another_path|$ tree .
=======================================================================
.
└── main_module
├── main_file.py
├── __pycache__
│   └── sample_file_to_be_imported.cpython-36.pyc
└── sample_file_to_be_imported.py
Notice that they are in the exact same directory (this contradicts point 2 above nevertheless it solves the problem).
Add the directory of your file to the PYTHONPATH environment variable then run your module (best answer):
➜ random_path|$ PYTHONPATH=$PYTHONPATH:./sample_module python3 ./main_module/main_file.py
1
self printing
=======================================================================
➜ random_path|$ tree .
.
├── main_module
│   └── main_file.py
└── sample_module
├── __pycache__
│   └── sample_file_to_be_imported.cpython-36.pyc
└── sample_file_to_be_imported.py
3 directories, 3 files
Content of the files:
➜ random_path|$ cat ./main_module/main_file.py
from sample_file_to_be_imported import func1, Class01
print(func1())
x = Class01()
x.cprint()
=======================================================================
➜ random_path|$ cat ./sample_module/sample_file_to_be_imported.py
def func1():
return 1
class Class01():
def cprint(self):
print('self printing')
Edit 01: #felipe-rubin answer does not work:
$ scala -cp /tmp/scala_stack_exchange/ myprogram.scala
/tmp/scala_stack_exchange/path01/myprogram.scala:3: error: not found: value Timer
val x = Timer(1)
^
one error found
=======================================================================
➜ path01 tree /tmp/scala_stack_exchange
/tmp/scala_stack_exchange
├── anotherpath
│   ├── Timer.class
│   └── timer.scala
└── path01
└── myprogram.scala
2 directories, 3 files
=======================================================================
$ cat /tmp/scala_stack_exchange/anotherpath/timer.scala
class Timer(a: Int) {
def time(): Unit = println("time this")
}
=======================================================================
$ cat /tmp/scala_stack_exchange/path01/myprogram.scala
import anotherpath.Timer
val x = Timer(1)
x.time()
The simplest way would be to compile a .scala file with scalac:
Linux/OSX: scalac mypackage/Example.scala
Windows: scalac mypackage\Example.scala
The above should generate a .class file (or more).
Assuming the file contains a class called Example you can import it somewhere else like this:
import mypackage.Example
When compiling another file which does the above import, you will need to have 'mypackage' in the classpath. You can add directories to the classpath when calling scalac by using the -cp flag like:
Linux/OSX: scalac -cp .:path/to/folder/where/mypackage/is/located AnotherExample.scala
Windows: scalac -cp .;path\to\folder\where\mypackage\is\located AnotherExample.scala
Doing this for bigger projects gets complicated, in which case you might resort to a build tool (e.g. SBT) or an IDE (e.g. IntelliJ Idea) to do the complicated work for you.
Other notes:
If you don't have scalac, you can get it from the scala website ('download binaries' option)
the -cp flag stand for "classpath". There is also a -classpath flag which does the same thing
Welcome to Scala :)
I finally got this working. Thanks for the valuable input from the other answers.
I have diversified the name of every path, file and object to be as general as possible. This probably does not follow the guidelines of the scala community but is the most explicit, illustrative help I could find. Project layout:
File Layout
$ tree /tmp/scala_stack_exchange
/tmp/scala_stack_exchange
├── anotherpath
│   ├── file_defines_class.scala
│   └── some_package_name
│   ├── MyObj.class
│   └── MyObj$.class
└── path01
└── myprogram.scala
3 directories, 4 files
Where I want to run myprogram.scala which should import classes defined in file_defines_class.scala.
Preparation
Compile the file you want to be imported by other modules:
cd /tmp/scala_stack_exchange/anotherpath && scalac ./file_defines_class.scala
Execution
cd /tmp/scala_stack_exchange/path01 && scala -cp /tmp/scala_stack_exchange/anotherpath/ ./myprogram.scala
Results
myobj time
Contents of the files
// /tmp/scala_stack_exchange/path01/myprogram.scala
import some_package_name.MyObj
val x = new MyObj(10)
x.time()
// /tmp/scala_stack_exchange/anotherpath/file_defines_class.scala
package some_package_name
object MyObj
case class MyObj(i: Int) {
def time(): Unit = println("myobj time")
}
Feels like magic. However this whole process is rather cumbersome :/

Kotlin cannot import packages

I'm using kotlin on command line and I'm getting import errors error: unresolved reference: ConnectionHandler
Following is my directory tree:
$ tree .
.
├── LICENSE
├── main.jar
├── main.kt
└── server
├── ConnectionHandler.class
├── ConnectionHandler.kt
├── HttpRequest.class
└── HttpRequest.kt
1 directory, 7 files
When I run kotlinc main.kt -include-runtime -d main.jar I get
main.kt:2:8: error: unresolved reference: server
import server.*
I have declared package server in both of server/ConnectionHandler.kt and server/HttpRequest.kt
Note: The META-INF folder is missing. It is not regenerated either on subsequent compilations.
What am I doing wrong? If it has anything to do with META-INF folder, how can I regenerate it?
You need to include all your source files when using kotlinc (or at least include the compiled classes on the classpath). e.g.
kotlinc main.kt server/ConnectionHandler.kt server/HttpRequest.kt -include-runtime -d main.jar