Skip to content

Commit bca40fd

Browse files
committed
Svars too
1 parent 9ba56ec commit bca40fd

File tree

2 files changed

+167
-2
lines changed

2 files changed

+167
-2
lines changed

Concurrent/SVar.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public struct SVar<A> {
3535
/// Creates a new SVar containing the supplied value.
3636
public init(initial : A){
3737
let v = MVar<A>(initial: initial)
38-
self.init(MVar(initial: (0, v)))
38+
self.init(MVar(initial: (1, v)))
3939
}
4040

4141
/// Empties the reciever.
@@ -70,7 +70,7 @@ public struct SVar<A> {
7070
self.svar.put(s)
7171
default:
7272
val.put(v)
73-
self.svar.put(min(1, readers), val)
73+
self.svar.put(min(1, readers + 1), val)
7474
}
7575
}
7676

ConcurrentTests/SVarSpec.swift

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
//
2+
// SVarSpec.swift
3+
// Concurrent
4+
//
5+
// Created by Robert Widmann on 6/6/15.
6+
// Copyright (c) 2015 TypeLift. All rights reserved.
7+
//
8+
9+
import Concurrent
10+
import XCTest
11+
import SwiftCheck
12+
import Swiftz
13+
14+
private enum Action {
15+
case NewEmptySVar
16+
case NewSVar(Int)
17+
case TakeSVar
18+
case PutSVar(Int)
19+
case IsEmptySVar
20+
case ReturnInt(Int)
21+
case ReturnBool(Bool)
22+
}
23+
24+
// Here to make the typechecker happy. Do not invoke these.
25+
extension Action : Arbitrary {
26+
static func arbitrary() -> Gen<Action> { return error("Cannot generate arbitrary Action.") }
27+
static func shrink(_ : Action) -> [Action] { return [] }
28+
}
29+
30+
class SVarSpec : XCTestCase {
31+
func testProperties() {
32+
property["An empty SVar really is empty"] = formulate([.NewEmptySVar, .IsEmptySVar], [.NewEmptySVar, .ReturnBool(true)])
33+
34+
property["A filled SVar really is filled"] = forAll { (n : Int) in
35+
return self.formulate([.NewSVar(n), .IsEmptySVar], [.NewSVar(n), .ReturnBool(false)])
36+
}
37+
38+
property["A take after filling == A return after an empty"] = forAll { (n : Int) in
39+
return self.formulate([.NewSVar(n), .TakeSVar], [.NewEmptySVar, .ReturnInt(n)])
40+
}
41+
42+
property["Filling then taking from an empty SVar is the same as an empty SVar"] = forAll { (n : Int) in
43+
return self.formulate([.NewEmptySVar, .PutSVar(n), .TakeSVar], [.NewEmptySVar, .ReturnInt(n)])
44+
}
45+
46+
property["Taking a new SVar is the same as a full SVar"] = forAll { (n : Int) in
47+
return self.formulate([.NewSVar(n), .TakeSVar], [.NewSVar(n), .ReturnInt(n)])
48+
}
49+
50+
property["Swapping a full SVar is the same as a full SVar with the swapped value"] = forAll { (m : Int, n : Int) in
51+
return self.formulate([.NewSVar(m), .PutSVar(n)], [.NewSVar(n)])
52+
}
53+
}
54+
55+
// Returns whether or not a sequence of Actions leaves us with a full or empty SVar.
56+
private func delta(b : Bool, ac : [Action]) -> Bool {
57+
if let x = ac.first {
58+
let xs = [Action](ac[1..<ac.endIndex])
59+
switch x {
60+
case .TakeSVar:
61+
return self.delta(b ? error("take on empty SVar") : true, ac: xs)
62+
case .IsEmptySVar:
63+
fallthrough
64+
case .ReturnInt(_):
65+
fallthrough
66+
case .ReturnBool(_):
67+
fallthrough
68+
case .IsEmptySVar:
69+
return self.delta(b, ac: xs)
70+
case .PutSVar(_):
71+
fallthrough
72+
case .NewSVar(_):
73+
return self.delta(false, ac: xs)
74+
case .NewEmptySVar:
75+
return self.delta(true, ac: xs)
76+
}
77+
}
78+
return b
79+
}
80+
81+
// The only thing that couldn't be reproduced. So take the lazy way out and naïvely unroll the
82+
// gist of the generator function.
83+
private func actionsGen(e : Bool) -> Gen<ArrayOf<Action>> {
84+
return Gen.sized({ n in
85+
var empty = e
86+
var result = [Action]()
87+
if n == 0 {
88+
return Gen.pure(ArrayOf(result))
89+
}
90+
while (rand() % Int32(n)) != 0 {
91+
if empty {
92+
result = result + [.PutSVar(Int.arbitrary().generate)]
93+
empty = false
94+
} else {
95+
result = result + [.TakeSVar]
96+
empty = true
97+
}
98+
}
99+
return Gen.pure(ArrayOf(result))
100+
})
101+
}
102+
103+
private func perform(mv : SVar<Int>, _ ac : [Action]) -> ([Bool], [Int]) {
104+
if let x = ac.first {
105+
let xs = [Action](ac[1..<ac.endIndex])
106+
107+
switch x {
108+
case .ReturnInt(let v):
109+
let (b, l) = perform(mv, xs)
110+
return (b, [v] + l)
111+
case .ReturnBool(let v):
112+
let (b, l) = perform(mv, xs)
113+
return ([v] + b, l)
114+
case .TakeSVar:
115+
let v = mv.read()
116+
let (b, l) = perform(mv, xs)
117+
return (b, [v] + l)
118+
case .PutSVar(let n):
119+
mv.write(n)
120+
return perform(mv, xs)
121+
case .IsEmptySVar:
122+
let v = mv.isEmpty
123+
let (b, l) = perform(mv, xs)
124+
return ([v] + b, l)
125+
default:
126+
return error("Fatal: Creating new SVars in the middle of a performance is forbidden")
127+
}
128+
}
129+
return ([], [])
130+
}
131+
132+
private func setupPerformance(ac : [Action]) -> ([Bool], [Int]) {
133+
if let x = ac.first {
134+
let xs = [Action](ac[1..<ac.endIndex])
135+
136+
switch x {
137+
case .ReturnInt(let v):
138+
let (b, l) = setupPerformance(xs)
139+
return (b, [v] + l)
140+
case .ReturnBool(let v):
141+
let (b, l) = setupPerformance(xs)
142+
return ([v] + b, l)
143+
case .NewEmptySVar:
144+
return perform(SVar<Int>(), xs)
145+
case .NewSVar(let n):
146+
return perform(SVar<Int>(initial: n), xs)
147+
default:
148+
return error("Fatal: NewSVar or NewEmptySVar must be the first actions")
149+
}
150+
}
151+
return ([], [])
152+
}
153+
154+
155+
private func formulate(c : [Action], _ d : [Action]) -> Property {
156+
return forAll(actionsGen(delta(true, ac: c))) { suff in
157+
let (b1, l1) = self.setupPerformance(c + suff.getArray)
158+
let (b2, l2) = self.setupPerformance(d + suff.getArray)
159+
return
160+
((b1 == b2) <?> "Boolean Values Match")
161+
^&&^
162+
((l1 == l2) <?> "SVar Values Match")
163+
}
164+
}
165+
}

0 commit comments

Comments
 (0)