Skip to content

Commit

Permalink
Add section on using library in Swift
Browse files Browse the repository at this point in the history
 - Contains a full working example that should work out of the box.
  • Loading branch information
xtremekforever committed Jul 13, 2024
1 parent 77034db commit 0f85c92
Showing 1 changed file with 113 additions and 0 deletions.
113 changes: 113 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,119 @@ Coming soon: guidelines, specs and code documentation. Check out the examples fo

See [the examples and demos](./demo/) for more examples.

## Usage in Swift

To use the library in Swift, it first must be compiled using the instructions above, then the library and header must be deployed manually to /usr:

```bash
sudo cp testcontainers-c/testcontainers-c.h /usr/include
sudo cp testcontainers-c/testcontainers-c.so /usr/lib/libtestcontainers-c.so
```

This is required so that Swift can actually find the header and library. On some systems, it may be required to deploy the *.so file to `/usr/lib64` instead. Try this if Swift is unable to find it when deployed to `/usr/lib` as shown above.

Next, create a new directory in your Swift project `Sources/` directory called `CTestContainers` and add a file called `CTestContainers.h` with the following content:

```c
#include <testcontainers-c.h>`
```

Then, create a file called `module.modulemap` in the same directory with this:

```c
module CTestContainers [system] {
header "CTestContainers.h"
link "testcontainers-c"
export *
}
```

Then, add a the following definitions to the `targets` in `Package.swift`:

```swift
.systemLibrary(name: "CTestContainers")
```

It can be then included as a dependency for a target, like this:

```swift
.executableTarget(
name: "my-swift-app",
dependencies: [
"CTestContainers"
]
),
```

This module can then be imported and used from inside the application. However, the only challenge is dealing with C-style strings that are typically utf8 and are null terminated, so they require a bit of extra support for translation in Swift.

Here is the `generic-containers` demo translated into Swift, with an exstension to properly translate a `String` to a utf8 string for C:

```swift
import CTestContainers
import Glibc
import Foundation

extension String {
func toCString() -> UnsafePointer<Int8> {
return NSString(string: self).utf8String!
}
}

let defaultImage = "wiremock/wiremock:3.0.1-1"
print("Using WireMock with the Testcontainers C binding (from Swift):")

print("Creating new container: \(defaultImage)")
let requestId = tc_new_container_request(defaultImage)
tc_with_exposed_tcp_port(requestId, 8080)
tc_with_wait_for_http(requestId, 8080, "/__admin/mappings".toCString())
tc_with_file(requestId, "test_data/hello.json".toCString(), "/home/wiremock/mappings/hello.json".toCString())
let ret = tc_run_container(requestId)
defer {
free(ret.r2)
}
let containerId = ret.r0
if ret.r1 == 0 {
print("Failed to run the container: \(String(cString: ret.r2))")
exit(-1)
}

print("Sending HTTP request to the container")
let response = tc_send_http_get(containerId, 8080, "/hello")
defer {
free(response.r1)
free(response.r2)
}
if response.r0 == -1 {
print("Failed to send HTTP request: \(String(cString: response.r2))")
exit(-1)
}
if response.r0 != 200 {
print("Received wrong response code: \(response.r0) instead of 200")
print(String(cString: response.r1!))
print(String(cString: response.r2!))
exit(-1)
}
print("Server Response: HTTP-\(response.r0)")
print(String(cString: response.r1!))
```

Also, note that that `free` should be called to avoid memory leaks on the C strings returned from the library. This is missing from the existing C demos, but is an important consideration.

To use the `wiremock` module in Swift, all that needs to be done is to deploy the header and library in the same way as described above, and then add the following to `CTestContainers.h`:

```c
#include <testcontainers-c-wiremock.h>`
```

And the following to `module.modulemap`:

```c
link "testcontainers-c-wiremock"`
```

Then it is possible to use all the wiremock module helper functions from inside of Swift.

## Usage in other languages

TL;DR: You get the C header file, a shared library object or a DLL file from the
Expand Down

0 comments on commit 0f85c92

Please sign in to comment.