Swift: Deconstruct SPF: Struct Mechanism
Tags: swift, beginners, package, spf
Published: 2021-05-20 04:09:44


Today, I will start on building out the functionality of the `struct Mechanism`.  
This will involve creating some tests, and basic functions.

## Instantiate the Mechanism Struct 

We have our struct defined as such:
```swift
struct Mechanism {
    var kind: MechanismKind;
    var qualifier: Qualifier;
    var mechanism: String;
    
    init(k: MechanismKind, q: Qualifier, m: String) {
        kind = k;
        qualifier = q;
        mechanism = m;
    }
    func mechanismString() -> String {
        self.mechanism;
    }
    func whatKind() -> MechanismKind {
        return self.kind;
    }
    func isPass() -> Bool {
        return self.qualifier == Qualifier.Pass;
    }
    func isFail() -> Bool {
        return self.qualifier == Qualifier.Fail;
    }
    func isSoftFail() -> Bool {
        return self.qualifier == Qualifier.SoftFail;
    }
    func isNeutral() -> Bool {
        return self.qualifier == Qualifier.Neutral;
    }
    func isNone() -> Bool {
        return self.qualifier == Qualifier.None;
    }
}
```

### init
This will instantiate the struct. Provide what kind of **mechanism** it is. Its **qualifier**, and the value of its **mechanism**.

### mechanismString
This will allow us to access the information stored in `mechanism` as a simple `String`  
### isPass
This will return `Bool` of **true** if the Qualifier is `Pass`
### isFail
This will return `Bool` of **true** if the Qualifier is `Fail`
### isSoftFail
This will return `Bool` of **true** if the Qualifier is `SoftFail`
### isNeutral
This will return `Bool` of **true** if the Qualifier is `Neutral`
### isNone
This will return `Bool` of **true** if the Qualifier is `None`
### whatKind
This will help us understand if the mechanism represents a **redirect**, **A**, or some other mechanism.

## Testing
For this we need to take a look at `Tests/DeconSpfTests/DeconSpfTests.swift`.  
Within this file we have the following initial set of code.
```swift
import XCTest
@testable import DeconSpf;

final class SPFTests: XCTestCase {

    func testMechanismRedirect() {
        let Mech = Mechanism(k: MechanismKind.Redirect, q: Qualifier.None, m: "test.com");
        XCTAssertEqual(Mech.mechanismString(), "test.com");
        XCTAssertEqual(Mech.whatKind(), MechanismKind.Redirect);
        XCTAssertNotEqual(Mech.whatKind(), MechanismKind.A);
        XCTAssertEqual(Mech.isNone(), true);
    }
    func testMechanismInclude() {
        let Mech = Mechanism(k: MechanismKind.Include, q: Qualifier.Pass, m: "_spf.test.com");
        XCTAssertEqual(Mech.mechanismString(), "_spf.test.com");
        XCTAssertEqual(Mech.whatKind(), MechanismKind.Include);
        XCTAssertNotEqual(Mech.whatKind(), MechanismKind.Redirect);
        XCTAssertNotEqual(Mech.whatKind(), MechanismKind.A);
        XCTAssertEqual(Mech.isPass(), true);
    }
    static var allTests = [
        ("testMechanismRedirect", testMechanismRedirect),
        ("testMechanismInclude", testMechanismInclude),
    ]
}
```
Let's break down each test function.

```swift
func testMechanismRedirect() {
    let Mech = Mechanism(k: MechanismKind.Redirect, q: Qualifier.None, m: "test.com");
    XCTAssertEqual(Mech.mechanismString(), "test.com");
    XCTAssertEqual(Mech.whatKind(), MechanismKind.Redirect);
    XCTAssertNotEqual(Mech.whatKind(), MechanismKind.A);
    XCTAssertEqual(Mech.isNone(), true);
}
```
What are is happening here:
1. Instantiate `Mech` and then we make four assertions.
2. mechanismString() matches "test.com"
3. whatKind() matches MechanismKind.Redirect
4. The MechanismKind is not MechanismKind.A
5. isNone() is `true`

```swift
func testMechanismInclude() {
    let Mech = Mechanism(k: MechanismKind.Include, q: Qualifier.Pass, m: "_spf.test.com");
    XCTAssertEqual(Mech.mechanismString(), "_spf.test.com");
    XCTAssertEqual(Mech.whatKind(), MechanismKind.Include);
    XCTAssertNotEqual(Mech.whatKind(), MechanismKind.Redirect);
    XCTAssertNotEqual(Mech.whatKind(), MechanismKind.A);
    XCTAssertEqual(Mech.isPass(), true);
}
```

This does the same basic tests, but for a mechanism that should be of MechanismKind.Include.

## Testing
```zsh
swift test
```
### Output
```zsh
[6/6] Linking DeconSpfPackageTests
Test Suite 'All tests' started at 2021-05-13 15:09:48.435
Test Suite 'DeconSpfPackageTests.xctest' started at 2021-05-13 15:09:48.436
Test Suite 'SPFTests' started at 2021-05-13 15:09:48.436
Test Case '-[DeconSpfTests.SPFTests testMechanismInclude]' started.
Test Case '-[DeconSpfTests.SPFTests testMechanismInclude]' passed (0.082 seconds).
Test Case '-[DeconSpfTests.SPFTests testMechanismRedirect]' started.
Test Case '-[DeconSpfTests.SPFTests testMechanismRedirect]' passed (0.000 seconds).
Test Suite 'SPFTests' passed at 2021-05-13 15:09:48.519.
  Executed 2 tests, with 0 failures (0 unexpected) in 0.083 (0.083) seconds
Test Suite 'DeconSpfPackageTests.xctest' passed at 2021-05-13 15:09:48.519.
  Executed 2 tests, with 0 failures (0 unexpected) in 0.083 (0.083) seconds
Test Suite 'All tests' passed at 2021-05-13 15:09:48.519.
  Executed 2 tests, with 0 failures (0 unexpected) in 0.083 (0.084) seconds

```

### Let's add a new test
We want to be able to get a string representation of the mechanism as it was originally seen. 

If I had an initially mechanism of `ip4:x.x.x.x` which was stored as
- kind: MechanismKind.Ip4
- qualifier: Qualifier.None
- mechanism: "x.x.x.x"

I should be able to call `mech.asMechanism()` and get `ip4:x.x.x.x` in return.

So let's make a test for this. (Expect failure)

We update the `DeconSpfTests.swift` with the following.
```swift
func testAsMechanism() {
    let Mech = Mechanism(k: MechanismKind.ip4, q: Qualifier.None, m: "192.168.1.0/24");
    XCTAssertEqual(Mech.asMechanism(), "ip4:192.168.1.0/24");
}
static var allTests = [
    ("testMechanismRedirect", testMechanismRedirect),
    ("testMechanismInclude", testMechanismInclude),
    ("testAsMechanism", testAsMechanism),
]
```

We add this test to the `allTests` so  that it will be run with the others.  

**Xcode** also complains  
`Value of type 'Mechanism' has no member 'asMechanism'`.  
This is because I have not yet defined a member function named `asMechanism()` on the **Mechanism** struct.

The code for this project can now be found [here](https://github.com/Bas-Man/swift-decon-spf).

This is the [diff](https://github.com/Bas-Man/swift-decon-spf/compare/Initial...QualifierGet) between the initial commit and the current code.

## Closing
That's it for today. In the next article. I will look at returning values based on the `Qualifier` type. These will be needed to build the string for `asMechanism()`