Swift: Deconstruct SPF: Qualifier and MechanismKind
Tags: swift, beginners, enum, package
Published: 2021-05-26 23:59:06

In this article I will be looking at defining the **enums** for `Qualifier` and `MechanismKind`. I will also be adding tests to ensure that the functions work as expected. Further I will implement a simple `asMechanism()` as a proof of concept.

## Qualifier
As mentioned in an earlier article. The Qualifier will consist of the following values.  

- `+` Pass
- `-` Fail
- `~` SoftFail
- `?` Neutral
- None

I expect that I will want to be able to obtain the character value (rawValue)
 at some point in the future.
 
### Definition
```swift
enum Qualifier: String {
    case Pass
    case Fail
    case SoftFail
    case Neutral
    case None
    
    func get() -> String {
        switch self {
        case .Pass:
            return "+"
        case .Fail:
            return "-"
        case .SoftFail:
            return "~"
        case .Neutral:
            return "?"
        case .None:
            return ""
        }
    }
}
```
At this point I have diverged from the original definition. This gave me a chance to look at the switch statement in **Swift**. I think will change this in a refactor session, as I expect to be able to access the [Raw Value](https://docs.swift.org/swift-book/LanguageGuide/Enumerations.html). Scroll down to find the actual documentation.

### Testing

To make testing a little cleaner and manageable moving forward. I also created a new file under `DeconfSpfTests` called `DeconfSpfQualifierTests.swift`.

This contains the following code.

```swift
import XCTest
@testable import DeconSpf;

final class SPFQualifierTests: XCTestCase {

    func testQualifierPass() {
        let Q = Qualifier.Pass;
        XCTAssertEqual(Q.get(), "+");
    }
    func testQualifierFail() {
        let Q = Qualifier.Fail;
        XCTAssertEqual(Q.get(), "-");
    }
    func testQualifierSoftFail() {
        let Q = Qualifier.SoftFail;
        XCTAssertEqual(Q.get(), "~");
    }
    func testQualifierNeutral() {
        let Q = Qualifier.Neutral;
        XCTAssertEqual(Q.get(), "?");
    }
    func testQualifierNone() {
        let Q = Qualifier.None;
        XCTAssertEqual(Q.get(), "");
    }

    static var allTests = [
        ("testQualifierPass", testQualifierPass),
        ("testQualifierFail", testQualifierFail),
        ("testQualifierSoftFail", testQualifierSoftFail),
        ("testQualifierNeutral", testQualifierNeutral),
        ("testQualifierNone", testQualifierNone),

    ]
}
```
- Note: The class name needs to be unique
  - `final class SPFQualifierTests: XCTestCase`
  - I am using `SPFQualifierTests`
 
## MechanismKind

I took the same approach here with `MechanismKind`.

### Definition

```swift
enum MechanismKind {
    case Redirect, Include, A, MX, ip4, ip6, All;
    
    func get() -> String {
        switch self {
        case .Redirect:
            return "redirect="
        case .Include:
            return "include:"
        case .A:
            return "a"
        case .MX:
            return "mx"
        case .ip4:
            return "ip4:"
        case .ip6:
            return "ip6:"
        case .All:
            return "all"
        }
    }
}

```

### Testing

I also again created a new test file called `DeconfSpfMechanismKindTests`.  
This also has a unique class name `SPFMechanimsKindTests`.

```swift
import XCTest
@testable import DeconSpf;

final class SPFMechanimsKindTests: XCTestCase {

    func testMechanimsKindRedirect() {
        let MK = MechanismKind.Redirect;
        XCTAssertEqual(MK.get(), "redirect=");
    }
    func testMechanimsKindInclude() {
        let MK = MechanismKind.Include;
        XCTAssertEqual(MK.get(), "include:");
    }
    func testMechanimsKindA() {
        let MK = MechanismKind.A;
        XCTAssertEqual(MK.get(), "a");
    }
    func testMechanimsKindMX() {
        let MK = MechanismKind.MX;
        XCTAssertEqual(MK.get(), "mx");
    }
    func testMechanimsKindIp4() {
        let MK = MechanismKind.ip4;
        XCTAssertEqual(MK.get(), "ip4:");
    }
    func testMechanimsKindIp6() {
        let MK = MechanismKind.ip6;
        XCTAssertEqual(MK.get(), "ip6:");
    }
    func testMechanimsKindAll() {
        let MK = MechanismKind.All;
        XCTAssertEqual(MK.get(), "all");
    }

    static var allTests = [
        ("testMechanismKindRedirect", testMechanimsKindRedirect),
        ("testMechanismKindInclude", testMechanimsKindInclude),
        ("testMechanismKindA", testMechanimsKindA),
        ("testMechanismKindMX", testMechanimsKindMX),
        ("testMechanismKindIp4", testMechanimsKindIp4),
        ("testMechanismKindIp6", testMechanimsKindIp6),
        ("testMechanismKindAll", testMechanimsKindAll),

    ]
}
```

## asMechanism

Here I would refer you to the documentation on [Strings and Characters](https://docs.swift.org/swift-book/LanguageGuide/StringsAndCharacters.html).

### Code

I have updated `struct Mechanism` as shown below
```swift
struct Mechanims {
  --snip--
  func asMechanism() -> String {
      var mechanismString = String();
      // TODO: Qualifier
      // Access the string for this mechanism's kind.
      mechanismString += self.kind.get();
      // Access the string for the mechanim
      mechanismString += self.mechanism;
      return mechanismString;
  }
  --snip--
}
```

### Tests

I now have my previous test working as well as a few new ones.
```swift
func testAsMechanismIp4() {
    let Mech = Mechanism(k: MechanismKind.ip4, q: Qualifier.None, m: "192.168.1.0/24");
    XCTAssertEqual(Mech.asMechanism(), "ip4:192.168.1.0/24");
}
func testAsMechanismIp6() {
    let Mech = Mechanism(k: MechanismKind.ip6, q: Qualifier.None, m: "X:X:X:X/16");
    XCTAssertEqual(Mech.asMechanism(), "ip6:X:X:X:X/16");
}
func testAsMechanismRedirect() {
    let Mech = Mechanism(k: MechanismKind.Redirect, q: Qualifier.None, m: "_spf.example.com");
    XCTAssertEqual(Mech.asMechanism(), "redirect=_spf.example.com");
}
func testAsMechanismInclude() {
    let Mech = Mechanism(k: MechanismKind.Include, q: Qualifier.None, m: "_spf1.example.com");
    XCTAssertEqual(Mech.asMechanism(), "include:_spf1.example.com");
}
func testAsMechanismA() {
    let Mech = Mechanism(k: MechanismKind.A, q: Qualifier.None, m: "");
    XCTAssertEqual(Mech.asMechanism(), "a");
}
func testAsMechanismMx() {
    let Mech = Mechanism(k: MechanismKind.MX, q: Qualifier.None, m: "");
    XCTAssertEqual(Mech.asMechanism(), "mx");
}
```

Note that these tests are not complete. And do not yet cover all cases. In particular these tests will fail with several examples of `A` and `MX` **Mechanism**s.

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...Initial-asMechanism) between *Initial* and *Initial-asMechanism*.

## Closing

Today I implemented an initial `get()` function for both `Qualifier` and `MechanismKind`. I also did an initial implementation for `asMechanism()`.