๐Ÿ“ฆ Bogdanp / Noise

๐Ÿ“„ RacketTest.swift ยท 94 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94import Noise
import XCTest

nonisolated(unsafe) var r: Racket!

class RacketTest: XCTestCase {
  override class func setUp() {
    // Runtime-paths are relative to `(find-system-path 'exec-file)`,
    // so our bundle needs to contain an `exec-file` (that doesn't
    // have to actually be executable) from which the runtime folder
    // path can be derived.  So, the easiest solution in this case is
    // to add a "cookie" file whose sole purpose is to help us work
    // out the paths.
    let cookiePath = Bundle.module.resourceURL!
      .appendingPathComponent("Modules")
      .appendingPathComponent("cookie")
      .path

    r = Racket(execPath: cookiePath)
    r.bracket {
      r.load(zo: Bundle.module.url(forResource: "Modules/mods", withExtension: "zo")!)
    }
  }

  override class func tearDown() {
    r.destroy()
  }

  func testApplication() {
    r.bracket {
      let mod = Val.cons(Val.symbol("quote"), Val.cons(Val.symbol("fib"), Val.null))
      let fib = r.require(Val.symbol("fib"), from: mod).car()!
      XCTAssertEqual(fib.apply(Val.cons(Val.fixnum(0), Val.null))!.car()!.fixnum(), 0)
      XCTAssertEqual(fib.apply(Val.cons(Val.fixnum(1), Val.null))!.car()!.fixnum(), 1)
      XCTAssertEqual(fib.apply(Val.cons(Val.fixnum(2), Val.null))!.car()!.fixnum(), 1)
      XCTAssertEqual(fib.apply(Val.cons(Val.fixnum(8), Val.null))!.car()!.fixnum(), 21)
    }
  }

  func testBytestring() {
    r.bracket {
      let mod = Val.cons(Val.symbol("quote"), Val.cons(Val.symbol("loud"), Val.null))
      let exclaim = r.require(Val.symbol("exclaim"), from: mod).car()!
      let res = exclaim.apply(Val.cons(Val.string("hello"), Val.null))!
      XCTAssertEqual(res.car()?.bytestring()!, "hello!!!")
    }
  }

  func testBytevector() {
    r.bracket {
      let mod = Val.cons(Val.symbol("quote"), Val.cons(Val.symbol("bytes"), Val.null))
      let get = r.require(Val.symbol("get-bytes"), from: mod).car()!
      let res = get.apply(Val.null)!.car()!.bytevector()!.map({ UInt8(bitPattern: $0) })
      XCTAssertEqual(res, [1, 2, 128, 255])
    }
  }

  func testHttp() {
    r.bracket {
      let mod = Val.cons(Val.symbol("quote"), Val.cons(Val.symbol("http"), Val.null))
      let proc = r.require(Val.symbol("get"), from: mod).car()!
      let res = proc.apply(Val.cons(Val.string("defn.io"), Val.null))!
      let status = res.car()!.fixnum()!
      let content = res.cdr()!.car()!.bytestring()!
      XCTAssertEqual(status, 200)

      let re = try! NSRegularExpression(pattern: "<title>Posts &mdash; defn.io</title>")
      let matches = re.numberOfMatches(in: content, range: NSMakeRange(0, content.count))
      XCTAssertEqual(matches, 1)
    }
  }

  func testCallout() {
    r.bracket {
      let mod = Val.cons(Val.symbol("quote"), Val.cons(Val.symbol("callout"), Val.null)).locked()
      defer { mod.unlock() }

      let install = r.require(Val.symbol("install-callout!"), from: mod).unsafeCar()
      let ptr = unsafeBitCast(calloutExampleProc, to: Optional<UnsafeMutableRawPointer>.self)!
      install.unsafeApply(Val.cons(Val.pointer(ptr), Val.null))

      let call = r.require(Val.symbol("exec-callout"), from: mod).unsafeCar()
      call.unsafeApply(Val.null)
    }
    XCTAssertEqual(calloutResult, "hello")
  }
}

nonisolated(unsafe) fileprivate var calloutResult: String?
nonisolated(unsafe) fileprivate var calloutExampleProc: @convention(c) (Int, UnsafePointer<CChar>) -> Void = { len, ptr in
  let data = Data(bytes: ptr, count: len)
  calloutResult = String(data: data, encoding: .utf8)!
}