-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathgodbc.go
146 lines (131 loc) · 3.73 KB
/
godbc.go
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//+build !prod
//
// Copyright (c) 2014 The godbc Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Design-by-Contract for Go
//
// Design by Contract is a programming methodology
// which binds the caller and the function called to a
// contract. The contract is represented using Hoare Triple:
// {P} C {Q}
// where {P} is the precondition before executing command C,
// and {Q} is the postcondition.
//
// See Also
//
// * http://en.wikipedia.org/wiki/Design_by_contract
// * http://en.wikipedia.org/wiki/Hoare_logic
// * http://dlang.org/dbc.html
//
// Usage
//
// Godbc is enabled by default, but can be disabled for production
// builds by using the tag 'prod' in builds and tests as follows:
// go build -tags 'prod'
// or
// go test -tags 'prod'
//
package godbc
import (
"errors"
"fmt"
"runtime"
)
// InvariantSimpleTester is an interface which provides a receiver to
// test the object
type InvariantSimpleTester interface {
Invariant() bool
}
// InvariantTester is an interface which provides not only an Invariant(),
// but also a receiver to print the structure
type InvariantTester interface {
InvariantSimpleTester
String() string
}
// dbc_panic prints to the screen information of the failure followed
// by a call to panic()
func dbc_panic(dbc_func_name string, b bool, message ...interface{}) {
if !b {
// Get caller information which is the caller
// of the caller of this function
pc, file, line, _ := runtime.Caller(2)
caller_func_info := runtime.FuncForPC(pc)
error_string := fmt.Sprintf("%s:\n\r\tfunc (%s) 0x%x\n\r\tFile %s:%d",
dbc_func_name,
caller_func_info.Name(),
pc,
file,
line)
if len(message) > 0 {
error_string += fmt.Sprintf("\n\r\tInfo: %+v", message)
}
err := errors.New(error_string)
// Finally panic
panic(err)
}
}
// Require checks that the preconditions are satisfied before
// executing the function
//
// Example Code
//
// func Divide(a, b int) int {
// godbc.Require(b != 0)
// return a/b
// }
//
func Require(b bool, message ...interface{}) {
dbc_panic("REQUIRE", b, message...)
}
// Ensure checks the postconditions are satisfied before returning
// to the caller.
//
// Example Code
//
// type Data struct {
// a int
// }
//
// func (*d Data) Set(a int) {
// d.a = a
// godbc.Ensure(d.a == a)
// }
//
func Ensure(b bool, message ...interface{}) {
dbc_panic("ENSURE", b, message...)
}
// Check provides a simple assert
func Check(b bool, message ...interface{}) {
dbc_panic("CHECK", b, message...)
}
// InvariantSimple calls the objects Invariant() receiver to test
// the object for correctness.
//
// The caller object must provide an object that supports the
// interface InvariantSimpleTester and does not need to provide
// a String() receiver
func InvariantSimple(obj InvariantSimpleTester, message ...interface{}) {
dbc_panic("INVARIANT", obj.Invariant(), message...)
}
// Invariant calls the objects Invariant() receiver to test
// the object for correctness.
//
// The caller object must provide an object that supports the
// interface InvariantTester
//
// To see an example, please take a look at the godbc_test.go
func Invariant(obj InvariantTester, message ...interface{}) {
m := append(message, obj)
dbc_panic("INVARIANT", obj.Invariant(), m)
}